• 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 
18 #include <algorithm>
19 #include <unordered_set>
20 
21 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
22 
23 #include "base/log/dump_log.h"
24 #include "base/log/event_report.h"
25 #include "base/perfmonitor/perf_constants.h"
26 #include "base/ressched/ressched_report.h"
27 #include "base/utils/system_properties.h"
28 #include "core/common/ime/input_method_manager.h"
29 #include "core/common/force_split/force_split_utils.h"
30 #include "core/components_ng/manager/avoid_info/avoid_info_manager.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
32 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
33 #include "core/components_ng/pattern/navigation/navigation_content_pattern.h"
34 #include "core/components_ng/pattern/navigation/navigation_drag_bar_pattern.h"
35 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
36 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
37 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
38 #include "core/components_ng/pattern/navigation/tool_bar_node.h"
39 #include "core/components_ng/pattern/navigation/tool_bar_pattern.h"
40 #include "core/components_ng/pattern/divider/divider_render_property.h"
41 #include "core/components_ng/pattern/stage/page_node.h"
42 #include "core/components_ng/property/measure_utils.h"
43 
44 #ifdef WINDOW_SCENE_SUPPORTED
45 #include "core/components_ng/pattern/window_scene/helper/window_scene_helper.h"
46 #endif
47 namespace OHOS::Ace::NG {
48 
49 constexpr int32_t NAVIMODE_CHANGE_ANIMATION_DURATION = 250;
50 constexpr int32_t OPACITY_ANIMATION_DURATION_APPEAR = 150;
51 constexpr int32_t OPACITY_ANIMATION_DURATION_DISAPPEAR = 250;
52 constexpr int32_t EMPTY_DESTINATION_CHILD_SIZE = 1;
53 constexpr Dimension DEFAULT_DRAG_REGION = 12.0_vp;
54 constexpr Dimension DEFAULT_DRAG_BAR_HOT_ZONE = 12.0_vp;
55 constexpr float DEFAULT_HALF = 2.0f;
56 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
57 constexpr int32_t PAGE_NODES = 1000;
58 constexpr int32_t PAGE_DEPTH = 300;
59 constexpr int32_t HALF_POSITION = 50;
60 constexpr int32_t END_POSITION = 100;
61 constexpr Dimension DRAG_BAR_RADIUS = 6.0_vp;
62 constexpr Dimension DRAG_BAR_BLUR_RADIUS = 20.0_vp;
63 constexpr Dimension DRAG_BAR_ITEM_RADIUS = 1.0_vp;
64 constexpr int32_t SECOND_ZINDEX_VALUE = 2;
65 constexpr int32_t INVALID_ANIMATION_ID = -1;
66 constexpr int32_t FULL_CIRCLE_ANGLE = 360;
67 
68 namespace {
69 constexpr int32_t MODE_SWITCH_ANIMATION_DURATION = 500; // ms
70 const RefPtr<CubicCurve> MODE_SWITCH_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.2f, 0.1f, 1.0f);
71 constexpr Dimension SPLIT_THRESHOLD_WIDTH = 600.0_vp;
72 
DeviceOrientationToString(DeviceOrientation ori)73 const char* DeviceOrientationToString(DeviceOrientation ori)
74 {
75     switch (ori) {
76         case DeviceOrientation::PORTRAIT:
77             return "PORTRAIT";
78         case DeviceOrientation::LANDSCAPE:
79             return "LANDSCAPE";
80         case DeviceOrientation::ORIENTATION_UNDEFINED:
81             return "ORIENTATION_UNDEFINED";
82         default:
83             return "UNKNOWN";
84     }
85 }
86 
ConvertDisplayOrientationToRotationAngle(DisplayOrientation ori)87 int32_t ConvertDisplayOrientationToRotationAngle(DisplayOrientation ori)
88 {
89     switch (ori) {
90         case DisplayOrientation::PORTRAIT: // corresponding to Orientation::PORTRAIT
91             return ROTATION_0;
92         case DisplayOrientation::LANDSCAPE_INVERTED: // corresponding to Orientation::LANDSCAPE
93             return ROTATION_90;
94         case DisplayOrientation::PORTRAIT_INVERTED: // corresponding to Orientation::PORTRAIT_INVERTED
95             return ROTATION_180;
96         case DisplayOrientation::LANDSCAPE: // corresponding to Orientation::LANDSCAPE_INVETED
97             return ROTATION_270;
98         default:
99             return ROTATION_0;
100     }
101 }
102 
CreatePercentGradientColor(int32_t percent,Color color)103 GradientColor CreatePercentGradientColor(int32_t percent, Color color)
104 {
105     NG::GradientColor gredient = GradientColor(color);
106     gredient.SetDimension(CalcDimension(percent, DimensionUnit::PERCENT));
107     return gredient;
108 }
109 
BuildNavDestinationInfoFromContext(const std::string & navigationId,NavDestinationState state,const RefPtr<NavDestinationContext> & context,bool isFrom,std::optional<NavDestinationInfo> & info)110 void BuildNavDestinationInfoFromContext(const std::string& navigationId, NavDestinationState state,
111     const RefPtr<NavDestinationContext>& context, bool isFrom, std::optional<NavDestinationInfo>& info)
112 {
113     if (!context) {
114         info.reset();
115         return;
116     }
117 
118     int32_t index = isFrom ? context->GetPreIndex() : context->GetIndex();
119     std::string navDestinationId = std::to_string(context->GetNavDestinationId());
120     std::string name;
121     napi_value param = nullptr;
122     auto pathInfo = context->GetNavPathInfo();
123     if (pathInfo) {
124         name = pathInfo->GetName();
125         param = pathInfo->GetParamObj();
126     }
127     NavDestinationMode mode = context->GetMode();
128     int32_t uniqueId = context->GetUniqueId();
129     info = std::make_optional<NavDestinationInfo>(navigationId, name, state, index, param,
130         navDestinationId, mode, uniqueId);
131 }
132 
LogCustomAnimationStart(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,NavigationOperation operation)133 void LogCustomAnimationStart(const RefPtr<NavDestinationGroupNode>& preTopDestination,
134     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, NavigationOperation operation)
135 {
136     RefPtr<NavDestinationPattern> prePattern =
137         preTopDestination ? preTopDestination->GetPattern<NavDestinationPattern>() : nullptr;
138     RefPtr<NavDestinationPattern> newPattern =
139         newTopNavDestination ? newTopNavDestination->GetPattern<NavDestinationPattern>() : nullptr;
140     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
141         "custom animation start: operation: %{public}d, pre name: %{public}s, id: %{public}s."
142         "top name: %{public}s, id: %{public}s",
143         operation, prePattern ? prePattern->GetName().c_str() : "null",
144         prePattern ? std::to_string(prePattern->GetNavDestinationId()).c_str() : "null",
145         newPattern ? newPattern->GetName().c_str() : "null",
146         newPattern ? std::to_string(newPattern->GetNavDestinationId()).c_str() : "null");
147 }
148 
TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode> & navDestination,NavigationOperation operation,bool isEnter)149 int32_t TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode>& navDestination,
150     NavigationOperation operation, bool isEnter)
151 {
152     CHECK_NULL_RETURN(navDestination, INVALID_ANIMATION_ID);
153     return navDestination->DoTransition(operation, isEnter);
154 }
155 } // namespace
156 
ReplaceNodeWithProxyNodeIfNeeded(const RefPtr<FrameNode> & navContentNode,const RefPtr<NavDestinationGroupNode> & node)157 void NavigationPattern::ReplaceNodeWithProxyNodeIfNeeded(
158     const RefPtr<FrameNode>& navContentNode, const RefPtr<NavDestinationGroupNode>& node)
159 {
160     CHECK_NULL_VOID(navContentNode);
161     CHECK_NULL_VOID(node);
162     auto proxyNode = node->GetOrCreateProxyNode();
163     if (!proxyNode) {
164         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "failed to create proxyNode for destNode[%{public}d]", node->GetId());
165         return;
166     }
167     node->SetIsShowInPrimaryPartition(true);
168     node->SetJSViewActive(true);
169     auto property = node->GetLayoutProperty();
170     if (property) {
171         property->UpdateVisibility(VisibleType::VISIBLE);
172     }
173     auto childIndex = navContentNode->GetChildIndex(node);
174     if (childIndex < 0) {
175         return;
176     }
177     proxyNode->SetIndex(node->GetIndex());
178     navContentNode->RemoveChildSilently(node);
179     navContentNode->AddChild(proxyNode, childIndex, true);
180     navContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
181 }
182 
RestoreNodeFromProxyNodeIfNeeded(const RefPtr<FrameNode> & primaryContentNode,const RefPtr<FrameNode> & navContentNode,const RefPtr<NavDestinationGroupNode> & node)183 void NavigationPattern::RestoreNodeFromProxyNodeIfNeeded(const RefPtr<FrameNode>& primaryContentNode,
184     const RefPtr<FrameNode>& navContentNode, const RefPtr<NavDestinationGroupNode>& node)
185 {
186     CHECK_NULL_VOID(primaryContentNode);
187     CHECK_NULL_VOID(navContentNode);
188     CHECK_NULL_VOID(node);
189     node->SetIsShowInPrimaryPartition(false);
190     auto proxyNode = node->GetOrCreateProxyNode();
191     CHECK_NULL_VOID(proxyNode);
192     auto childIndex = navContentNode->GetChildIndex(proxyNode);
193     if (childIndex < 0) {
194         return;
195     }
196 
197     node->SetIndex(proxyNode->GetIndex());
198     primaryContentNode->RemoveChildSilently(node);
199     primaryContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
200 
201     navContentNode->RemoveChildSilently(proxyNode);
202     navContentNode->AddChild(node, childIndex, true);
203     navContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
204 
205     node->SetJSViewActive(true);
206     auto property = node->GetLayoutProperty();
207     CHECK_NULL_VOID(property);
208     property->UpdateVisibility(VisibleType::VISIBLE);
209 }
210 
ReorderPrimaryNodes(const RefPtr<FrameNode> & primaryContentNode,const std::vector<WeakPtr<NavDestinationGroupNode>> & nodes)211 void NavigationPattern::ReorderPrimaryNodes(const RefPtr<FrameNode>& primaryContentNode,
212     const std::vector<WeakPtr<NavDestinationGroupNode>>& nodes)
213 {
214     int32_t slot = 0;
215     for (const auto& weakNode : nodes) {
216         auto node = weakNode.Upgrade();
217         CHECK_NULL_CONTINUE(node);
218         auto childIndex = primaryContentNode->GetChildIndex(node);
219         if (childIndex < 0) {
220             node->MountToParent(primaryContentNode, slot, true);
221         } else if (slot != childIndex) {
222             node->MovePosition(slot);
223         }
224         slot++;
225     }
226 }
227 
NavigationPattern()228 NavigationPattern::NavigationPattern()
229 {
230     navigationController_ = std::make_shared<InnerNavigationController>(WeakClaim(this), Container::CurrentId());
231 }
232 
GetTitleBarRenderContext()233 RefPtr<RenderContext> NavigationPattern::GetTitleBarRenderContext()
234 {
235     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
236     CHECK_NULL_RETURN(hostNode, nullptr);
237     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
238     CHECK_NULL_RETURN(layoutProperty, nullptr);
239     auto contentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
240     CHECK_NULL_RETURN(contentNode, nullptr);
241     if (contentNode->FindChildNodeOfClass<NavDestinationGroupNode>()) {
242         auto navBarOrHomeDestNode =
243             AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
244         CHECK_NULL_RETURN(navBarOrHomeDestNode, nullptr);
245         auto renderContext = navBarOrHomeDestNode->GetRenderContext();
246         return renderContext;
247     } else {
248         auto renderContext = contentNode->GetRenderContext();
249         return renderContext;
250     }
251 }
252 
DoAnimation(NavigationMode usrNavigationMode)253 void NavigationPattern::DoAnimation(NavigationMode usrNavigationMode)
254 {
255     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
256     CHECK_NULL_VOID(hostNode);
257     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
258     CHECK_NULL_VOID(layoutProperty);
259 
260     auto context = PipelineContext::GetCurrentContext();
261     CHECK_NULL_VOID(context);
262     layoutProperty->UpdateNavigationMode(navigationMode_);
263     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
264     AnimationOption option = AnimationOption();
265     option.SetDuration(NAVIMODE_CHANGE_ANIMATION_DURATION);
266     option.SetCurve(Curves::FRICTION);
267     option.SetFillMode(FillMode::FORWARDS);
268     AnimationOption optionAlpha = AnimationOption();
269     optionAlpha.SetCurve(Curves::SHARP);
270     optionAlpha.SetFillMode(FillMode::FORWARDS);
271     auto renderContext = GetTitleBarRenderContext();
272     CHECK_NULL_VOID(renderContext);
273 
274     std::function<void()> finishCallback = [optionAlpha, renderContext, hostNode]() {
275         renderContext->OpacityAnimation(optionAlpha, 0, 1);
276         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
277     };
278 
279     context->OpenImplicitAnimation(option, option.GetCurve(), finishCallback);
280     layoutProperty->UpdateNavigationMode(usrNavigationMode);
281     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
282     context->FlushUITasks();
283     if (usrNavigationMode == NavigationMode::STACK || navigationMode_ == NavigationMode::SPLIT) {
284         optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_DISAPPEAR);
285         renderContext->OpacityAnimation(optionAlpha, 1, 0);
286     } else if (usrNavigationMode == NavigationMode::SPLIT || navigationMode_ == NavigationMode::STACK) {
287         optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_APPEAR);
288         renderContext->OpacityAnimation(optionAlpha, 0, 1);
289     }
290     context->CloseImplicitAnimation();
291     navigationMode_ = usrNavigationMode;
292 }
293 
OnAttachToFrameNode()294 void NavigationPattern::OnAttachToFrameNode()
295 {
296     auto host = GetHost();
297     CHECK_NULL_VOID(host);
298     auto context = host->GetContext();
299     CHECK_NULL_VOID(context);
300     auto id = host->GetId();
301     context->AddWindowStateChangedCallback(id);
302     context->AddWindowSizeChangeCallback(id);
303 
304     auto theme = NavigationGetTheme();
305     if (theme && theme->GetNavBarUnfocusEffectEnable()) {
306         context->AddWindowFocusChangedCallback(id);
307     }
308     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
309         SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_ALL, .edges = SAFE_AREA_EDGE_ALL };
310         host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
311     }
312     auto manager = context->GetNavigationManager();
313     CHECK_NULL_VOID(manager);
314     if (manager->IsForceSplitSupported()) {
315         RegisterForceSplitListener(context, id);
316     }
317 }
318 
OnDetachFromFrameNode(FrameNode * frameNode)319 void NavigationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
320 {
321     CHECK_NULL_VOID(frameNode);
322     auto context = frameNode->GetContext();
323     CHECK_NULL_VOID(context);
324     auto id = frameNode->GetId();
325     context->RemoveWindowStateChangedCallback(id);
326     context->RemoveWindowSizeChangeCallback(id);
327     auto manager = context->GetNavigationManager();
328     CHECK_NULL_VOID(manager);
329     if (manager->IsForceSplitSupported()) {
330         UnregisterForceSplitListener(context, id);
331     }
332 }
333 
334 
DoNavbarHideAnimation(const RefPtr<NavigationGroupNode> & hostNode)335 void NavigationPattern::DoNavbarHideAnimation(const RefPtr<NavigationGroupNode>& hostNode)
336 {
337     AnimationOption option;
338     option.SetCurve(MODE_SWITCH_CURVE);
339     option.SetFillMode(FillMode::FORWARDS);
340     option.SetDuration(MODE_SWITCH_ANIMATION_DURATION);
341     AnimationUtils::Animate(option, [weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
342         auto hostNode = weakHost.Upgrade();
343         CHECK_NULL_VOID(hostNode);
344         auto layoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
345         CHECK_NULL_VOID(layoutProperty);
346         bool hideNavBar = layoutProperty->GetHideNavBarValue(false);
347         auto navBarOrHomeDestNode =
348             AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
349         CHECK_NULL_VOID(navBarOrHomeDestNode);
350         auto navBarLayoutProperty = navBarOrHomeDestNode->GetLayoutProperty();
351         CHECK_NULL_VOID(navBarLayoutProperty);
352         navBarLayoutProperty->UpdateVisibility(hideNavBar ? VisibleType::INVISIBLE : VisibleType::VISIBLE, true);
353         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
354         hostNode->GetContext()->FlushUITasks();
355     }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, hostNode->GetContextRefPtr());
356 }
357 
InitDragBarEvent()358 void NavigationPattern::InitDragBarEvent()
359 {
360     auto dragBarNode = AceType::DynamicCast<FrameNode>(GetDragBarNode());
361     CHECK_NULL_VOID(dragBarNode);
362     auto dragGestureHub = dragBarNode->GetOrCreateGestureEventHub();
363     CHECK_NULL_VOID(dragGestureHub);
364     InitDragBarPanEvent(dragGestureHub);
365     InitTouchEvent(dragGestureHub);
366 
367     // clear divider hover and pan event
368     auto dividerNode = GetDividerNode();
369     CHECK_NULL_VOID(dividerNode);
370     auto dividerGestureHub = dividerNode->GetOrCreateGestureEventHub();
371     CHECK_NULL_VOID(dividerGestureHub);
372     auto dividerInputHub = dividerNode->GetOrCreateInputEventHub();
373     CHECK_NULL_VOID(dividerInputHub);
374     if (hoverEvent_) {
375         dividerInputHub->RemoveOnHoverEvent(hoverEvent_);
376         hoverEvent_.Reset();
377     }
378     if (panEvent_) {
379         dividerGestureHub->RemovePanEvent(panEvent_);
380         panEvent_.Reset();
381     }
382 }
383 
ClearDragBarEvent()384 void NavigationPattern::ClearDragBarEvent()
385 {
386     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
387     CHECK_NULL_VOID(hostNode);
388     auto dragBarNode = AceType::DynamicCast<FrameNode>(GetDragBarNode());
389     CHECK_NULL_VOID(dragBarNode);
390     auto dragGestureHub = dragBarNode->GetOrCreateGestureEventHub();
391     CHECK_NULL_VOID(dragGestureHub);
392 
393     // clear drag bar touch and pan event
394     if (touchEvent_) {
395         dragGestureHub->RemoveTouchEvent(touchEvent_);
396         touchEvent_.Reset();
397     }
398     if (dragBarPanEvent_) {
399         dragGestureHub->RemovePanEvent(dragBarPanEvent_);
400         dragBarPanEvent_.Reset();
401     }
402 
403     hostNode->RemoveChild(dragBarNode);
404     hostNode->SetDragBarNode(nullptr);
405 }
406 
BuildDragBar()407 void NavigationPattern::BuildDragBar()
408 {
409     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TEN)) {
410         return;
411     }
412     if (enableDragBar_) {
413         if (GetDragBarNode()) {
414             // if dragBar is already in navigation, do nothing
415             return;
416         }
417         // create drag bar and init drag bar gesture event
418         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
419         CHECK_NULL_VOID(hostNode);
420         CreateDragBarNode(hostNode);
421         InitDragBarEvent();
422         return;
423     }
424     auto dividerNode = GetDividerNode();
425     CHECK_NULL_VOID(dividerNode);
426     auto dividerGestureHub = dividerNode->GetOrCreateGestureEventHub();
427     CHECK_NULL_VOID(dividerGestureHub);
428     auto dividerInputHub = dividerNode->GetOrCreateInputEventHub();
429     CHECK_NULL_VOID(dividerInputHub);
430     InitDividerPanEvent(dividerGestureHub);
431     InitDividerMouseEvent(dividerInputHub);
432     if (GetDragBarNode()) {
433         // clear drag bar gesture event and remove dragBar
434         ClearDragBarEvent();
435     }
436 }
437 
CreateHomeDestination(RefPtr<UINode> & customNode,RefPtr<NavDestinationGroupNode> & homeDest)438 bool NavigationPattern::CreateHomeDestination(RefPtr<UINode>& customNode, RefPtr<NavDestinationGroupNode>& homeDest)
439 {
440     CHECK_NULL_RETURN(navigationStack_, false);
441     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
442     do {
443         if (parentNode_.Upgrade() || !host) {
444             break;
445         }
446         auto context = host->GetContext();
447         // Avoid the loading problem of atomicservice on the home page
448         if ((context && !context->GetInstallationFree()) || !context) {
449             break;
450         }
451         RefPtr<UINode> parentCustomNode;
452         auto curNode = host->GetParent();
453         while (curNode) {
454             auto curTag = curNode->GetTag();
455             if (curTag == V2::JS_VIEW_ETS_TAG) {
456                 parentCustomNode = curNode;
457                 break;
458             }
459             curNode = curNode->GetParent();
460         }
461         auto pattern = host->GetPattern<NavigationPattern>();
462         if (pattern && parentCustomNode) {
463             pattern->SetParentCustomNode(parentCustomNode);
464         }
465     } while (false);
466     RefPtr<UINode> node;
467     if (!navigationStack_->CreateHomeDestination(parentNode_, node)) {
468         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "failed to create home NavDestination");
469         return false;
470     }
471     CHECK_NULL_RETURN(node, false);
472     node->SetFreeze(true, true);
473     auto destNode = AceType::DynamicCast<NavDestinationGroupNode>(
474         NavigationGroupNode::GetNavDestinationNode(node));
475     CHECK_NULL_RETURN(destNode, false);
476     destNode->SetIsHomeDestination(true);
477     // set navigation id
478     auto destPattern = AceType::DynamicCast<NavDestinationPattern>(destNode->GetPattern());
479     if (host && destPattern) {
480         destPattern->SetNavigationNode(host);
481         destPattern->SetNavigationId(host->GetInspectorId().value_or(""));
482     }
483     customNode = node;
484     homeDest = destNode;
485     return true;
486 }
487 
OnModifyDone()488 void NavigationPattern::OnModifyDone()
489 {
490     // !!! Do not add operations about NavPathStack here, see @SyncWithJsStackIfNeeded
491     Pattern::OnModifyDone();
492     UpdateChildLayoutPolicy();
493     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
494     CHECK_NULL_VOID(hostNode);
495     auto navBarOrHomeDesteNode =
496         AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
497     if (navBarOrHomeDesteNode) {
498         navBarOrHomeDesteNode->MarkModifyDone();
499     }
500     auto navBarNode = AceType::DynamicCast<NavBarNode>(navBarOrHomeDesteNode);
501     isRightToLeft_ = AceApplicationInfo::GetInstance().IsRightToLeft();
502 
503     auto pipeline = PipelineContext::GetCurrentContext();
504     CHECK_NULL_VOID(pipeline);
505     BuildDragBar();
506 
507     auto layoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
508     CHECK_NULL_VOID(layoutProperty);
509     auto curNavBarPosition = layoutProperty->GetNavBarPositionValue(NavBarPosition::START);
510     if (preNavBarPosition_.has_value() && preNavBarPosition_.value() != curNavBarPosition) {
511         MarkAllNavDestinationDirtyIfNeeded(hostNode);
512     }
513     preNavBarPosition_ = curNavBarPosition;
514 
515     auto&& opts = layoutProperty->GetSafeAreaExpandOpts();
516     if (opts) {
517         uint8_t ignoreExpandKeyboard = 0x11;
518         SafeAreaExpandOpts optsExceptKeyboard = { .type = opts->type & ignoreExpandKeyboard,
519             .edges = opts->edges };
520         if (navBarNode) {
521             navBarNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
522             navBarNode->MarkModifyDone();
523         }
524 
525         auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
526         CHECK_NULL_VOID(navigationContentNode);
527         navigationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
528         navigationContentNode->MarkModifyDone();
529 
530         auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
531         CHECK_NULL_VOID(dividerNode);
532         dividerNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(optsExceptKeyboard);
533         dividerNode->MarkModifyDone();
534     }
535 
536     bool enableModeChangeAnimation = layoutProperty->GetEnableModeChangeAnimation().value_or(true);
537     if (enableModeChangeAnimation && GetNavigationMode() == NavigationMode::SPLIT && GetNavBarVisibilityChange() &&
538         !forceSplitSuccess_) { // there is no need for navBar animation in the forceSplit scenario.
539         DoNavbarHideAnimation(hostNode);
540     }
541 
542     if (!HandleIntent(false)) {
543         // AddRecoverableNavigation function will check inside whether current navigation can be recovered
544         pipeline->GetNavigationManager()->AddRecoverableNavigation(hostNode->GetCurId(), hostNode);
545         RestoreJsStackIfNeeded();
546     }
547     UpdateToobarFocusColor();
548     UpdateDividerBackgroundColor();
549     NavigationModifyDoneToolBarManager();
550 }
551 
SetSystemBarStyle(const RefPtr<SystemBarStyle> & style)552 void NavigationPattern::SetSystemBarStyle(const RefPtr<SystemBarStyle>& style)
553 {
554     auto host = GetHost();
555     CHECK_NULL_VOID(host);
556     auto pipeline = host->GetContext();
557     CHECK_NULL_VOID(pipeline);
558     auto windowManager = pipeline->GetWindowManager();
559     CHECK_NULL_VOID(windowManager);
560     if (!backupStyle_.has_value()) {
561         backupStyle_ = windowManager->GetSystemBarStyle();
562     }
563     currStyle_ = style;
564 
565     // The systemBarStyle may only take effect when navigation fills the entire page.
566     if (!isFullPageNavigation_) {
567         return;
568     }
569 
570     // When there is NavDestination in the stack, the systemBarStyle set for Navigation does not take effect.
571     do {
572         if (!navigationStack_) {
573             break;
574         }
575         auto topPath = navigationStack_->GetTopNavPath();
576         if (!topPath.has_value()) {
577             break;
578         }
579         auto topNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
580             NavigationGroupNode::GetNavDestinationNode(topPath->second));
581         if (topNavDestination) {
582             return;
583         }
584     } while (false);
585 
586     /**
587      * When developers provide a valid style to systemBarStyle, we should set the style to window;
588      * when 'undefined' was provided, we should restore the style.
589      */
590     if (currStyle_.value() != nullptr) {
591         windowManager->SetSystemBarStyle(currStyle_.value());
592     } else {
593         TryRestoreSystemBarStyle(windowManager);
594     }
595 }
596 
OnAttachToMainTree()597 void NavigationPattern::OnAttachToMainTree()
598 {
599     auto host = GetHost();
600     CHECK_NULL_VOID(host);
601     InitPageNode(host);
602     InitFoldState();
603     RegisterAvoidInfoChangeListener(host);
604 }
605 
InitFoldState()606 void NavigationPattern::InitFoldState()
607 {
608     auto container = Container::Current();
609     CHECK_NULL_VOID(container);
610     container->InitIsFoldable();
611     if (container->IsFoldable()) {
612         currentFoldStatus_ = container->GetCurrentFoldStatus();
613     }
614 }
615 
OnDetachFromMainTree()616 void NavigationPattern::OnDetachFromMainTree()
617 {
618     isFullPageNavigation_ = false;
619     auto host = GetHost();
620     CHECK_NULL_VOID(host);
621     UnregisterAvoidInfoChangeListener(host);
622     auto pipeline = host->GetContext();
623     CHECK_NULL_VOID(pipeline);
624     auto windowManager = pipeline->GetWindowManager();
625     CHECK_NULL_VOID(windowManager);
626     TryRestoreSystemBarStyle(windowManager);
627     backupStyle_.reset();
628     currStyle_.reset();
629     pageNode_ = nullptr;
630     SetIsTargetForceSplitNav(false);
631 }
632 
IsTopNavDestination(const RefPtr<UINode> & node) const633 bool NavigationPattern::IsTopNavDestination(const RefPtr<UINode>& node) const
634 {
635     CHECK_NULL_RETURN(node, false);
636     CHECK_NULL_RETURN(navigationStack_, false);
637     auto topPath = navigationStack_->GetTopNavPath();
638     RefPtr<NavDestinationGroupNode> destination = nullptr;
639     if (!topPath.has_value()) {
640         auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
641         CHECK_NULL_RETURN(host, false);
642         destination = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
643     } else {
644         destination = AceType::DynamicCast<NavDestinationGroupNode>(
645             NavigationGroupNode::GetNavDestinationNode(topPath->second));
646     }
647     return destination == node;
648 }
649 
JudgeFoldStateChangeAndUpdateState()650 bool NavigationPattern::JudgeFoldStateChangeAndUpdateState()
651 {
652     auto container = Container::Current();
653     CHECK_NULL_RETURN(container, false);
654     auto foldStatus = container->GetCurrentFoldStatus();
655     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "newFoldStatus: %{public}d, currentFoldStatus: %{public}d.",
656         static_cast<int32_t>(foldStatus), static_cast<int32_t>(currentFoldStatus_));
657     if (foldStatus != currentFoldStatus_) {
658         currentFoldStatus_ = foldStatus;
659         return true;
660     }
661     return false;
662 }
663 
UpdateIsFullPageNavigation(const RefPtr<FrameNode> & host)664 void NavigationPattern::UpdateIsFullPageNavigation(const RefPtr<FrameNode>& host)
665 {
666     CHECK_NULL_VOID(host);
667     auto geometryNode = host->GetGeometryNode();
668     CHECK_NULL_VOID(geometryNode);
669     auto frame = geometryNode->GetFrameRect();
670     auto pipeline = host->GetContext();
671     CHECK_NULL_VOID(pipeline);
672     auto windowManager = pipeline->GetWindowManager();
673     CHECK_NULL_VOID(windowManager);
674 
675     bool isFullPage = false;
676     auto pageNode = pageNode_.Upgrade();
677     if (pageNode) {
678         auto pageNodeGeometryNode = pageNode->GetGeometryNode();
679         if (pageNodeGeometryNode) {
680             auto pageFrame = pageNodeGeometryNode->GetFrameRect();
681             isFullPage = pageFrame.GetSize().Width() <= frame.GetSize().Width() &&
682                 pageFrame.GetSize().Height() <= frame.GetSize().Height();
683         }
684     }
685     pageNode = nullptr;
686 
687     if (isFullPage == isFullPageNavigation_) {
688         return;
689     }
690 
691     isFullPageNavigation_ = isFullPage;
692     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Navigation[%{public}d] change to %{public}s",
693         host->GetId(), isFullPageNavigation_ ? "FullPage" : "PartialPage");
694     MarkAllNavDestinationDirtyIfNeeded(host);
695     UpdatePageLevelConfigForSizeChanged();
696     UpdateSystemBarStyleOnFullPageStateChange(windowManager);
697     if (isFullPageNavigation_) {
698         RegisterPageVisibilityChangeCallback();
699     }
700 }
701 
UpdateSystemBarStyleOnFullPageStateChange(const RefPtr<WindowManager> & windowManager)702 void NavigationPattern::UpdateSystemBarStyleOnFullPageStateChange(const RefPtr<WindowManager>& windowManager)
703 {
704     // full page -> partial page
705     if (!isFullPageNavigation_) {
706         TryRestoreSystemBarStyle(windowManager);
707         return;
708     }
709 
710     // partial page -> full page
711     auto topPath = navigationStack_->GetTopNavPath();
712     UpdateSystemBarStyleWithTopNavPath(windowManager, topPath);
713 }
714 
UpdateSystemBarStyleOnTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath)715 void NavigationPattern::UpdateSystemBarStyleOnTopNavPathChange(
716     const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath)
717 {
718     if (!isFullPageNavigation_) {
719         return;
720     }
721 
722     auto host = GetHost();
723     CHECK_NULL_VOID(host);
724     auto pipeline = host->GetContext();
725     CHECK_NULL_VOID(pipeline);
726     auto windowManager = pipeline->GetWindowManager();
727     CHECK_NULL_VOID(windowManager);
728     UpdateSystemBarStyleWithTopNavPath(windowManager, newTopNavPath);
729 }
730 
UpdateSystemBarStyleWithTopNavPath(const RefPtr<WindowManager> & windowManager,const std::optional<std::pair<std::string,RefPtr<UINode>>> & topNavPath)731 void NavigationPattern::UpdateSystemBarStyleWithTopNavPath(const RefPtr<WindowManager>& windowManager,
732     const std::optional<std::pair<std::string, RefPtr<UINode>>>& topNavPath)
733 {
734     if (ApplyTopNavPathSystemBarStyleOrRestore(windowManager, topNavPath)) {
735         return;
736     }
737 
738     if (currStyle_.has_value() && currStyle_.value() != nullptr) {
739         windowManager->SetSystemBarStyle(currStyle_.value());
740     } else {
741         TryRestoreSystemBarStyle(windowManager);
742     }
743 }
744 
TryRestoreSystemBarStyle(const RefPtr<WindowManager> & windowManager)745 void NavigationPattern::TryRestoreSystemBarStyle(const RefPtr<WindowManager>& windowManager)
746 {
747     if (backupStyle_.has_value()) {
748         windowManager->SetSystemBarStyle(backupStyle_.value());
749     }
750 }
751 
UpdateSystemBarStyleOnPageVisibilityChange(bool show)752 void NavigationPattern::UpdateSystemBarStyleOnPageVisibilityChange(bool show)
753 {
754     if (!isFullPageNavigation_) {
755         return;
756     }
757 
758     CHECK_NULL_VOID(navigationStack_);
759     auto host = GetHost();
760     CHECK_NULL_VOID(host);
761     auto pipeline = host->GetContext();
762     CHECK_NULL_VOID(pipeline);
763     auto windowManager = pipeline->GetWindowManager();
764     CHECK_NULL_VOID(windowManager);
765     if (show) {
766         // page containing Navigation, hide -> show
767         auto topPath = navigationStack_->GetTopNavPath();
768         UpdateSystemBarStyleWithTopNavPath(windowManager, topPath);
769     } else {
770         // page containing Navigation, show -> hide
771         TryRestoreSystemBarStyle(windowManager);
772     }
773 }
774 
RegisterPageVisibilityChangeCallback()775 void NavigationPattern::RegisterPageVisibilityChangeCallback()
776 {
777     auto pageNode = pageNode_.Upgrade();
778     CHECK_NULL_VOID(pageNode);
779     RefPtr<PagePattern> pagePattern = pageNode->GetPattern<PagePattern>();
780     CHECK_NULL_VOID(pagePattern);
781     auto callback = [weak = WeakClaim(this)](bool show) {
782         auto pattern = weak.Upgrade();
783         CHECK_NULL_VOID(pattern);
784         // we need update the "systemBarStyle" at the beginning of the transition animation on the router page
785         pattern->UpdateSystemBarStyleOnPageVisibilityChange(show);
786     };
787     pagePattern->SetPageVisibilityChangeCallback(std::move(callback));
788 }
789 
ApplyTopNavPathSystemBarStyleOrRestore(const RefPtr<WindowManager> & windowManager,const std::optional<std::pair<std::string,RefPtr<UINode>>> & topNavPath)790 bool NavigationPattern::ApplyTopNavPathSystemBarStyleOrRestore(
791     const RefPtr<WindowManager>& windowManager,
792     const std::optional<std::pair<std::string, RefPtr<UINode>>>& topNavPath)
793 {
794     RefPtr<NavDestinationGroupNode> topDestNode = nullptr;
795     if (topNavPath.has_value()) {
796         topDestNode = AceType::DynamicCast<NavDestinationGroupNode>(
797             NavigationGroupNode::GetNavDestinationNode(topNavPath.value().second));
798     } else {
799         auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
800         CHECK_NULL_RETURN(host, false);
801         topDestNode = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
802     }
803     if (!topDestNode) {
804         return false;
805     }
806 
807     auto navDestinationPattern = topDestNode->GetPattern<NavDestinationPattern>();
808     if (!navDestinationPattern) {
809         return false;
810     }
811     /**
812      * Backup is only performed when the developer sets the "systemBarStyle" attribute,
813      * and the entire Navigation is only backed up once.
814      * Therefore, when developer only set the "systemBarStyle" attribute to NavDestination, we need to
815      * save the attribute to Navigation.
816      */
817     auto backupFromNavDestination = navDestinationPattern->GetBackupStyle();
818     if (!backupStyle_.has_value() && backupFromNavDestination.has_value()) {
819         backupStyle_ = backupFromNavDestination;
820     }
821 
822     auto destCurrStyle = navDestinationPattern->GetCurrentStyle();
823     if (destCurrStyle.has_value() && destCurrStyle.value() != nullptr) {
824         windowManager->SetSystemBarStyle(destCurrStyle.value());
825     } else {
826         TryRestoreSystemBarStyle(windowManager);
827     }
828     return true;
829 }
830 
InitPageNode(const RefPtr<FrameNode> & host)831 void NavigationPattern::InitPageNode(const RefPtr<FrameNode>& host)
832 {
833     CHECK_NULL_VOID(host);
834     auto parent = host->GetParent();
835     CHECK_NULL_VOID(parent);
836     RefPtr<FrameNode> pageNode = nullptr;
837     while (parent) {
838         if (parent->GetTag() == V2::PAGE_ETS_TAG) {
839             pageNode = AceType::DynamicCast<FrameNode>(parent);
840             break;
841         }
842         parent = parent->GetParent();
843     }
844     if (!pageNode) {
845         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "Failed to find PageNode of Navigation");
846     } else {
847         pageNode_ = WeakPtr<FrameNode>(pageNode);
848     }
849 }
850 
OnLanguageConfigurationUpdate()851 void NavigationPattern::OnLanguageConfigurationUpdate()
852 {
853     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
854     if (isRightToLeft != isRightToLeft_) {
855         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
856         CHECK_NULL_VOID(hostNode);
857         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
858         isRightToLeft_ = isRightToLeft;
859     }
860 }
861 
GetFirstNewDestinationIndex(const NavPathList & preList,const NavPathList & curList)862 int32_t NavigationPattern::GetFirstNewDestinationIndex(const NavPathList& preList, const NavPathList& curList)
863 {
864     struct Hash {
865         size_t operator()(const RefPtr<UINode>& node) const
866         {
867             return node->GetId();
868         }
869     };
870     std::unordered_set<RefPtr<UINode>, Hash> preNodeSet;
871     for (const auto& pair : preList) {
872         CHECK_NULL_CONTINUE(pair.second);
873         preNodeSet.emplace(pair.second);
874     }
875     int32_t firstNewNodeIndex = -1;
876     for (int32_t index = 0; index < static_cast<int32_t>(curList.size()); index++) {
877         const auto& uiNode = curList[index].second;
878         if (preNodeSet.find(uiNode) != preNodeSet.end()) {
879             continue;
880         }
881         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
882             NavigationGroupNode::GetNavDestinationNode(uiNode));
883         CHECK_NULL_CONTINUE(node);
884         firstNewNodeIndex = index;
885         break;
886     }
887     return firstNewNodeIndex;
888 }
889 
ClearSecondaryNodesIfNeeded(NavPathList && preList)890 void NavigationPattern::ClearSecondaryNodesIfNeeded(NavPathList&& preList)
891 {
892     /**
893      * When the following conditions are met:
894      * 1. The homeNode exists
895      * 2. homeNode is in focus
896      * 3. After stack synchronization, the homeNode remains in the stack
897      * 4. The latest top NavDestination does not exist in the previous stack
898      *
899      * This will trigger the following logic:
900      * The NavDestination between the homeNode and the first newly added NavDestination will be removed.
901      */
902     auto homeNode = homeNode_.Upgrade();
903     if (!forceSplitSuccess_ || !homeNodeTouched_) {
904         return;
905     }
906     if (!forceSplitUseNavBar_ && !homeNode) {
907         return;
908     }
909     const auto& curList = navigationStack_->GetAllNavDestinationNodes();
910     if (curList.empty()) {
911         return;
912     }
913     const auto& curTopNode = curList.back().second;
914     auto it = std::find_if(preList.begin(), preList.end(), [&curTopNode](const auto& pair) {
915             return pair.second == curTopNode;
916         });
917     if (it != preList.end()) {
918         return;
919     }
920 
921     std::vector<int32_t> removeIndexes;
922     bool foundHomeNode = false;
923     int32_t firstNewNodeIndex = GetFirstNewDestinationIndex(preList, curList);
924     for (int32_t index = firstNewNodeIndex - 1; index >= 0; --index) {
925         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
926             NavigationGroupNode::GetNavDestinationNode(curList[index].second));
927         CHECK_NULL_CONTINUE(node);
928         if (!forceSplitUseNavBar_ && node == homeNode) {
929             foundHomeNode = true;
930             break;
931         }
932         removeIndexes.push_back(index);
933     }
934     if (!forceSplitUseNavBar_ && !foundHomeNode) {
935         return;
936     }
937     if (removeIndexes.empty()) {
938         return;
939     }
940 
941     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Remove secondary NavDestinationNodes, count:%{public}d",
942         static_cast<int32_t>(removeIndexes.size()));
943     std::reverse(removeIndexes.begin(), removeIndexes.end());
944     navigationStack_->RemoveByIndexes(removeIndexes);
945     /**
946      * Because calling RemoveByIndexes here will remark the need for stack synchronization for the next VSync signal,
947      * but we have already done it proactively, so we will reset the needSyncWithJsStack_ flag here.
948      */
949     needSyncWithJsStack_ = false;
950     UpdateNavPathList();
951 }
952 
IsForceSplitSupported(const RefPtr<PipelineContext> & context)953 bool NavigationPattern::IsForceSplitSupported(const RefPtr<PipelineContext>& context)
954 {
955     CHECK_NULL_RETURN(context, false);
956     auto manager = context->GetNavigationManager();
957     CHECK_NULL_RETURN(manager, false);
958     return manager->IsForceSplitSupported();
959 }
960 
SyncWithJsStackIfNeeded()961 void NavigationPattern::SyncWithJsStackIfNeeded()
962 {
963     if (!needSyncWithJsStack_) {
964         TAG_LOGI(AceLogTag::ACE_NAVIGATION,
965             "not need SyncWithJsStack, needSyncWithJsStack_ %{public}d", needSyncWithJsStack_);
966         return;
967     }
968     CHECK_NULL_VOID(navigationStack_);
969     needSyncWithJsStack_ = false;
970     if (!isFinishInteractiveAnimation_) {
971         TAG_LOGI(AceLogTag::ACE_NAVIGATION,
972             "not need SyncWithJsStack, interactive animation: %{public}d", isFinishInteractiveAnimation_);
973         return;
974     }
975     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
976     CHECK_NULL_VOID(hostNode);
977     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
978         "sync with js stack, id: %{public}s, UINodeId: %{public}d, preStackSize: %{public}d, newStackSize: %{public}d",
979         hostNode->GetCurId().c_str(), hostNode->GetId(), navigationStack_->PreSize(),
980         static_cast<int32_t>(navigationStack_->GetAllPathName().size()));
981     GetVisibleNodes(true, preVisibleNodes_);
982     if (runningTransitionCount_ <= 0) {
983         isTransitionAnimationAborted_ = false;
984     }
985     preTopNavPath_ = navigationStack_->GetPreTopNavPath();
986     preStackSize_ = navigationStack_->PreSize();
987     preContext_ = nullptr;
988     if (preTopNavPath_.has_value()) {
989         auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(
990             NavigationGroupNode::GetNavDestinationNode(preTopNavPath_->second));
991         if (preDestination) {
992             auto pattern = AceType::DynamicCast<NavDestinationPattern>(preDestination->GetPattern());
993             preContext_ = pattern->GetNavDestinationContext();
994             if (preContext_) {
995                 preContext_->SetPreIndex(preStackSize_ - 1);
996             }
997         }
998     }
999     if (isCustomAnimation_) {
1000         navigationStack_->UpdateRecoveryList();
1001     }
1002     navigationStack_->SavePreNavList();
1003     NavPathList preList;
1004     auto context = hostNode->GetContextRefPtr();
1005     if (IsForceSplitSupported(context)) {
1006         preList = navigationStack_->GetPreNavPathList();
1007         prePrimaryNodes_ = primaryNodes_;
1008     }
1009     UpdateNavPathList();
1010     auto newTopNavPath = navigationStack_->GetTopNavPath();
1011     auto replaceValue = navigationStack_->GetReplaceValue();
1012     if (preTopNavPath_ != newTopNavPath || replaceValue == 1) {
1013         isReplace_ = replaceValue != 0;
1014         UpdateIsAnimation(preTopNavPath_);
1015         lastPreIndex_ = 0;
1016         if (preTopNavPath_.has_value()) {
1017             lastPreIndex_ = navigationStack_->FindIndex(preTopNavPath_->first, preTopNavPath_->second, true);
1018         }
1019         FireInterceptionEvent(true, newTopNavPath);
1020         if (needSyncWithJsStack_) {
1021             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "sync with js stack in before interception");
1022             UpdateNavPathList();
1023             needSyncWithJsStack_ = false;
1024         }
1025     }
1026     if (IsForceSplitSupported(context)) {
1027         ClearSecondaryNodesIfNeeded(std::move(preList));
1028     }
1029     RefreshNavDestination();
1030 }
1031 
RecognizeHomePageIfNeeded()1032 void NavigationPattern::RecognizeHomePageIfNeeded()
1033 {
1034     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1035     CHECK_NULL_VOID(host);
1036     auto context = host->GetContextRefPtr();
1037     if (!IsForceSplitSupported(context)) {
1038         return;
1039     }
1040     const auto& curList = navigationStack_->GetAllNavDestinationNodes();
1041     std::vector<RefPtr<NavDestinationGroupNode>> allDestNodes;
1042     for (const auto& pair : curList) {
1043         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
1044             NavigationGroupNode::GetNavDestinationNode(pair.second));
1045         CHECK_NULL_CONTINUE(node);
1046         allDestNodes.push_back(node);
1047     }
1048 
1049     auto homeNode = homeNode_.Upgrade();
1050     if (homeNode) {
1051         bool homeNodeExistInCurStack = false;
1052         for (const auto& node : allDestNodes) {
1053             if (node == homeNode) {
1054                 homeNodeExistInCurStack = true;
1055                 break;
1056             }
1057         }
1058         if (!homeNodeExistInCurStack) {
1059             homeNode = nullptr;
1060             homeNode_ = nullptr;
1061         }
1062     }
1063     if (homeNode) {
1064         return;
1065     }
1066     CHECK_NULL_VOID(context);
1067     auto navManager = context->GetNavigationManager();
1068     CHECK_NULL_VOID(navManager);
1069     const auto& expectedHomeName = navManager->GetHomePageName();
1070     if (!expectedHomeName.empty()) {
1071         navBarIsHome_ = false;
1072     } else if (IsNavBarValid()) {
1073         if (navBarIsHome_) {
1074             return;
1075         }
1076         auto navBar = AceType::DynamicCast<NavBarNode>(host->GetNavBarNode());
1077         if (navBar && ForceSplitUtils::IsHomePageNavBar(navBar)) {
1078             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Recognize NavBar as HomePage");
1079             navBarIsHome_ = true;
1080             return;
1081         }
1082     }
1083 
1084     for (const auto& node : allDestNodes) {
1085         if (ForceSplitUtils::IsHomePageNavDestination(node)) {
1086             node->SetNavDestinationType(NavDestinationType::HOME);
1087             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Recognize NavDestination[%{public}d] as HomePage", node->GetId());
1088             homeNode_ = WeakPtr(node);
1089             break;
1090         }
1091     }
1092 }
1093 
UpdateNavPathList()1094 void NavigationPattern::UpdateNavPathList()
1095 {
1096     CHECK_NULL_VOID(navigationStack_);
1097     auto pathNames = navigationStack_->GetAllPathName();
1098     auto indexes = navigationStack_->GetAllPathIndex();
1099     topFromSingletonMoved_ = navigationStack_->IsTopFromSingletonMoved();
1100     navigationStack_->ResetSingletonMoved();
1101     navigationStack_->InitNavPathIndex(pathNames);
1102     auto cacheNodes = navigationStack_->GetAllCacheNodes();
1103     NavPathList navPathList;
1104     int32_t pathListSize = static_cast<int32_t>(pathNames.size());
1105     isCurTopNewInstance_ = false;
1106     // lastRecoveredStandardIndex will be only used in recovery case
1107     int32_t lastRecoveredStandardIndex = 0;
1108     int32_t removeSize = 0; // push destination failed size
1109     bool isCurForceSetList = false;
1110     for (int32_t index = 0; index < pathListSize; ++index) {
1111         auto pathName = pathNames[index];
1112         RefPtr<UINode> uiNode = nullptr;
1113         int32_t arrayIndex = index - removeSize;
1114         if (navigationStack_->IsFromRecovery(arrayIndex)) {
1115             if (navigationStack_->GetRecoveredDestinationMode(arrayIndex) ==
1116                 static_cast<int32_t>(NavDestinationMode::STANDARD)) {
1117                 lastRecoveredStandardIndex = arrayIndex;
1118             }
1119             navPathList.emplace_back(std::make_pair(pathName, uiNode));
1120             // only create recovery node when it is at top
1121             if (index == pathListSize - 1) {
1122                 removeSize += GenerateUINodeFromRecovery(lastRecoveredStandardIndex, navPathList);
1123             }
1124             continue;
1125         }
1126         auto pathIndex = indexes[index];
1127         if (navigationStack_->NeedBuildNewInstance(arrayIndex)) {
1128             navigationStack_->SetNeedBuildNewInstance(arrayIndex, false);
1129             // if marked NEW_INSTANCE when push/replace in frontend, build a new instance anyway
1130             if (!GenerateUINodeByIndex(arrayIndex, uiNode)) {
1131                 removeSize++;
1132                 continue;
1133             }
1134             navPathList.emplace_back(std::make_pair(pathName, uiNode));
1135             if (index == pathListSize - 1) {
1136                 isCurTopNewInstance_ = true;
1137             }
1138             continue;
1139         }
1140         bool isPageForceSet = navigationStack_->GetIsForceSet(arrayIndex);
1141         if (isPageForceSet) {
1142             isCurForceSetList = true;
1143         }
1144         auto navDestinationId = navigationStack_->GetNavDestinationIdInt(arrayIndex);
1145         if (index == pathListSize - 1 && addByNavRouter_) {
1146             addByNavRouter_ = false;
1147             uiNode = navigationStack_->Get();
1148         } else if (isCurForceSetList) {
1149             if (static_cast<int32_t>(navDestinationId) != -1) {
1150                 uiNode = FindNavDestinationNodeInPreList(navDestinationId);
1151             }
1152         } else {
1153             uiNode = navigationStack_->Get(pathIndex);
1154         }
1155         if (uiNode) {
1156             TAG_LOGD(AceLogTag::ACE_NAVIGATION, "find in list, navigation stack reserve node, "
1157                 "old index: %{public}d, index: %{public}d, removeSize: %{public}d, name: %{public}s.",
1158                 pathIndex, index, removeSize, pathName.c_str());
1159             /**
1160              * If we call the function pushPath/pushDestination with singleton mode(
1161              * LaunchMode == MOVE_TO_TOP_SINGLETON/POP_TO_SINGLETON), and the top NavDestination of stack
1162              * is the NavDestination which we need to push(NavDestination's name == NavPathInfo's name),
1163              * then wee need to update the NavDestination's parameters.
1164              */
1165             navigationStack_->UpdatePathInfoIfNeeded(uiNode, arrayIndex);
1166             auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(
1167                 NavigationGroupNode::GetNavDestinationNode(uiNode));
1168             if (navDestinationGroupNode && navDestinationGroupNode->GetCanReused()) {
1169                 navigationStack_->ResetIsForceSetFlag(arrayIndex);
1170                 navPathList.emplace_back(std::make_pair(pathName, uiNode));
1171                 continue;
1172             }
1173         }
1174         uiNode = navigationStack_->GetFromCacheNode(cacheNodes, pathName);
1175         if (uiNode) {
1176             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "find in cached node, navigation stack reserve node, "
1177                 "index: %{public}d, removeSize: %{public}d, name: %{public}s.", index, removeSize, pathName.c_str());
1178             navPathList.emplace_back(std::make_pair(pathName, uiNode));
1179             navigationStack_->RemoveCacheNode(cacheNodes, pathName, uiNode);
1180             auto navDestination =
1181                 DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(uiNode));
1182             if (navDestination) {
1183                 navDestination->SetInCurrentStack(true);
1184                 auto eventHub = navDestination->GetOrCreateEventHub<EventHub>();
1185                 CHECK_NULL_VOID(eventHub);
1186                 eventHub->SetEnabledInternal(true);
1187                 navigationStack_->ResetIsForceSetFlag(arrayIndex);
1188             }
1189             continue;
1190         }
1191         if (isPageForceSet) {
1192             navPathList.emplace_back(std::make_pair(pathName, uiNode));
1193             continue;
1194         }
1195         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "find in nowhere, navigation stack create new node, "
1196             "index: %{public}d, removeSize: %{public}d, name: %{public}s.", index, removeSize, pathName.c_str());
1197         if (!GenerateUINodeByIndex(arrayIndex, uiNode)) {
1198             std::string replacedName = "";
1199             int32_t replacedIndex = -1;
1200             if (navigationStack_->CheckIsReplacedDestination(arrayIndex, replacedName, replacedIndex)) {
1201                 navigationStack_->SetRecoveryFromReplaceDestination(arrayIndex, false);
1202                 pathNames[index] = replacedName;
1203                 indexes[index] = replacedIndex;
1204                 index--;
1205                 continue;
1206             }
1207             removeSize++;
1208             continue;
1209         }
1210         navPathList.emplace_back(std::make_pair(pathName, uiNode));
1211     }
1212     if (isCurForceSetList) {
1213         GenerateLastStandardPage(navPathList);
1214     }
1215     navigationStack_->SetNavPathList(navPathList);
1216     navigationStack_->SetIsCurForceSetList(isCurForceSetList);
1217 }
1218 
RefreshNavDestination()1219 void NavigationPattern::RefreshNavDestination()
1220 {
1221     isChanged_ = false;
1222     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1223     CHECK_NULL_VOID(hostNode);
1224     auto pipeline = PipelineContext::GetCurrentContext();
1225     CHECK_NULL_VOID(pipeline);
1226     auto preTopNavPath = std::move(preTopNavPath_);
1227     auto preLastStandardIndex = hostNode->GetLastStandardIndex();
1228     auto& navPathList = navigationStack_->GetAllNavDestinationNodes();
1229     hostNode->UpdateNavDestinationNodeWithoutMarkDirty(
1230         preTopNavPath.has_value() ? preTopNavPath->second : nullptr, navigationModeChange_);
1231     auto newTopNavPath = navigationStack_->GetTopNavPath();
1232 #if defined(ENABLE_NAV_SPLIT_MODE)
1233     isBackPage_ = newTopNavPath.has_value() ?
1234         navigationStack_->isLastListContains(newTopNavPath->first, newTopNavPath->second) : false;
1235 #endif
1236     if (topFromSingletonMoved_) {
1237         FireOnNewParam(newTopNavPath.has_value() ? newTopNavPath->second : nullptr);
1238     }
1239     CheckTopNavPathChange(preTopNavPath, newTopNavPath, preLastStandardIndex);
1240 
1241     // close keyboard
1242 #if defined(ENABLE_STANDARD_INPUT)
1243     RefPtr<FrameNode> targetNode = newTopNavPath.has_value() ? AceType::DynamicCast<FrameNode>(
1244             NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second)) :
1245             AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
1246     if (isChanged_ && GetIsFocusable(targetNode)) {
1247         InputMethodManager::GetInstance()->CloseKeyboard();
1248     }
1249 #endif
1250 
1251 #if defined(ENABLE_NAV_SPLIT_MODE)
1252     navigationStack_->SetLastNavPathList(navPathList);
1253 #endif
1254 
1255     /* if first navDestination is removed, the new one will be refreshed */
1256     if (!navPathList.empty()) {
1257         auto firstNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(
1258             NavigationGroupNode::GetNavDestinationNode(navPathList.front().second));
1259         CHECK_NULL_VOID(firstNavDesNode);
1260         firstNavDesNode->MarkModifyDone();
1261     }
1262 
1263     std::string navDestinationName = newTopNavPath.has_value() ? newTopNavPath->first : "";
1264     pipeline->AddPredictTask([weak = WeakClaim(this), weakNode = WeakPtr<FrameNode>(hostNode),
1265         navDestinationName](int64_t deadline, bool canUseLongPredictTask) {
1266             auto navigationPattern = weak.Upgrade();
1267             CHECK_NULL_VOID(navigationPattern);
1268             auto navigationNode = weakNode.Upgrade();
1269             CHECK_NULL_VOID(navigationNode);
1270             int32_t count = 0;
1271             int32_t depth = 0;
1272             navigationNode->GetPageNodeCountAndDepth(&count, &depth);
1273             navigationPattern->PerformanceEventReport(count, depth, navDestinationName);
1274         });
1275 }
1276 
UpdateColorModeForNodes(const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath)1277 void NavigationPattern::UpdateColorModeForNodes(
1278     const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath)
1279 {
1280     if (SystemProperties::ConfigChangePerform()) {
1281         auto& allStackNode = navigationStack_->GetAllNavDestinationNodes();
1282         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1283         CHECK_NULL_VOID(hostNode);
1284         auto lastIndex = hostNode->GetLastStandardIndex();
1285         lastIndex = lastIndex < 0 ? 0 : lastIndex;
1286         auto pipelineContext = hostNode->GetContext();
1287         CHECK_NULL_VOID(pipelineContext);
1288         auto colorMode = pipelineContext->GetColorMode() == ColorMode::DARK ? true : false;
1289         for (auto index = lastIndex; index < static_cast<int32_t>(allStackNode.size()); index++) {
1290             auto node = allStackNode[index].second;
1291             if (node && node->CheckIsDarkMode() == colorMode) {
1292                 continue;
1293             }
1294             pipelineContext->SetIsSystemColorChange(false);
1295             node->SetRerenderable(true);
1296             node->NotifyColorModeChange(colorMode);
1297         }
1298         if (!newTopNavPath.has_value()) {
1299             auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
1300             CHECK_NULL_VOID(nodeBase);
1301             if (nodeBase->CheckIsDarkMode() == colorMode) {
1302                 return;
1303             }
1304             pipelineContext->SetIsSystemColorChange(false);
1305             nodeBase->SetRerenderable(true);
1306             nodeBase->NotifyColorModeChange(colorMode);
1307         }
1308     }
1309 }
1310 
ProcessSameTopNavPath()1311 void NavigationPattern::ProcessSameTopNavPath()
1312 {
1313     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "page is not change. don't transition");
1314     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1315     CHECK_NULL_VOID(hostNode);
1316     auto currentProxy = GetTopNavigationProxy();
1317     if (currentProxy) {
1318         currentProxy->SetIsSuccess(false);
1319     }
1320 
1321     auto pipeline = hostNode->GetContextRefPtr();
1322     bool isForceSplitSupported = IsForceSplitSupported(pipeline);
1323     std::set<RefPtr<NavDestinationGroupNode>> filterNodes;
1324     if (isForceSplitSupported) {
1325         AppendFilterNodesForWillHideLifecycle(filterNodes);
1326     }
1327     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_HIDE);
1328     if (isForceSplitSupported) {
1329         NotifyPrePrimaryNodesOnWillHide(std::move(filterNodes));
1330         filterNodes.clear();
1331         AppendFilterNodesForWillShowLifecycle(filterNodes);
1332         NotifyCurPrimaryNodesOnWillShow(std::move(filterNodes));
1333     }
1334     NotifyDialogChange(NavDestinationLifecycle::ON_WILL_SHOW, true);
1335     CHECK_NULL_VOID(pipeline);
1336     pipeline->AddAfterLayoutTask([weakPattern = WeakClaim(this), isForceSplitSupported]() {
1337         auto pattern = weakPattern.Upgrade();
1338         CHECK_NULL_VOID(pattern);
1339         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(pattern->GetHost());
1340         CHECK_NULL_VOID(hostNode);
1341         hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
1342         if (isForceSplitSupported) {
1343             pattern->FirePreTopPrimaryNodeInactiveIfNeeded();
1344             pattern->FirePrePrimaryNodesOnHide();
1345         }
1346 
1347         std::set<RefPtr<NavDestinationGroupNode>> filterNodes;
1348         if (isForceSplitSupported) {
1349             pattern->AppendFilterNodesFromHideNodes(filterNodes);
1350         }
1351         hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1352         if (isForceSplitSupported) {
1353             pattern->FirePrePrimaryNodesOnWillDisappear(std::move(filterNodes));
1354             pattern->FirePrimaryNodesOnShowAndActive();
1355         }
1356 
1357         pattern->NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true);
1358         hostNode->RemoveDialogDestination();
1359 
1360         if (isForceSplitSupported) {
1361             pattern->prePrimaryNodes_.clear();
1362             pattern->primaryNodesToBeRemoved_.clear();
1363             pattern->RemoveRedundantPrimaryNavDestination();
1364         }
1365     });
1366     ClearRecoveryList();
1367 }
1368 
CheckTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath,int32_t preLastStandardIndex)1369 void NavigationPattern::CheckTopNavPathChange(
1370     const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath,
1371     const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath,
1372     int32_t preLastStandardIndex)
1373 {
1374     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1375     CHECK_NULL_VOID(hostNode);
1376     if (preTopNavPath != newTopNavPath) {
1377         UpdateSystemBarStyleOnTopNavPathChange(newTopNavPath);
1378     }
1379     auto replaceValue = navigationStack_->GetReplaceValue();
1380     if (preTopNavPath == newTopNavPath) {
1381         ProcessSameTopNavPath();
1382         return;
1383     }
1384 
1385     isChanged_ = true;
1386     UpdateIsAnimation(preTopNavPath);
1387     isReplace_ = replaceValue != 0;
1388     if (replaceValue == 1) {
1389         const int32_t replaceAnimation = 2;
1390         navigationStack_->UpdateReplaceValue(replaceAnimation);
1391     }
1392     auto context = PipelineContext::GetCurrentContext();
1393     CHECK_NULL_VOID(context);
1394     // close the text selection menu before transition.
1395     auto selectOverlayManager = context->GetSelectOverlayManager();
1396     if (selectOverlayManager) {
1397         selectOverlayManager->ResetSelectionAndDestroySelectOverlay();
1398     }
1399     // fire onHidden and lostFocus event
1400     RefPtr<NavDestinationGroupNode> preTopNavDestination;
1401     int32_t lastPreIndex = -1;
1402     bool isPopPage = false;
1403     if (preTopNavPath.has_value()) {
1404         // pre page is not in the current stack
1405         lastPreIndex = navigationStack_->FindIndex(preTopNavPath->first, preTopNavPath->second, true);
1406         isPopPage |= lastPreIndex == -1;
1407         preTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1408             NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
1409     }
1410     if (isCurTopNewInstance_) {
1411         isPopPage = false;
1412     }
1413     RefPtr<NavDestinationGroupNode> newTopNavDestination;
1414     UpdateColorModeForNodes(newTopNavPath);
1415     if (newTopNavPath.has_value()) {
1416         newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1417             NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
1418         do {
1419             if (!newTopNavDestination) {
1420                 break;
1421             }
1422             if (!GetIsFocusable(newTopNavDestination)) {
1423                 break;
1424             }
1425             auto navDestinationPattern = newTopNavDestination->GetPattern<NavDestinationPattern>();
1426             auto navDestinationFocusView = AceType::DynamicCast<FocusView>(navDestinationPattern);
1427             CHECK_NULL_VOID(navDestinationFocusView);
1428             if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1429                 navDestinationFocusView->SetIsViewRootScopeFocused(false);
1430             }
1431             navDestinationFocusView->FocusViewShow();
1432         } while (0);
1433     } else {
1434         // back to navBar or HomeDestination case
1435         auto navBarOrHomeDestNode =
1436             AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
1437         CHECK_NULL_VOID(navBarOrHomeDestNode);
1438         navBarOrHomeDestNode->SetNodeFreeze(false);
1439         auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
1440         if (!navigationLayoutProperty->GetHideNavBarValue(false)) {
1441             navBarOrHomeDestNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
1442             navBarOrHomeDestNode->SetJSViewActive(true);
1443         }
1444         ProcessPageShowEvent();
1445         navBarOrHomeDestNode->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
1446         if (GetIsFocusable(navBarOrHomeDestNode)) {
1447             auto navBarOrHomeDestFocusView = navBarOrHomeDestNode->GetPattern<FocusView>();
1448             CHECK_NULL_VOID(navBarOrHomeDestFocusView);
1449             if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1450                 navBarOrHomeDestFocusView->SetIsViewRootScopeFocused(false);
1451             }
1452             navBarOrHomeDestFocusView->FocusViewShow();
1453         }
1454     }
1455     bool isShow = false;
1456     bool isDialog =
1457         (preTopNavDestination && preTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG) ||
1458         (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
1459     if (preTopNavDestination && isDialog) {
1460         auto lastStandardIndex = hostNode->GetLastStandardIndex();
1461         isShow = (lastPreIndex != -1) && (lastPreIndex >= lastStandardIndex);
1462         hostNode->SetNeedSetInvisible(lastStandardIndex >= 0);
1463         if (lastStandardIndex < 0) {
1464             auto navBarOrHomeDestNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
1465             auto layoutProperty = navBarOrHomeDestNode->GetLayoutProperty();
1466             layoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
1467             navBarOrHomeDestNode->SetJSViewActive(true);
1468         }
1469     }
1470     bool disableAllAnimation = navigationStack_->GetDisableAnimation();
1471     bool animated = navigationStack_->GetAnimatedValue();
1472     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
1473         "transition start, disableAllAnimation: %{public}d, animated: %{public}d, isPopPage: %{public}d, isDialog: "
1474         "%{public}d, isReplace: %{public}d, isCustomAnimation: %{public}d",
1475         disableAllAnimation, animated, isPopPage, isDialog, isReplace_, isCustomAnimation_);
1476     if (disableAllAnimation || !animated) {
1477         // transition without animation need to run before layout for geometryTransition.
1478         StartTransition(preTopNavDestination, newTopNavDestination, false, isPopPage, isShow);
1479         navigationStack_->UpdateAnimatedValue(true);
1480         hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
1481         return;
1482     }
1483     if (isDialog && !isCustomAnimation_) {
1484         bool isNeedAnimation =
1485             AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_THIRTEEN) ?
1486             true : false;
1487         StartTransition(preTopNavDestination, newTopNavDestination, isNeedAnimation, isPopPage, isShow);
1488         hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
1489         return;
1490     }
1491 
1492     // before the animation of navDes replacing, update the zIndex of the previous navDes node
1493     UpdatePreNavDesZIndex(preTopNavDestination, newTopNavDestination, preLastStandardIndex);
1494     // transition with animation need to run after layout task
1495     StartTransition(preTopNavDestination, newTopNavDestination, true, isPopPage, isShow);
1496     hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
1497 }
1498 
FireNavDestinationStateChange(NavDestinationLifecycle lifecycle)1499 int32_t NavigationPattern::FireNavDestinationStateChange(NavDestinationLifecycle lifecycle)
1500 {
1501     const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
1502     auto errIndex = static_cast<int32_t>(navDestinationNodes.size());
1503     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1504     CHECK_NULL_RETURN(hostNode, errIndex);
1505     NotifyDialogChange(lifecycle, true);
1506     return hostNode->GetLastStandardIndex();
1507 }
1508 
FireNavigationStateChange(const RefPtr<UINode> & node,bool isShow)1509 void NavigationPattern::FireNavigationStateChange(const RefPtr<UINode>& node, bool isShow)
1510 {
1511     if (isShow) {
1512         NavigationPattern::FireNavigationLifecycleChange(node, NavDestinationLifecycle::ON_SHOW);
1513         return;
1514     }
1515     NavigationPattern::FireNavigationLifecycleChange(node, NavDestinationLifecycle::ON_HIDE);
1516 }
1517 
CheckParentDestinationIsOnhide(const RefPtr<NavDestinationGroupNode> & destinationNode)1518 bool NavigationPattern::CheckParentDestinationIsOnhide(const RefPtr<NavDestinationGroupNode>& destinationNode)
1519 {
1520     CHECK_NULL_RETURN(destinationNode, false);
1521     auto destinationNodePattern = destinationNode->GetPattern<NavDestinationPattern>();
1522     CHECK_NULL_RETURN(destinationNodePattern, false);
1523     return !destinationNodePattern->GetIsOnShow();
1524 }
1525 
CheckParentDestinationInactive()1526 bool NavigationPattern::CheckParentDestinationInactive()
1527 {
1528     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1529     CHECK_NULL_RETURN(hostNode, false);
1530     auto parentDestination = hostNode->GetParentDestinationNode().Upgrade();
1531     CHECK_NULL_RETURN(parentDestination, false);
1532     auto pattern = parentDestination->GetPattern<NavDestinationPattern>();
1533     CHECK_NULL_RETURN(pattern, false);
1534     return !pattern->IsActive();
1535 }
1536 
CheckDestinationIsPush(const RefPtr<NavDestinationGroupNode> & destinationNode)1537 bool NavigationPattern::CheckDestinationIsPush(const RefPtr<NavDestinationGroupNode>& destinationNode)
1538 {
1539     CHECK_NULL_RETURN(destinationNode, false);
1540     return destinationNode->GetIndex() != -1 || destinationNode->GetNavDestinationCustomNode();
1541 }
1542 
CheckIfNeedHideOrShowPrimaryNodes(const RefPtr<NavigationPattern> & pattern,int32_t lastStandardIndex)1543 bool NavigationPattern::CheckIfNeedHideOrShowPrimaryNodes(
1544     const RefPtr<NavigationPattern>& pattern, int32_t lastStandardIndex)
1545 {
1546     CHECK_NULL_RETURN(pattern, false);
1547     if (!pattern->GetHomeNode()) {
1548         return false;
1549     }
1550     auto primaryNodes = pattern->GetPrimaryNodes();
1551     if (primaryNodes.empty()) {
1552         return false;
1553     }
1554     auto firstNode = primaryNodes[0].Upgrade();
1555     CHECK_NULL_RETURN(firstNode, false);
1556     auto homeIndex = firstNode->GetIndex();
1557     if (homeIndex >= lastStandardIndex) {
1558         return false;
1559     }
1560     return true;
1561 }
1562 
FireNavigationInner(const RefPtr<UINode> & node,bool isOnShow)1563 void NavigationPattern::FireNavigationInner(const RefPtr<UINode>& node, bool isOnShow)
1564 {
1565     CHECK_NULL_VOID(node);
1566     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(node);
1567     if (!navigationNode) {
1568         NavigationPattern::FireNavigationChange(node, isOnShow, false);
1569         return;
1570     }
1571     auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
1572     CHECK_NULL_VOID(navigationPattern);
1573     CHECK_NULL_VOID(navigationPattern->navigationStack_);
1574     const auto& navDestinationNodes = navigationPattern->navigationStack_->GetAllNavDestinationNodes();
1575     auto lastStandardIndex = navigationNode->GetLastStandardIndex();
1576     int32_t standardIndex = lastStandardIndex >= 0 ? lastStandardIndex : 0;
1577     int32_t start = standardIndex;
1578     int32_t end = navigationPattern->navigationStack_->Size();
1579     auto pipeline = PipelineContext::GetCurrentContext();
1580     CHECK_NULL_VOID(pipeline);
1581     auto overlayManager = pipeline->GetOverlayManager();
1582     bool needHideOrShowPrimaryNodes = CheckIfNeedHideOrShowPrimaryNodes(navigationPattern, lastStandardIndex);
1583 
1584     if (isOnShow) {
1585         if (overlayManager && overlayManager->HasModalPage()) {
1586             return;
1587         }
1588         if (needHideOrShowPrimaryNodes) {
1589             navigationPattern->FirePrimaryNodesLifecycle(NavDestinationLifecycle::ON_SHOW);
1590         }
1591         navigationPattern->FireHomeDestinationLifeCycleIfNeeded(
1592             NavDestinationLifecycle::ON_SHOW, false, NavDestinationActiveReason::APP_STATE_CHANGE);
1593         navigationPattern->FireHomeDestinationLifeCycleIfNeeded(
1594             NavDestinationLifecycle::ON_ACTIVE, false, NavDestinationActiveReason::APP_STATE_CHANGE);
1595         for (int32_t index = start; index < end; index++) {
1596             const auto& curPath = navDestinationNodes[index];
1597             auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1598                 navigationNode->GetNavDestinationNode(curPath.second));
1599             if (!curDestination || !curDestination->GetLayoutProperty()) {
1600                 continue;
1601             }
1602             auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1603             CHECK_NULL_VOID(navDestinationPattern);
1604             auto property = curDestination->GetLayoutProperty();
1605             if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE ||
1606                 !curDestination->IsActive() || navDestinationPattern->GetIsOnShow() == isOnShow) {
1607                 continue;
1608             }
1609             auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
1610             CHECK_NULL_VOID(eventHub);
1611             auto param = Recorder::EventRecorder::Get().IsPageParamRecordEnable() ?
1612                 navigationPattern->navigationStack_->GetRouteParam() : "";
1613             eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
1614             navDestinationPattern->SetIsOnShow(true);
1615             NavigationPattern::FireNavigationChange(curDestination, true, false);
1616             NavigationPattern::NotifyPerfMonitorPageMsg(navDestinationPattern->GetName());
1617         }
1618         return;
1619     }
1620     for (int32_t index = end - 1; index >= 0 && index >= start; index--) {
1621         const auto& curPath = navDestinationNodes[index];
1622         auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1623             navigationNode->GetNavDestinationNode(curPath.second));
1624         if (!curDestination || !curDestination->GetLayoutProperty()) {
1625             continue;
1626         }
1627         auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1628         CHECK_NULL_VOID(navDestinationPattern);
1629         auto property = curDestination->GetLayoutProperty();
1630         if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE ||
1631             !curDestination->IsActive() || navDestinationPattern->GetIsOnShow() == isOnShow) {
1632             continue;
1633         }
1634         auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
1635         CHECK_NULL_VOID(eventHub);
1636         eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
1637         navDestinationPattern->SetIsOnShow(false);
1638         NavigationPattern::FireNavigationChange(curDestination, false, false);
1639     }
1640     navigationPattern->FireHomeDestinationLifeCycleIfNeeded(
1641         NavDestinationLifecycle::ON_INACTIVE, false, NavDestinationActiveReason::APP_STATE_CHANGE);
1642     navigationPattern->FireHomeDestinationLifeCycleIfNeeded(
1643         NavDestinationLifecycle::ON_HIDE, false, NavDestinationActiveReason::APP_STATE_CHANGE);
1644     if (needHideOrShowPrimaryNodes) {
1645         navigationPattern->FirePrimaryNodesLifecycle(NavDestinationLifecycle::ON_HIDE);
1646     }
1647 }
1648 
FireNavigationChange(const RefPtr<UINode> & node,bool isOnShow,bool isFirst)1649 void NavigationPattern::FireNavigationChange(const RefPtr<UINode>& node, bool isOnShow, bool isFirst)
1650 {
1651     CHECK_NULL_VOID(node);
1652     if (isFirst) {
1653         FireNavigationInner(node, isOnShow);
1654         return;
1655     }
1656     const auto children = node->GetChildren(true);
1657     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1658         auto& child = *iter;
1659         FireNavigationInner(child, isOnShow);
1660     }
1661 }
1662 
FireNavigationLifecycleChange(const RefPtr<UINode> & node,NavDestinationLifecycle lifecycle)1663 void NavigationPattern::FireNavigationLifecycleChange(const RefPtr<UINode>& node, NavDestinationLifecycle lifecycle)
1664 {
1665     CHECK_NULL_VOID(node);
1666     const auto children = node->GetChildren(true);
1667     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1668         auto& child = *iter;
1669         auto navigation = AceType::DynamicCast<NavigationGroupNode>(child);
1670         if (navigation) {
1671             auto destinationNode = navigation->GetParentDestinationNode().Upgrade();
1672             if ((lifecycle == NavDestinationLifecycle::ON_SHOW) && CheckParentDestinationIsOnhide(destinationNode) &&
1673                 CheckDestinationIsPush(destinationNode)) {
1674                 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation parent is onhide");
1675                 continue;
1676             }
1677             auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
1678             CHECK_NULL_VOID(navigationPattern);
1679             navigationPattern->FireNavDestinationStateChange(lifecycle);
1680         } else {
1681             NavigationPattern::FireNavigationLifecycleChange(child, lifecycle);
1682         }
1683     }
1684 }
1685 
NotifyPageHide(const std::string & pageName)1686 void NavigationPattern::NotifyPageHide(const std::string& pageName)
1687 {
1688     auto container = Container::Current();
1689     CHECK_NULL_VOID(container);
1690     auto pageUrlChecker = container->GetPageUrlChecker();
1691     CHECK_NULL_VOID(pageUrlChecker);
1692     pageUrlChecker->NotifyPageHide(pageName);
1693 }
1694 
NotifyPageShow(const std::string & pageName)1695 void NavigationPattern::NotifyPageShow(const std::string& pageName)
1696 {
1697     auto container = Container::Current();
1698     CHECK_NULL_VOID(container);
1699     auto pageUrlChecker = container->GetPageUrlChecker();
1700     CHECK_NULL_VOID(pageUrlChecker);
1701     pageUrlChecker->NotifyPageShow(pageName);
1702     if (PerfMonitor::GetPerfMonitor() != nullptr) {
1703         PerfMonitor::GetPerfMonitor()->SetPageName(pageName);
1704     }
1705 }
1706 
ProcessPageShowEvent()1707 void NavigationPattern::ProcessPageShowEvent()
1708 {
1709     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1710     CHECK_NULL_VOID(hostNode);
1711     auto context = hostNode->GetContext();
1712     CHECK_NULL_VOID(context);
1713     auto stageManager = context->GetStageManager();
1714     if (stageManager) {
1715         RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1716         CHECK_NULL_VOID(pageNode);
1717         auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1718         CHECK_NULL_VOID(pagePattern);
1719         auto pageInfo = pagePattern->GetPageInfo();
1720         CHECK_NULL_VOID(pageInfo);
1721         NotifyPageShow(pageInfo->GetPageUrl());
1722     }
1723 }
1724 
ReplaceAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination)1725 void NavigationPattern::ReplaceAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1726     const RefPtr<NavDestinationGroupNode>& newTopNavDestination)
1727 {
1728     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1729     CHECK_NULL_VOID(navigationNode);
1730     auto navBarOrHomeDestNode =
1731         AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
1732     CHECK_NULL_VOID(navBarOrHomeDestNode);
1733     bool preUseCustomTransition = TriggerNavDestinationTransition(
1734         (preTopNavDestination ? preTopNavDestination :
1735         AceType::DynamicCast<NavDestinationGroupNode>(navBarOrHomeDestNode)),
1736         NavigationOperation::REPLACE, false) != INVALID_ANIMATION_ID;
1737     TriggerNavDestinationTransition(newTopNavDestination, NavigationOperation::REPLACE, true);
1738     if (newTopNavDestination && preTopNavDestination && !preUseCustomTransition) {
1739         navigationNode->DealNavigationExit(preTopNavDestination, false, false);
1740     } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1741         navigationNode->DealNavigationExit(navBarOrHomeDestNode, true, false);
1742     }
1743     navigationNode->RemoveDialogDestination();
1744     auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1745     navigationNode->OnAccessibilityEvent(
1746         AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1747     navigationStack_->UpdateReplaceValue(0);
1748 
1749     auto context = navigationNode->GetContext();
1750     CHECK_NULL_VOID(context);
1751     OnStartOneTransitionAnimation();
1752     context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
1753         auto pattern = weak.Upgrade();
1754         CHECK_NULL_VOID(pattern);
1755         pattern->OnFinishOneTransitionAnimation();
1756     });
1757 }
1758 
TransitionWithOutAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,RefPtr<NavDestinationGroupNode> newTopNavDestination,bool isPopPage,bool needVisible)1759 void NavigationPattern::TransitionWithOutAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,
1760     RefPtr<NavDestinationGroupNode> newTopNavDestination, bool isPopPage, bool needVisible)
1761 {
1762     ClearRecoveryList();
1763     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1764     CHECK_NULL_VOID(navigationNode);
1765     auto navBarOrHomeDestNode =
1766         AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
1767     CHECK_NULL_VOID(navBarOrHomeDestNode);
1768 
1769     // replace
1770     auto replaceVal = navigationStack_->GetReplaceValue();
1771     if (replaceVal != 0) {
1772         ReplaceAnimation(preTopNavDestination, newTopNavDestination);
1773         return;
1774     }
1775 
1776     auto context = navigationNode->GetContext();
1777     CHECK_NULL_VOID(context);
1778     OnStartOneTransitionAnimation();
1779     context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
1780         auto pattern = weak.Upgrade();
1781         CHECK_NULL_VOID(pattern);
1782         pattern->OnFinishOneTransitionAnimation();
1783     });
1784 
1785     // navDestination push/pop navDestination
1786     if (newTopNavDestination && preTopNavDestination) {
1787         if (isPopPage) {
1788             newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
1789             preTopNavDestination->CleanContent(false, true);
1790             auto parent = preTopNavDestination->GetParent();
1791             CHECK_NULL_VOID(parent);
1792             parent->RemoveChild(preTopNavDestination, true);
1793             parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1794         } else {
1795             preTopNavDestination->GetRenderContext()->RemoveClipWithRRect();
1796             preTopNavDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
1797             newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
1798             if (forceSplitSuccess_ &&
1799                 (preTopNavDestination->IsShowInPrimaryPartition() ||
1800                 newTopNavDestination->IsShowInPrimaryPartition())) {
1801                 needVisible = true;
1802             }
1803             DealTransitionVisibility(preTopNavDestination, needVisible, false);
1804             if (preTopNavDestination->NeedRemoveInPush()) {
1805                 preTopNavDestination->CleanContent(false, true);
1806                 auto parent = preTopNavDestination->GetParent();
1807                 CHECK_NULL_VOID(parent);
1808                 parent->RemoveChild(preTopNavDestination, true);
1809                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1810             }
1811         }
1812         navigationNode->RemoveDialogDestination();
1813         auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1814         navigationNode->OnAccessibilityEvent(
1815             AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1816         return;
1817     }
1818 
1819     // navBar or HomeDestination push navDestination
1820     if (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
1821         newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
1822         // current mode is stack, set navBar or HomeDestination invisible
1823         auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
1824         if (layoutProperty && layoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO) == NavigationMode::STACK
1825             && navBarOrHomeDestNode) {
1826             navBarOrHomeDestNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
1827             DealTransitionVisibility(navBarOrHomeDestNode, false, true);
1828         }
1829         // if current mode is auto, need set navBar need set invisible true
1830         navigationNode->SetNeedSetInvisible(true);
1831     }
1832 
1833     // navDestination pop to navBar or HomeDestination
1834     if (preTopNavDestination) {
1835         preTopNavDestination->CleanContent(false, true);
1836         auto parent = preTopNavDestination->GetParent();
1837         CHECK_NULL_VOID(parent);
1838         parent->RemoveChild(preTopNavDestination, true);
1839         navigationNode->SetNeedSetInvisible(false);
1840         if (navBarOrHomeDestNode) {
1841             navBarOrHomeDestNode->SetTransitionType(PageTransitionType::ENTER_POP);
1842         }
1843         parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1844     }
1845     navigationNode->RemoveDialogDestination();
1846     auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1847     navigationNode->OnAccessibilityEvent(
1848         AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1849 }
1850 
TransitionWithAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,RefPtr<NavDestinationGroupNode> newTopNavDestination,bool isPopPage,bool isNeedVisible)1851 void NavigationPattern::TransitionWithAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,
1852     RefPtr<NavDestinationGroupNode> newTopNavDestination, bool isPopPage, bool isNeedVisible)
1853 {
1854     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1855     CHECK_NULL_VOID(navigationNode);
1856     auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
1857     CHECK_NULL_VOID(layoutProperty);
1858     if (layoutProperty->GetHideNavBarValue(false) && (!newTopNavDestination || !preTopNavDestination)) {
1859         // hide navBarNode and need to do animation with navBarNode
1860         if (preTopNavDestination) {
1861             // remove preTopNavDestination node in pop
1862             auto parent = preTopNavDestination->GetParent();
1863             CHECK_NULL_VOID(parent);
1864             preTopNavDestination->CleanContent();
1865             parent->RemoveChild(preTopNavDestination);
1866             parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1867         }
1868         navigationNode->RemoveDialogDestination();
1869         ClearRecoveryList();
1870         OnStartOneTransitionAnimation();
1871         OnFinishOneTransitionAnimation();
1872         return;
1873     }
1874     if (isCustomAnimation_ && TriggerCustomAnimation(preTopNavDestination, newTopNavDestination, isPopPage)) {
1875         auto operation = NavigationOperation::REPLACE;
1876         if (navigationStack_->GetReplaceValue() == 0) {
1877             operation = isPopPage ? NavigationOperation::POP : NavigationOperation::PUSH;
1878         }
1879         auto homeDestination =
1880             AceType::DynamicCast<NavDestinationGroupNode>(navigationNode->GetNavBarOrHomeDestinationNode());
1881         if (!preTopNavDestination) {
1882             preTopNavDestination = homeDestination;
1883         } else if (!newTopNavDestination) {
1884             newTopNavDestination = homeDestination;
1885         }
1886         TriggerNavDestinationTransition(preTopNavDestination, operation, false);
1887         TriggerNavDestinationTransition(newTopNavDestination, operation, true);
1888         return;
1889     }
1890     StartDefaultAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1891 }
1892 
DialogAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool isNeedVisible)1893 void NavigationPattern::DialogAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1894     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool isNeedVisible)
1895 {
1896     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_THIRTEEN)) {
1897         TransitionWithDialogAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
1898     } else {
1899         TransitionWithOutAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1900     }
1901 }
1902 
StartDefaultAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool isNeedVisible)1903 void NavigationPattern::StartDefaultAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1904     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool isNeedVisible)
1905 {
1906     ClearNavigationCustomTransition();
1907     bool isPreDialog = preTopNavDestination &&
1908         preTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
1909     bool isNewDialog = newTopNavDestination &&
1910         newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
1911     if (isPreDialog || isNewDialog) {
1912         DialogAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isNeedVisible);
1913         return;
1914     }
1915     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1916     CHECK_NULL_VOID(navigationNode);
1917     auto navBarOrHomeDestNode =
1918         AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
1919     CHECK_NULL_VOID(navBarOrHomeDestNode);
1920     // replace
1921     auto replaceValue = navigationStack_->GetReplaceValue();
1922     if (replaceValue != 0) {
1923         if (newTopNavDestination && preTopNavDestination) {
1924             navigationNode->TransitionWithReplace(preTopNavDestination, newTopNavDestination, false);
1925         } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1926             navigationNode->TransitionWithReplace(navBarOrHomeDestNode, newTopNavDestination, true);
1927         }
1928         navigationStack_->UpdateReplaceValue(0);
1929         return;
1930     }
1931     // navDestination push/pop navDestination
1932     if (newTopNavDestination && preTopNavDestination) {
1933         if (isPopPage) {
1934             navigationNode->TransitionWithPop(preTopNavDestination, newTopNavDestination);
1935         } else {
1936             navigationNode->TransitionWithPush(preTopNavDestination, newTopNavDestination);
1937         }
1938         return;
1939     }
1940     // navBar or HomeDestination push navDestination
1941     if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1942         navigationNode->TransitionWithPush(navBarOrHomeDestNode, newTopNavDestination, true);
1943         return;
1944     }
1945     // navDestination pop to navBar or HomeDestination
1946     if (preTopNavDestination) {
1947         if (navigationMode_ == NavigationMode::SPLIT) {
1948             navigationNode->TransitionWithPop(preTopNavDestination, nullptr);
1949         }
1950         if (navigationMode_ == NavigationMode::STACK) {
1951             navigationNode->TransitionWithPop(preTopNavDestination, navBarOrHomeDestNode, true);
1952         }
1953     }
1954 }
1955 
OnVisibleChange(bool isVisible)1956 void NavigationPattern::OnVisibleChange(bool isVisible)
1957 {
1958     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1959     CHECK_NULL_VOID(hostNode);
1960     auto eventHub = hostNode->GetOrCreateEventHub<NavigationEventHub>();
1961     CHECK_NULL_VOID(eventHub);
1962     eventHub->FireNavBarStateChangeEvent(isVisible);
1963 }
1964 
OnNavBarStateChange(bool modeChange)1965 void NavigationPattern::OnNavBarStateChange(bool modeChange)
1966 {
1967     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
1968     CHECK_NULL_VOID(layoutProperty);
1969     auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
1970     if (visibilityValue != VisibleType::VISIBLE) {
1971         return;
1972     }
1973 
1974     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1975     CHECK_NULL_VOID(hostNode);
1976     auto eventHub = hostNode->GetOrCreateEventHub<NavigationEventHub>();
1977     CHECK_NULL_VOID(eventHub);
1978     auto currentNavigationMode = GetNavigationMode();
1979 
1980     auto lastStandardIndex = hostNode->GetLastStandardIndex();
1981     if (modeChange) {
1982         bool navbarIsHidden = (currentNavigationMode == NavigationMode::STACK && lastStandardIndex >= 0) ||
1983                               layoutProperty->GetHideNavBar().value_or(false);
1984         eventHub->FireNavBarStateChangeEvent(!navbarIsHidden);
1985         SetNavBarVisibilityChange(false);
1986         return;
1987     }
1988 
1989     if (GetNavBarVisibilityChange()) {
1990         if (!layoutProperty->GetHideNavBarValue(false)) {
1991             eventHub->FireNavBarStateChangeEvent(true);
1992         } else {
1993             eventHub->FireNavBarStateChangeEvent(false);
1994         }
1995         SetNavBarVisibilityChange(false);
1996         return;
1997     }
1998 
1999     if (currentNavigationMode == NavigationMode::STACK) {
2000         bool navbarIsHidden = (lastStandardIndex >= 0) || layoutProperty->GetHideNavBar().value_or(false);
2001         eventHub->FireNavBarStateChangeEvent(!navbarIsHidden);
2002     }
2003 }
2004 
OnNavigationModeChange(bool modeChange)2005 void NavigationPattern::OnNavigationModeChange(bool modeChange)
2006 {
2007     if (!modeChange) {
2008         return;
2009     }
2010     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2011     CHECK_NULL_VOID(hostNode);
2012     auto eventHub = hostNode->GetOrCreateEventHub<NavigationEventHub>();
2013     CHECK_NULL_VOID(eventHub);
2014     eventHub->FireNavigationModeChangeEvent(navigationMode_);
2015     // fire navigation stack navigation mode change event
2016     navigationStack_->FireNavigationModeChange(navigationMode_);
2017 }
2018 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)2019 bool NavigationPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
2020 {
2021     if (config.skipMeasure && config.skipLayout) {
2022         return false;
2023     }
2024     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2025     CHECK_NULL_RETURN(hostNode, false);
2026     UpdateIsFullPageNavigation(hostNode);
2027     if (navigationModeChange_) {
2028         if (NavigationMode::STACK == navigationMode_) {
2029             // Set focus on navDestination when mode changes to STACK
2030             RefreshFocusToDestination();
2031         }
2032         AbortAnimation(hostNode);
2033     }
2034     auto context = PipelineContext::GetCurrentContext();
2035     if (context) {
2036         context->GetTaskExecutor()->PostTask(
2037             [weak = WeakClaim(this), navigationStackWeak = WeakPtr<NavigationStack>(navigationStack_),
2038                 navigationWeak = WeakPtr<NavigationGroupNode>(hostNode)] {
2039                 auto pattern = weak.Upgrade();
2040                 CHECK_NULL_VOID(pattern);
2041                 auto navigationGroupNode = navigationWeak.Upgrade();
2042                 CHECK_NULL_VOID(navigationGroupNode);
2043                 auto navigationLayoutProperty =
2044                     AceType::DynamicCast<NavigationLayoutProperty>(navigationGroupNode->GetLayoutProperty());
2045                 CHECK_NULL_VOID(navigationLayoutProperty);
2046                 auto navigationStack = navigationStackWeak.Upgrade();
2047                 CHECK_NULL_VOID(navigationStack);
2048                 auto curTopNavPath = navigationStack->GetTopNavPath();
2049                 if (curTopNavPath.has_value()) {
2050                     // considering backButton visibility
2051                     auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
2052                         NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
2053                     pattern->UpdateContextRect(curTopNavDestination, navigationGroupNode);
2054                 }
2055                 // considering navBar/HomeDestination visibility
2056                 auto navBarOrHomeDestNode =
2057                     AceType::DynamicCast<NavDestinationNodeBase>(navigationGroupNode->GetNavBarOrHomeDestinationNode());
2058                 CHECK_NULL_VOID(navBarOrHomeDestNode);
2059                 auto navBarOrHomeDestLayoutProperty =
2060                     navBarOrHomeDestNode->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
2061                 CHECK_NULL_VOID(navBarOrHomeDestLayoutProperty);
2062                 if (pattern->IsForceSplitSuccess()) {
2063                     if (pattern->IsHideNavBarInForceSplitModeNeeded()) {
2064                         navBarOrHomeDestLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
2065                         navBarOrHomeDestNode->SetJSViewActive(false);
2066                     } else {
2067                         navBarOrHomeDestNode->GetRenderContext()->UpdateOpacity(1.0f);
2068                         navBarOrHomeDestLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
2069                         navBarOrHomeDestNode->SetJSViewActive(true);
2070                     }
2071                 } else {
2072                     auto lastStandardIndex = navigationGroupNode->GetLastStandardIndex();
2073                     bool isSetInvisible = navigationGroupNode->GetNeedSetInvisible() && navigationStack->Size() != 0 &&
2074                         lastStandardIndex >= 0;
2075                     if (navigationLayoutProperty->GetHideNavBar().value_or(false) ||
2076                         (pattern->GetNavigationMode() == NavigationMode::STACK && isSetInvisible)) {
2077                         navBarOrHomeDestLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
2078                         navBarOrHomeDestNode->SetJSViewActive(false);
2079                     } else {
2080                         navBarOrHomeDestNode->GetRenderContext()->UpdateOpacity(1.0f);
2081                         navBarOrHomeDestLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
2082                         navBarOrHomeDestNode->SetJSViewActive(true);
2083                     }
2084                 }
2085                 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationGroupNode->GetContentNode());
2086                 CHECK_NULL_VOID(navigationContentNode);
2087                 auto navDestinationNode =
2088                     AceType::DynamicCast<NavDestinationGroupNode>(navigationContentNode->GetLastChild());
2089                 CHECK_NULL_VOID(navDestinationNode);
2090                 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
2091                 auto navDestinationFocusHub = navDestinationNode->GetFocusHub();
2092                 CHECK_NULL_VOID(navDestinationFocusHub);
2093                 auto defaultFocusHub = navDestinationFocusHub->GetChildFocusNodeByType(FocusNodeType::DEFAULT);
2094                 if (!defaultFocusHub && navDestinationNode->GetChildren(true).size() <= EMPTY_DESTINATION_CHILD_SIZE &&
2095                     navDestinationPattern->GetBackButtonState()) {
2096                     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
2097                     CHECK_NULL_VOID(titleBarNode);
2098                     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
2099                     backButtonNode->GetOrCreateFocusHub()->SetIsDefaultFocus(true);
2100                     auto navigation = pattern->GetHost();
2101                     CHECK_NULL_VOID(navigation);
2102                     auto navigationFocusHub = navigation->GetFocusHub();
2103                     CHECK_NULL_VOID(navigationFocusHub);
2104                     auto navDestinationFocusView = navDestinationNode->GetPattern<FocusView>();
2105                     if (navigationFocusHub->IsCurrentFocus() && navDestinationFocusView) {
2106                         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2107                             navDestinationFocusView->SetIsViewRootScopeFocused(false);
2108                         }
2109                         navDestinationFocusView->FocusViewShow();
2110                     }
2111                 }
2112             },
2113             TaskExecutor::TaskType::UI, "ArkUINavigationDirtyLayoutWrapperSwap",
2114             TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
2115     }
2116     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
2117     CHECK_NULL_RETURN(navigationLayoutProperty, false);
2118     UpdateTitleModeChangeEventHub(hostNode);
2119     FireNavBarWidthChangeEvent(dirty);
2120     AddDragBarHotZoneRect();
2121     AddDividerHotZoneRect();
2122     ifNeedInit_ = false;
2123     return false;
2124 }
2125 
AbortAnimation(RefPtr<NavigationGroupNode> & hostNode)2126 void NavigationPattern::AbortAnimation(RefPtr<NavigationGroupNode>& hostNode)
2127 {
2128     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "Aborting navigation animations");
2129     if (runningTransitionCount_ > 0) {
2130         isTransitionAnimationAborted_ = true;
2131     }
2132     if (!hostNode->GetPushAnimations().empty()) {
2133         auto pushAnimations = hostNode->GetPushAnimations();
2134         for (const auto& animation : pushAnimations) {
2135             if (animation) {
2136                 AnimationUtils::StopAnimation(animation);
2137             }
2138         }
2139     }
2140     if (!hostNode->GetPopAnimations().empty()) {
2141         auto popAnimations = hostNode->GetPopAnimations();
2142         for (const auto& animation : popAnimations) {
2143             if (animation) {
2144                 AnimationUtils::StopAnimation(animation);
2145             }
2146         }
2147     }
2148     hostNode->CleanPushAnimations();
2149     hostNode->CleanPopAnimations();
2150 }
2151 
UpdateContextRect(const RefPtr<NavDestinationGroupNode> & curDestination,const RefPtr<NavigationGroupNode> & hostNode)2152 void NavigationPattern::UpdateContextRect(
2153     const RefPtr<NavDestinationGroupNode>& curDestination, const RefPtr<NavigationGroupNode>& hostNode)
2154 {
2155     CHECK_NULL_VOID(curDestination);
2156     CHECK_NULL_VOID(hostNode);
2157     auto navBarOrHomeDestNode =
2158         AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
2159     CHECK_NULL_VOID(navBarOrHomeDestNode);
2160     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
2161     CHECK_NULL_VOID(navigationPattern);
2162 
2163     if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
2164         curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
2165         return;
2166     }
2167     auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
2168     CHECK_NULL_VOID(navigationLayoutProperty);
2169     auto navBarOrHomeDestProperty = navBarOrHomeDestNode->GetLayoutProperty();
2170     navBarOrHomeDestProperty->UpdateVisibility(VisibleType::VISIBLE);
2171     navBarOrHomeDestNode->SetJSViewActive(true);
2172     if (!curDestination->IsOnAnimation()) {
2173         curDestination->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
2174         curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
2175         navBarOrHomeDestNode->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
2176         auto titleBarNode = DynamicCast<TitleBarNode>(navBarOrHomeDestNode->GetTitleBarNode());
2177         CHECK_NULL_VOID(titleBarNode);
2178         auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
2179         CHECK_NULL_VOID(titleNode);
2180         titleNode->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
2181     }
2182 }
2183 
UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode> & hostNode)2184 bool NavigationPattern::UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode>& hostNode)
2185 {
2186     // HomeDestination's title couldn't change titleMode.
2187     auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
2188     CHECK_NULL_RETURN(navBarNode, false);
2189     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
2190     CHECK_NULL_RETURN(titleBarNode, false);
2191     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
2192     CHECK_NULL_RETURN(titleBarLayoutProperty, false);
2193     auto eventHub = hostNode->GetOrCreateEventHub<NavigationEventHub>();
2194     CHECK_NULL_RETURN(eventHub, false);
2195     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
2196         auto titleBarPattern = AceType::DynamicCast<TitleBarPattern>(titleBarNode->GetPattern());
2197         CHECK_NULL_RETURN(titleBarPattern, false);
2198         NavigationTitleMode titleMode = titleBarPattern->GetNavigationTitleMode();
2199         if (titleMode != NavigationTitleMode::FREE && titleMode_ != titleMode) {
2200             NavigationTitleModeChangeEvent navigationTitleModeChange(titleMode == NavigationTitleMode::MINI);
2201             eventHub->FireChangeEvent(&navigationTitleModeChange);
2202             titleMode_ = titleMode;
2203         }
2204     }
2205     return true;
2206 }
2207 
FireNavBarWidthChangeEvent(const RefPtr<LayoutWrapper> & layoutWrapper)2208 void NavigationPattern::FireNavBarWidthChangeEvent(const RefPtr<LayoutWrapper>& layoutWrapper)
2209 {
2210     auto host = GetHost();
2211     CHECK_NULL_VOID(host);
2212     auto geometryNode = host->GetGeometryNode();
2213     CHECK_NULL_VOID(geometryNode);
2214     auto frameSize = geometryNode->GetFrameSize();
2215     auto frameWidth = frameSize.Width();
2216     auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
2217     CHECK_NULL_VOID(navigationLayoutProperty);
2218     auto userSetDimensionUnit = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH).Unit();
2219     CHECK_NULL_VOID(layoutWrapper);
2220     auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
2221     CHECK_NULL_VOID(layoutAlgorithm);
2222     auto navigationLayoutAlgorithm = AceType::DynamicCast<NavigationLayoutAlgorithm>(
2223         layoutAlgorithm->GetLayoutAlgorithm());
2224     CHECK_NULL_VOID(navigationLayoutAlgorithm);
2225     auto realBavBarWidth = navigationLayoutAlgorithm->GetRealNavBarWidth();
2226     auto realNavBarWidthDimension = Dimension(realBavBarWidth, DimensionUnit::PX);
2227     Dimension usrSetUnitWidth = Dimension(0.0, userSetDimensionUnit);
2228     if (!NearZero(frameWidth)) {
2229         usrSetUnitWidth = DimensionUnit::PERCENT == userSetDimensionUnit ?
2230             Dimension(realBavBarWidth / frameWidth, DimensionUnit::PERCENT) :
2231             Dimension(realNavBarWidthDimension.GetNativeValue(userSetDimensionUnit), userSetDimensionUnit);
2232     }
2233     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
2234     initNavBarWidth_ = realBavBarWidth;
2235     SetNavigationWidthToolBarManager(realBavBarWidth, frameWidth - realBavBarWidth - dividerWidth, dividerWidth);
2236     auto eventHub = host->GetEventHub<NavigationEventHub>();
2237     CHECK_NULL_VOID(eventHub);
2238     eventHub->FireNavBarWidthChangeEvent(usrSetUnitWidth);
2239 }
2240 
GenerateUINodeFromRecovery(int32_t lastStandardIndex,NavPathList & navPathList)2241 int32_t NavigationPattern::GenerateUINodeFromRecovery(int32_t lastStandardIndex, NavPathList& navPathList)
2242 {
2243     /**
2244      * In case several pages at the top of stack are dialog pages.
2245      * We need to recovery node until a standard page created.
2246      * And the creation process should be bottom-up to satisfy the order of life-cycle.
2247      */
2248     int32_t jsStackSize = static_cast<int32_t>(navPathList.size());
2249     int32_t removeSize = 0;
2250     for (int32_t index = lastStandardIndex; index < jsStackSize; ++ index) {
2251         if (navPathList[index].second || !navigationStack_->IsFromRecovery(index)) {
2252             continue;
2253         }
2254         if (!GenerateUINodeByIndex(index - removeSize, navPathList[index].second)) {
2255             removeSize++;
2256             continue;
2257         }
2258         navigationStack_->SetFromRecovery(index, false);
2259         auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(
2260             NavigationGroupNode::GetNavDestinationNode(navPathList[index].second));
2261         navdestination->SetNeedAppearFromRecovery(true);
2262     }
2263     return removeSize;
2264 }
2265 
GenerateUINodeByIndex(int32_t index,RefPtr<UINode> & node)2266 bool NavigationPattern::GenerateUINodeByIndex(int32_t index, RefPtr<UINode>& node)
2267 {
2268     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2269     do {
2270         if (parentNode_.Upgrade() || !host) {
2271             break;
2272         }
2273         auto context = host->GetContext();
2274         // Avoid the loading problem of atomicservice on the home page
2275         if ((context && !context->GetInstallationFree()) || !context) {
2276             break;
2277         }
2278         RefPtr<UINode> parentCustomNode;
2279         auto curNode = host->GetParent();
2280         while (curNode) {
2281             auto curTag = curNode->GetTag();
2282             if (curTag == V2::JS_VIEW_ETS_TAG) {
2283                 parentCustomNode = curNode;
2284                 break;
2285             }
2286             curNode = curNode->GetParent();
2287         }
2288         auto pattern = host->GetPattern<NavigationPattern>();
2289         if (pattern && parentCustomNode) {
2290             pattern->SetParentCustomNode(parentCustomNode);
2291         }
2292     } while (false);
2293     bool isCreate = navigationStack_->CreateNodeByIndex(index, parentNode_, node);
2294     if (node) {
2295         node->SetFreeze(true, true);
2296     }
2297     auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
2298         NavigationGroupNode::GetNavDestinationNode(node));
2299     CHECK_NULL_RETURN(navDestinationNode, isCreate);
2300     auto onStart = [weakPattern = WeakClaim(this)]() {
2301         auto pattern = weakPattern.Upgrade();
2302         CHECK_NULL_VOID(pattern);
2303         pattern->OnStartOneTransitionAnimation();
2304     };
2305     auto onFinish = [weakPattern = WeakClaim(this)]() {
2306         auto pattern = weakPattern.Upgrade();
2307         CHECK_NULL_VOID(pattern);
2308         pattern->OnFinishOneTransitionAnimation();
2309     };
2310     navDestinationNode->SetOnStartTransitionAnimationCallback(std::move(onStart));
2311     navDestinationNode->SetOnFinishTransitionAnimationCallback(std::move(onFinish));
2312     // set navigation id
2313     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2314     auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestinationNode->GetPattern());
2315     if (navigationNode && navDestinationPattern) {
2316         navDestinationPattern->SetNavigationNode(navigationNode);
2317         navDestinationPattern->SetNavigationId(navigationNode->GetInspectorId().value_or(""));
2318     }
2319     auto eventHub = navDestinationNode->GetOrCreateEventHub<NavDestinationEventHub>();
2320     CHECK_NULL_RETURN(eventHub, isCreate);
2321     eventHub->FireOnWillAppear();
2322     return isCreate;
2323 }
2324 
InitDividerMouseEvent(const RefPtr<InputEventHub> & inputHub)2325 void NavigationPattern::InitDividerMouseEvent(const RefPtr<InputEventHub>& inputHub)
2326 {
2327     CHECK_NULL_VOID(inputHub);
2328     CHECK_NULL_VOID(!hoverEvent_);
2329 
2330     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
2331         auto pattern = weak.Upgrade();
2332         if (pattern) {
2333             pattern->OnHover(isHover);
2334         }
2335     };
2336     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
2337     inputHub->AddOnHoverEvent(hoverEvent_);
2338 }
2339 
HandleDragStart()2340 void NavigationPattern::HandleDragStart()
2341 {
2342     preNavBarWidth_ = realNavBarWidth_;
2343     if (!isDividerDraggable_) {
2344         return;
2345     }
2346     isInDividerDrag_ = true;
2347     if (!enableDragBar_) {
2348         SetMouseStyle(MouseFormat::RESIZE_LEFT_RIGHT);
2349     }
2350 }
2351 
HandleDragUpdate(float xOffset)2352 void NavigationPattern::HandleDragUpdate(float xOffset)
2353 {
2354     auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
2355     CHECK_NULL_VOID(navigationLayoutProperty);
2356     auto host = GetHost();
2357     CHECK_NULL_VOID(host);
2358     auto geometryNode = host->GetGeometryNode();
2359     CHECK_NULL_VOID(geometryNode);
2360     auto frameWidth = geometryNode->GetFrameSize().Width();
2361     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
2362     auto parentSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
2363     float minNavBarWidthPx = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
2364     float maxNavBarWidthPx = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
2365     float minContentWidthPx = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
2366     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
2367 
2368     auto navigationPosition = navigationLayoutProperty->GetNavBarPosition().value_or(NavBarPosition::START);
2369     bool isNavBarStart = navigationPosition == NavBarPosition::START;
2370     auto navBarLine = isRightToLeft_ ? preNavBarWidth_ + (isNavBarStart ? -xOffset : xOffset)
2371                                      : preNavBarWidth_ + (isNavBarStart ? xOffset : -xOffset);
2372 
2373     if (maxNavBarWidthPx + dividerWidth + minContentWidthPx > frameWidth) {
2374         maxNavBarWidthPx = frameWidth - minContentWidthPx - dividerWidth;
2375     }
2376     navBarLine = std::min(navBarLine, maxNavBarWidthPx);
2377 
2378     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
2379         if (minContentWidthPx >= frameWidth) {
2380             realNavBarWidth_ = 0.0f;
2381         } else if (navBarLine + dividerWidth + minContentWidthPx <= frameWidth) {
2382             realNavBarWidth_ = navBarLine;
2383         } else {
2384             realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
2385         }
2386     } else {
2387         realDividerWidth_ = dividerWidth;
2388         float remainingSpace = frameWidth - navBarLine - dividerWidth;
2389         if (remainingSpace >= minContentWidthPx) {
2390             realNavBarWidth_ = navBarLine;
2391         } else if (remainingSpace < minContentWidthPx && navBarLine > minNavBarWidthPx) {
2392             realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
2393         } else {
2394             realNavBarWidth_ = minNavBarWidthPx;
2395         }
2396     }
2397     realNavBarWidth_ = std::max(std::min(std::min(realNavBarWidth_, frameWidth), maxNavBarWidthPx), minNavBarWidthPx);
2398     SetNavigationWidthToolBarManager(
2399         realNavBarWidth_, frameWidth - realNavBarWidth_ - realDividerWidth_, realDividerWidth_);
2400     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
2401 }
2402 
HandleDragEnd()2403 void NavigationPattern::HandleDragEnd()
2404 {
2405     preNavBarWidth_ = realNavBarWidth_;
2406     if (!isDividerDraggable_) {
2407         return;
2408     }
2409     isInDividerDrag_ = false;
2410     SetMouseStyle(MouseFormat::DEFAULT);
2411 }
2412 
InitDividerPanEvent(const RefPtr<GestureEventHub> & gestureHub)2413 void NavigationPattern::InitDividerPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2414 {
2415     CHECK_NULL_VOID(!panEvent_);
2416     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2417         auto pattern = weak.Upgrade();
2418         CHECK_NULL_VOID(pattern);
2419         pattern->HandleDragStart();
2420     };
2421     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2422         auto pattern = weak.Upgrade();
2423         CHECK_NULL_VOID(pattern);
2424         pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
2425     };
2426     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2427         auto pattern = weak.Upgrade();
2428         CHECK_NULL_VOID(pattern);
2429         pattern->HandleDragEnd();
2430     };
2431     auto actionCancelTask = [weak = WeakClaim(this)]() {
2432         auto pattern = weak.Upgrade();
2433         CHECK_NULL_VOID(pattern);
2434         pattern->HandleDragEnd();
2435     };
2436     panEvent_ = MakeRefPtr<PanEvent>(
2437         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
2438     PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
2439     PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
2440         { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
2441     gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, distanceMap);
2442 }
2443 
InitDragBarPanEvent(const RefPtr<GestureEventHub> & gestureHub)2444 void NavigationPattern::InitDragBarPanEvent(const RefPtr<GestureEventHub>& gestureHub)
2445 {
2446     CHECK_NULL_VOID(!dragBarPanEvent_);
2447     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2448         auto pattern = weak.Upgrade();
2449         CHECK_NULL_VOID(pattern);
2450         pattern->HandleDragStart();
2451     };
2452     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2453         auto pattern = weak.Upgrade();
2454         CHECK_NULL_VOID(pattern);
2455         pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
2456     };
2457     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
2458         auto pattern = weak.Upgrade();
2459         CHECK_NULL_VOID(pattern);
2460         pattern->HandleDragEnd();
2461     };
2462     auto actionCancelTask = [weak = WeakClaim(this)]() {
2463         auto pattern = weak.Upgrade();
2464         CHECK_NULL_VOID(pattern);
2465         pattern->HandleDragEnd();
2466     };
2467     dragBarPanEvent_ = MakeRefPtr<PanEvent>(
2468         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
2469     PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
2470     PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
2471         { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
2472     gestureHub->AddPanEvent(dragBarPanEvent_, panDirection, DEFAULT_PAN_FINGER, distanceMap);
2473 }
2474 
OnHover(bool isHover)2475 void NavigationPattern::OnHover(bool isHover)
2476 {
2477     if (isInDividerDrag_) {
2478         return;
2479     }
2480     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
2481     CHECK_NULL_VOID(layoutProperty);
2482     auto userSetMinNavBarWidthValue = layoutProperty->GetMinNavBarWidthValue(Dimension(0.0));
2483     auto userSetMaxNavBarWidthValue = layoutProperty->GetMaxNavBarWidthValue(Dimension(0.0));
2484     bool navBarWidthRangeEqual = userSetMinNavBarWidthValue.Value() >= userSetMaxNavBarWidthValue.Value();
2485     if ((userSetNavBarWidthFlag_ && !userSetNavBarRangeFlag_) || (userSetNavBarRangeFlag_ && navBarWidthRangeEqual)) {
2486         isDividerDraggable_ = false;
2487         return;
2488     }
2489     isDividerDraggable_ = true;
2490     MouseFormat format = isHover ? MouseFormat::RESIZE_LEFT_RIGHT : MouseFormat::DEFAULT;
2491     SetMouseStyle(format);
2492 }
2493 
GetNavigationNode() const2494 RefPtr<FrameNode> NavigationPattern::GetNavigationNode() const
2495 {
2496     auto host = GetHost();
2497     CHECK_NULL_RETURN(host, nullptr);
2498     auto navigationNode = AceType::DynamicCast<FrameNode>(host);
2499     CHECK_NULL_RETURN(navigationNode, nullptr);
2500     return host;
2501 }
2502 
GetNavBarNode() const2503 RefPtr<FrameNode> NavigationPattern::GetNavBarNode() const
2504 {
2505     auto host = GetHost();
2506     CHECK_NULL_RETURN(host, nullptr);
2507     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
2508     CHECK_NULL_RETURN(navigationNode, nullptr);
2509     auto frameNode = AceType::DynamicCast<FrameNode>(navigationNode->GetNavBarNode());
2510     CHECK_NULL_RETURN(frameNode, nullptr);
2511     return frameNode;
2512 }
2513 
GetNavBarNodeOrHomeDestination() const2514 RefPtr<FrameNode> NavigationPattern::GetNavBarNodeOrHomeDestination() const
2515 {
2516     auto host = GetHost();
2517     CHECK_NULL_RETURN(host, nullptr);
2518     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
2519     CHECK_NULL_RETURN(navigationNode, nullptr);
2520     return AceType::DynamicCast<FrameNode>(navigationNode->GetNavBarOrHomeDestinationNode());
2521 }
2522 
GetContentNode() const2523 RefPtr<FrameNode> NavigationPattern::GetContentNode() const
2524 {
2525     auto host = GetHost();
2526     CHECK_NULL_RETURN(host, nullptr);
2527     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
2528     CHECK_NULL_RETURN(navigationNode, nullptr);
2529     auto frameNode = AceType::DynamicCast<FrameNode>(navigationNode->GetContentNode());
2530     CHECK_NULL_RETURN(frameNode, nullptr);
2531     return frameNode;
2532 }
2533 
GetDividerNode() const2534 RefPtr<FrameNode> NavigationPattern::GetDividerNode() const
2535 {
2536     auto host = GetHost();
2537     CHECK_NULL_RETURN(host, nullptr);
2538     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
2539     CHECK_NULL_RETURN(navigationNode, nullptr);
2540     auto dividerFrameNode = AceType::DynamicCast<FrameNode>(navigationNode->GetDividerNode());
2541     CHECK_NULL_RETURN(dividerFrameNode, nullptr);
2542     return dividerFrameNode;
2543 }
2544 
GetDragBarNode() const2545 RefPtr<FrameNode> NavigationPattern::GetDragBarNode() const
2546 {
2547     auto host = GetHost();
2548     CHECK_NULL_RETURN(host, nullptr);
2549     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
2550     CHECK_NULL_RETURN(navigationNode, nullptr);
2551     auto dragBarNode = AceType::DynamicCast<FrameNode>(navigationNode->GetDragBarNode());
2552     CHECK_NULL_RETURN(dragBarNode, nullptr);
2553     return dragBarNode;
2554 }
2555 
BeforeSyncGeometryProperties(const DirtySwapConfig &)2556 void NavigationPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& /* config */)
2557 {
2558     AddDividerHotZoneRect();
2559 }
2560 
AddDividerHotZoneRect()2561 void NavigationPattern::AddDividerHotZoneRect()
2562 {
2563     if (NearZero(realDividerWidth_)) {
2564         return;
2565     }
2566     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2567     CHECK_NULL_VOID(hostNode);
2568     auto navBarOrHomeDestNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
2569     CHECK_NULL_VOID(navBarOrHomeDestNode);
2570     auto geometryNode = navBarOrHomeDestNode->GetGeometryNode();
2571     CHECK_NULL_VOID(geometryNode);
2572 
2573     OffsetF hotZoneOffset;
2574     hotZoneOffset.SetX(-DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
2575     hotZoneOffset.SetY(DEFAULT_DIVIDER_START_MARGIN.ConvertToPx());
2576     SizeF hotZoneSize;
2577     hotZoneSize.SetWidth(realDividerWidth_ + DIVIDER_HOT_ZONE_HORIZONTAL_PADDING_NUM *
2578                                                  DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
2579     hotZoneSize.SetHeight(geometryNode->GetFrameSize().Height());
2580     DimensionRect hotZoneRegion;
2581     auto paintHeight = GetPaintRectHeight(navBarOrHomeDestNode);
2582     if (navigationMode_ == NavigationMode::STACK || enableDragBar_) {
2583         hotZoneRegion.SetSize(DimensionSize(Dimension(0.0f), Dimension(0.0f)));
2584     } else {
2585         hotZoneRegion.SetSize(DimensionSize(
2586             Dimension(hotZoneSize.Width()), Dimension(NearZero(paintHeight) ? hotZoneSize.Height() : paintHeight)));
2587     }
2588     hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset.GetX()), Dimension(hotZoneOffset.GetY())));
2589 
2590     std::vector<DimensionRect> mouseRegion;
2591     mouseRegion.emplace_back(hotZoneRegion);
2592 
2593     auto dividerFrameNode = GetDividerNode();
2594     CHECK_NULL_VOID(dividerFrameNode);
2595     auto dividerGestureHub = dividerFrameNode->GetOrCreateGestureEventHub();
2596     CHECK_NULL_VOID(dividerGestureHub);
2597     dividerGestureHub->SetMouseResponseRegion(mouseRegion);
2598 
2599     auto dragRectOffset = geometryNode->GetMarginFrameOffset();
2600     dragRectOffset.SetX(-DEFAULT_DRAG_REGION.ConvertToPx());
2601     dragRect_.SetOffset(dragRectOffset);
2602     if (navigationMode_ == NavigationMode::STACK || enableDragBar_) {
2603         dragRect_.SetSize(SizeF(0.0f, 0.0f));
2604     } else {
2605         dragRect_.SetSize(SizeF(DEFAULT_DRAG_REGION.ConvertToPx() * DEFAULT_HALF + realDividerWidth_,
2606             NearZero(paintHeight) ? geometryNode->GetFrameSize().Height() : paintHeight));
2607     }
2608 
2609     std::vector<DimensionRect> responseRegion;
2610     DimensionOffset responseOffset(dragRectOffset);
2611     DimensionRect responseRect(Dimension(dragRect_.Width(), DimensionUnit::PX),
2612         Dimension(dragRect_.Height(), DimensionUnit::PX), responseOffset);
2613     responseRegion.emplace_back(responseRect);
2614     dividerGestureHub->SetResponseRegion(responseRegion);
2615 }
2616 
AddDragBarHotZoneRect()2617 void NavigationPattern::AddDragBarHotZoneRect()
2618 {
2619     if (NearZero(realDividerWidth_)) {
2620         return;
2621     }
2622     auto dargBarNode = GetDragBarNode();
2623     CHECK_NULL_VOID(dargBarNode);
2624     auto geometryNode = dargBarNode->GetGeometryNode();
2625     CHECK_NULL_VOID(geometryNode);
2626     auto dragBarGestureHub = dargBarNode->GetOrCreateGestureEventHub();
2627     CHECK_NULL_VOID(dragBarGestureHub);
2628 
2629     auto dragRectOffset = geometryNode->GetMarginFrameOffset();
2630     dragRectOffset.SetX(-DEFAULT_DRAG_BAR_HOT_ZONE.ConvertToPx());
2631     dragRectOffset.SetY(0.0f);
2632     dragBarRect_.SetOffset(dragRectOffset);
2633     if (navigationMode_ == NavigationMode::STACK) {
2634         dragBarRect_.SetSize(SizeF(0.0f, 0.0f));
2635     } else {
2636         dragBarRect_.SetSize(SizeF(DEFAULT_DRAG_BAR_HOT_ZONE.ConvertToPx() * DEFAULT_HALF +
2637             geometryNode->GetFrameSize().Width(), geometryNode->GetFrameSize().Height()));
2638     }
2639     std::vector<DimensionRect> responseRegion;
2640     DimensionOffset responseOffset(dragRectOffset);
2641     DimensionRect responseRect(Dimension(dragBarRect_.Width(), DimensionUnit::PX),
2642         Dimension(dragBarRect_.Height(), DimensionUnit::PX), responseOffset);
2643     responseRegion.emplace_back(responseRect);
2644     dragBarGestureHub->SetResponseRegion(responseRegion);
2645 }
2646 
NotifyDialogChange(NavDestinationLifecycle lifecycle,bool isFromStandardIndex)2647 void NavigationPattern::NotifyDialogChange(NavDestinationLifecycle lifecycle, bool isFromStandardIndex)
2648 {
2649     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2650     CHECK_NULL_VOID(hostNode);
2651     const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
2652     int32_t lastStandardIndex = hostNode->GetLastStandardIndex();
2653     int32_t standardIndex = lastStandardIndex >= 0 ? lastStandardIndex : 0;
2654     int32_t start = isFromStandardIndex ? standardIndex : 0;
2655     int32_t end = isFromStandardIndex ? navigationStack_->Size() : standardIndex;
2656     bool isShow = (lifecycle == NavDestinationLifecycle::ON_SHOW)
2657         || (lifecycle == NavDestinationLifecycle::ON_WILL_SHOW);
2658     if (isShow) {
2659         for (int32_t index = start; index < end; index++) {
2660             NotifyDestinationLifecycle(navDestinationNodes[index].second, lifecycle);
2661         }
2662     } else {
2663         for (int32_t index = end - 1; index >= 0 && index >= start; index--) {
2664             NotifyDestinationLifecycle(navDestinationNodes[index].second, lifecycle);
2665         }
2666     }
2667 }
2668 
DumpInfo()2669 void NavigationPattern::DumpInfo()
2670 {
2671     if (!navigationStack_) {
2672         return;
2673     }
2674     DumpLog::GetInstance().AddDesc(std::string("size").append(std::to_string(navigationStack_->Size())));
2675 }
2676 
TriggerCustomAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,RefPtr<NavDestinationGroupNode> newTopNavDestination,bool isPopPage)2677 bool NavigationPattern::TriggerCustomAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,
2678     RefPtr<NavDestinationGroupNode> newTopNavDestination, bool isPopPage)
2679 {
2680     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "will trigger navigation custom animation");
2681     if ((!preTopNavDestination && !newTopNavDestination) || !onTransition_) {
2682         return false;
2683     }
2684     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2685     CHECK_NULL_RETURN(hostNode, false);
2686     hostNode->SetIsOnAnimation(true);
2687     if (!newTopNavDestination) {
2688         // pop animation with top navDestination, recover navBar visible tag
2689         hostNode->SetNeedSetInvisible(false);
2690     }
2691     auto proxy = AceType::MakeRefPtr<NavigationTransitionProxy>();
2692     auto homeDestination = AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavBarOrHomeDestinationNode());
2693     proxy->SetPreDestination(preTopNavDestination ? preTopNavDestination : homeDestination);
2694     proxy->SetTopDestination(newTopNavDestination ? newTopNavDestination : homeDestination);
2695     auto proxyId = proxy->GetProxyId();
2696     proxyList_.emplace_back(proxy);
2697     auto navigationTransition = ExecuteTransition(preTopNavDestination, newTopNavDestination, isPopPage);
2698     if (!navigationTransition.isValid) {
2699         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom transition value is invalid, do default animation");
2700         return false;
2701     }
2702     ExecuteAddAnimation(preTopNavDestination, newTopNavDestination, isPopPage, proxy, navigationTransition);
2703     ACE_SCOPED_TRACE_COMMERCIAL("Navigation page custom transition start");
2704     if (navigationTransition.interactive) {
2705         PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH_INTERACTIVE,
2706             PerfActionType::FIRST_MOVE, "");
2707         std::function<void()> onFinish = [weakNavigation = WeakClaim(this),
2708                                   weakPreNavDestination = WeakPtr<NavDestinationGroupNode>(preTopNavDestination),
2709                                   weakNewNavDestination = WeakPtr<NavDestinationGroupNode>(newTopNavDestination),
2710                                   isPopPage, proxyId]() {
2711             auto pattern = weakNavigation.Upgrade();
2712             CHECK_NULL_VOID(pattern);
2713             auto proxy = pattern->GetProxyById(proxyId);
2714             if (proxy == nullptr) {
2715                 return;
2716             }
2717             if (!proxy->GetInteractive()) {
2718                 pattern->RemoveProxyById(proxyId);
2719                 return;
2720             }
2721             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "interactive animation is finish: %{public}d", proxy->GetIsSuccess());
2722             pattern->isFinishInteractiveAnimation_ = true;
2723             auto preDestination = weakPreNavDestination.Upgrade();
2724             auto topDestination = weakNewNavDestination.Upgrade();
2725             proxy->SetIsFinished(true);
2726             // this flag will be update in cancelTransition or finishTransition
2727             ACE_SCOPED_TRACE_COMMERCIAL("navigation page custom transition end");
2728             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH_INTERACTIVE, true);
2729             if (proxy->GetIsSuccess()) {
2730                 pattern->ClearRecoveryList();
2731                 pattern->OnCustomAnimationFinish(preDestination, topDestination, isPopPage);
2732             } else {
2733                 // fire page cancel transition
2734                 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "interactive animation canceled");
2735                 pattern->RecoveryToLastStack(preDestination, topDestination);
2736                 pattern->SyncWithJsStackIfNeeded();
2737             }
2738             proxy->FireEndCallback();
2739             pattern->RemoveProxyById(proxyId);
2740         };
2741         auto finishCallback = [onFinishCb = std::move(onFinish), weakNavigation = WeakClaim(this)]() {
2742             auto pattern = weakNavigation.Upgrade();
2743             if (onFinishCb) {
2744                 onFinishCb();
2745             }
2746             CHECK_NULL_VOID(pattern);
2747             pattern->OnFinishOneTransitionAnimation();
2748         };
2749         auto pipelineContext = hostNode->GetContext();
2750         CHECK_NULL_RETURN(pipelineContext, false);
2751         auto navigationManager = pipelineContext->GetNavigationManager();
2752         CHECK_NULL_RETURN(navigationManager, false);
2753         navigationManager->SetInteractive(hostNode->GetId());
2754         proxy->SetInteractiveAnimation(AnimationUtils::CreateInteractiveAnimation(
2755             nullptr, finishCallback), finishCallback);
2756         navigationTransition.transition(proxy);
2757         isFinishInteractiveAnimation_ = false;
2758         navigationManager->FinishInteractiveAnimation();
2759         OnStartOneTransitionAnimation();
2760         proxy->StartAnimation();
2761     } else {
2762         PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
2763         ClearRecoveryList();
2764         OnStartOneTransitionAnimation();
2765         navigationTransition.transition(proxy);
2766         // enable render group for text node during custom animation to reduce
2767         // unnecessary redrawing
2768         if (isPopPage && preTopNavDestination) {
2769             preTopNavDestination->UpdateTextNodeListAsRenderGroup(isPopPage, proxy);
2770         }
2771         if (!isPopPage && newTopNavDestination) {
2772             newTopNavDestination->UpdateTextNodeListAsRenderGroup(isPopPage, proxy);
2773         }
2774     }
2775 
2776     RefPtr<EventHub> eventHub;
2777     if (!preTopNavDestination && navigationMode_ == NavigationMode::STACK) {
2778         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2779         CHECK_NULL_RETURN(hostNode, true);
2780         auto navBarOrHomeDestNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
2781         CHECK_NULL_RETURN(navBarOrHomeDestNode, true);
2782         eventHub = navBarOrHomeDestNode->GetOrCreateEventHub<EventHub>();
2783     }
2784     if (preTopNavDestination) {
2785         eventHub = preTopNavDestination->GetOrCreateEventHub<EventHub>();
2786     }
2787     CHECK_NULL_RETURN(eventHub, true);
2788     eventHub->SetEnabledInternal(false);
2789     return true;
2790 }
2791 
OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2792 void NavigationPattern::OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
2793     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2794 {
2795     // preTopNavDestination or newTopNavDestination maybe is HomeNavDestination!!!
2796     if (!preTopNavDestination && !newTopNavDestination) {
2797         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "preDestination and topDestination is invalid");
2798         return;
2799     }
2800     ACE_SCOPED_TRACE_COMMERCIAL("Navigation page custom transition end");
2801     PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
2802     auto replaceValue = navigationStack_->GetReplaceValue();
2803     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2804     CHECK_NULL_VOID(hostNode);
2805     auto homeDest = AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetHomeDestinationNode());
2806     bool preIsHomeDest = homeDest && preTopNavDestination == homeDest;
2807     hostNode->SetIsOnAnimation(false);
2808     auto id = hostNode->GetTopDestination() ? hostNode->GetTopDestination()->GetAccessibilityId() : -1;
2809     hostNode->OnAccessibilityEvent(
2810         AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
2811     do {
2812         if (replaceValue != 0) {
2813             if (preTopNavDestination) {
2814                 preTopNavDestination->SetIsOnAnimation(false);
2815             }
2816             if (newTopNavDestination) {
2817                 newTopNavDestination->SetIsOnAnimation(false);
2818             }
2819             hostNode->DealNavigationExit(preTopNavDestination, (preTopNavDestination == nullptr || preIsHomeDest));
2820             navigationStack_->UpdateReplaceValue(0);
2821             break;
2822         }
2823         if ((newTopNavDestination && preTopNavDestination && isPopPage) ||
2824             (preTopNavDestination && !newTopNavDestination)) {
2825             PageTransitionType preNodeTransitionType = preTopNavDestination->GetTransitionType();
2826             if (preNodeTransitionType != PageTransitionType::EXIT_POP) {
2827                 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
2828                 return;
2829             }
2830             preTopNavDestination->SetIsOnAnimation(false);
2831             if (newTopNavDestination && newTopNavDestination->GetTransitionType() == PageTransitionType::ENTER_POP) {
2832                 newTopNavDestination->SetIsOnAnimation(false);
2833             }
2834             auto preDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
2835             CHECK_NULL_VOID(preDestinationPattern);
2836             auto shallowBuilder = preDestinationPattern->GetShallowBuilder();
2837             if (shallowBuilder && !preIsHomeDest) {
2838                 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
2839             }
2840             if (!preIsHomeDest) {
2841                 auto parent = preTopNavDestination->GetParent();
2842                 CHECK_NULL_VOID(parent);
2843                 parent->RemoveChild(preTopNavDestination);
2844                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2845             }
2846             break;
2847         }
2848         if ((newTopNavDestination && preTopNavDestination && !isPopPage) ||
2849             (!preTopNavDestination && newTopNavDestination && navigationMode_ == NavigationMode::STACK)) {
2850             hostNode->SetNeedSetInvisible(true);
2851             RefPtr<FrameNode> node;
2852             PageTransitionType preNodeTransitionType;
2853             if (preTopNavDestination) {
2854                 preNodeTransitionType = preTopNavDestination->GetTransitionType();
2855                 node = preTopNavDestination;
2856             } else {
2857                 // pre destination is nullptr, preNode is navBarNode or HomeDestination
2858                 auto navBarOrHomeDestNode =
2859                     AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
2860                 CHECK_NULL_VOID(navBarOrHomeDestNode);
2861                 preNodeTransitionType = navBarOrHomeDestNode->GetTransitionType();
2862                 node = navBarOrHomeDestNode;
2863                 CHECK_NULL_VOID(node);
2864             }
2865             if (newTopNavDestination && newTopNavDestination->GetTransitionType() == PageTransitionType::ENTER_PUSH) {
2866                 newTopNavDestination->SetIsOnAnimation(false);
2867             }
2868             if (preNodeTransitionType != PageTransitionType::EXIT_PUSH) {
2869                 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
2870                 return;
2871             }
2872             if (preTopNavDestination) {
2873                 preTopNavDestination->SetIsOnAnimation(false);
2874             }
2875             // recover event hub
2876             auto eventHub = node->GetOrCreateEventHub<EventHub>();
2877             if (eventHub) {
2878                 eventHub->SetEnabledInternal(true);
2879             }
2880             bool isDialog = newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG;
2881             if (isDialog) {
2882                 return;
2883             }
2884             if (preIsHomeDest && navigationMode_ == NavigationMode::SPLIT) {
2885                 return;
2886             }
2887             auto property = node->GetLayoutProperty();
2888             property->UpdateVisibility(VisibleType::INVISIBLE);
2889             node->SetJSViewActive(false);
2890             if (!preTopNavDestination) {
2891                 hostNode->NotifyPageHide();
2892             }
2893         }
2894     } while (0);
2895     hostNode->RemoveDialogDestination();
2896     auto context = PipelineContext::GetCurrentContext();
2897     CHECK_NULL_VOID(context);
2898     context->MarkNeedFlushMouseEvent();
2899 }
2900 
ExecuteTransition(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)2901 NavigationTransition NavigationPattern::ExecuteTransition(const RefPtr<NavDestinationGroupNode>& preTopDestination,
2902     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
2903 {
2904     NavigationTransition navigationTransition;
2905     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2906     CHECK_NULL_RETURN(hostNode, navigationTransition);
2907     NavigationOperation operation;
2908     auto currentProxy = GetTopNavigationProxy();
2909     auto preInfo = currentProxy->GetPreDestinationContext();
2910     auto topInfo = currentProxy->GetTopDestinationContext();
2911     auto replaceValue = navigationStack_->GetReplaceValue();
2912     RefPtr<NavDestinationGroupNode> realPreTopDest = nullptr;
2913     RefPtr<NavDestinationGroupNode> realNewTopDest = nullptr;
2914     if (replaceValue != 0) {
2915         operation = NavigationOperation::REPLACE;
2916     } else if (!preTopDestination) {
2917         operation = NavigationOperation::PUSH;
2918         // if animated with navBarNode/HomeDestination, recover navBar/HomeDestination visibility
2919         hostNode->SetNeedSetInvisible(false);
2920     } else {
2921         operation = (!newTopNavDestination || isPopPage) ? NavigationOperation::POP : NavigationOperation::PUSH;
2922     }
2923     /* set transition animation flag fro navBarNode or navDestinationNode */
2924     if (operation == NavigationOperation::PUSH) {
2925         if (preTopDestination != nullptr) {
2926             preTopDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
2927             realPreTopDest = preTopDestination;
2928         } else {
2929             // preTopDestination is nullptr, previous node is navBar or HomeDestination
2930             auto navBarOrHomeDestNode =
2931                 AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
2932             CHECK_NULL_RETURN(navBarOrHomeDestNode, navigationTransition);
2933             navBarOrHomeDestNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
2934             realPreTopDest = AceType::DynamicCast<NavDestinationGroupNode>(navBarOrHomeDestNode);
2935         }
2936         if (newTopNavDestination != nullptr) {
2937             newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
2938             realNewTopDest = newTopNavDestination;
2939         }
2940     }
2941     if (operation == NavigationOperation::POP) {
2942         if (preTopDestination != nullptr) {
2943             preTopDestination->SetTransitionType(PageTransitionType::EXIT_POP);
2944             realPreTopDest = preTopDestination;
2945         }
2946         if (newTopNavDestination != nullptr) {
2947             newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
2948             realNewTopDest = newTopNavDestination;
2949         } else {
2950             // newTopNavDestination is nullptr, current node is navBar or HomeDestination
2951             auto navBarOrHomeDestNode =
2952                 AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
2953             CHECK_NULL_RETURN(navBarOrHomeDestNode, navigationTransition);
2954             navBarOrHomeDestNode->SetTransitionType(PageTransitionType::ENTER_POP);
2955             realNewTopDest = AceType::DynamicCast<NavDestinationGroupNode>(navBarOrHomeDestNode);
2956         }
2957     }
2958     LogCustomAnimationStart(realPreTopDest, realNewTopDest, operation);
2959     return onTransition_(preInfo, topInfo, operation);
2960 }
2961 
OnColorConfigurationUpdate()2962 void NavigationPattern::OnColorConfigurationUpdate()
2963 {
2964     UpdateDividerBackgroundColor();
2965 
2966     auto dragBarNode = GetDragBarNode();
2967     CHECK_NULL_VOID(dragBarNode);
2968     auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
2969     CHECK_NULL_VOID(dragPattern);
2970     dragPattern->UpdateDefaultColor();
2971 }
2972 
UpdateDividerBackgroundColor()2973 void NavigationPattern::UpdateDividerBackgroundColor()
2974 {
2975     auto navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2976     CHECK_NULL_VOID(navigationGroupNode);
2977     auto dividerNode = GetDividerNode();
2978     CHECK_NULL_VOID(dividerNode);
2979     auto theme = NavigationGetTheme(navigationGroupNode->GetThemeScopeId());
2980     CHECK_NULL_VOID(theme);
2981     dividerNode->GetRenderContext()->UpdateBackgroundColor(theme->GetNavigationDividerColor());
2982     dividerNode->MarkDirtyNode();
2983 }
2984 
UpdateToobarFocusColor()2985 void NavigationPattern::UpdateToobarFocusColor()
2986 {
2987     auto navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
2988     CHECK_NULL_VOID(navigationGroupNode);
2989     auto navBarOrHomeDestNode =
2990         AceType::DynamicCast<NavDestinationNodeBase>(navigationGroupNode->GetNavBarOrHomeDestinationNode());
2991     CHECK_NULL_VOID(navBarOrHomeDestNode);
2992     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(navBarOrHomeDestNode->GetPreToolBarNode());
2993     CHECK_NULL_VOID(toolBarNode);
2994     auto containerNode = AceType::DynamicCast<FrameNode>(toolBarNode->GetToolbarContainerNode());
2995     CHECK_NULL_VOID(containerNode);
2996     auto toolBarItemNodes = containerNode->GetChildren();
2997     auto theme = NavigationGetTheme(navigationGroupNode->GetThemeScopeId());
2998     CHECK_NULL_VOID(theme);
2999     for (auto& toolBarItemNode : toolBarItemNodes) {
3000         auto buttonNode = AceType::DynamicCast<FrameNode>(toolBarItemNode);
3001         CHECK_NULL_VOID(buttonNode);
3002         auto buttonPattern = AceType::DynamicCast<ButtonPattern>(buttonNode->GetPattern());
3003         CHECK_NULL_VOID(buttonPattern);
3004         buttonPattern->SetFocusBorderColor(theme->GetToolBarItemFocusColor());
3005         auto focusHub = buttonNode->GetFocusHub();
3006         CHECK_NULL_VOID(focusHub);
3007         focusHub->SetPaintColor(theme->GetToolBarItemFocusColor());
3008     }
3009 }
3010 
OnThemeScopeUpdate(int32_t themeScopeId)3011 bool NavigationPattern::OnThemeScopeUpdate(int32_t themeScopeId)
3012 {
3013     auto navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3014     CHECK_NULL_RETURN(navigationGroupNode, false);
3015     auto navBarOrHomeDestNode =
3016         AceType::DynamicCast<NavDestinationNodeBase>(navigationGroupNode->GetNavBarOrHomeDestinationNode());
3017     CHECK_NULL_RETURN(navBarOrHomeDestNode, false);
3018 
3019     auto dividerNode = AceType::DynamicCast<FrameNode>(navBarOrHomeDestNode->GetToolBarDividerNode());
3020     CHECK_NULL_RETURN(dividerNode, false);
3021 
3022     auto theme = NavigationGetTheme(themeScopeId);
3023     CHECK_NULL_RETURN(theme, false);
3024 
3025     auto dividerRenderProperty = dividerNode->GetPaintProperty<DividerRenderProperty>();
3026     CHECK_NULL_RETURN(dividerRenderProperty, false);
3027     dividerRenderProperty->UpdateDividerColor(theme->GetToolBarDividerColor());
3028 
3029     navigationGroupNode->MarkModifyDone();
3030     return false;
3031 }
3032 
UpdatePreNavDesZIndex(const RefPtr<FrameNode> & preTopNavDestination,const RefPtr<FrameNode> & newTopNavDestination,int32_t preLastStandardIndex)3033 void NavigationPattern::UpdatePreNavDesZIndex(const RefPtr<FrameNode> &preTopNavDestination,
3034     const RefPtr<FrameNode> &newTopNavDestination, int32_t preLastStandardIndex)
3035 {
3036     auto replaceVal = navigationStack_->GetReplaceValue();
3037     if (replaceVal != 0 && preTopNavDestination && newTopNavDestination) {
3038         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3039         CHECK_NULL_VOID(hostNode);
3040         auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
3041         CHECK_NULL_VOID(navigationContentNode);
3042         auto newDesNodeContext = newTopNavDestination->GetRenderContext();
3043         CHECK_NULL_VOID(newDesNodeContext);
3044         std::optional<int32_t> newNodeZIndex = newDesNodeContext->GetZIndex();
3045         int32_t standardIndex = newNodeZIndex.value_or(0) - 1;
3046         auto hideNodes = hostNode->GetHideNodes();
3047         for (auto iter = hideNodes.begin(); iter != hideNodes.end(); ++iter) {
3048             // if navdestination nodes is not need removed, default zIndex is satisfied, don't need change
3049             if (!iter->second) {
3050                 continue;
3051             }
3052             auto navDestination = iter->first;
3053             if (!navDestination) {
3054                 continue;
3055             }
3056             auto navDestinationContext = navDestination->GetRenderContext();
3057             if (!navDestinationContext) {
3058                 continue;
3059             }
3060             // get navDestination index in hideNodes, use navdestination index in pre navigation stack
3061             int32_t hideNodesIndex =
3062                 static_cast<int32_t>(hideNodes.size()) - (navDestination->GetIndex() - preLastStandardIndex);
3063             navDestinationContext->UpdateZIndex(standardIndex - hideNodesIndex);
3064         }
3065         auto preDesNodeContext = preTopNavDestination->GetRenderContext();
3066         CHECK_NULL_VOID(preDesNodeContext);
3067         preDesNodeContext->UpdateZIndex(standardIndex);
3068         navigationContentNode->RebuildRenderContextTree();
3069         auto context = PipelineContext::GetCurrentContext();
3070         CHECK_NULL_VOID(context);
3071         context->RequestFrame();
3072     }
3073 }
3074 
SetNavigationStack(const RefPtr<NavigationStack> & navigationStack)3075 void NavigationPattern::SetNavigationStack(const RefPtr<NavigationStack>& navigationStack)
3076 {
3077     if (navigationStack_) {
3078         navigationStack_->SetOnStateChangedCallback(nullptr);
3079     }
3080     navigationStack_ = navigationStack;
3081     if (navigationStack_) {
3082         navigationStack_->SetNavigationNode(GetHost());
3083         WeakPtr<NavigationPattern> weakPattern = WeakClaim(this);
3084         auto id = Container::CurrentId();
3085         auto callback = [weakPattern, id]() {
3086             ContainerScope scope(id);
3087             auto pattern = weakPattern.Upgrade();
3088             CHECK_NULL_VOID(pattern);
3089             if (pattern->NeedSyncWithJsStackMarked()) {
3090                 return;
3091             }
3092             pattern->MarkNeedSyncWithJsStack();
3093             auto context = PipelineContext::GetCurrentContext();
3094             CHECK_NULL_VOID(context);
3095             context->AddBuildFinishCallBack([weakPattern]() {
3096                 auto pattern = weakPattern.Upgrade();
3097                 CHECK_NULL_VOID(pattern);
3098                 pattern->SyncWithJsStackIfNeeded();
3099                 auto host = pattern->GetHost();
3100                 CHECK_NULL_VOID(host);
3101                 host->MarkDirtyNode();
3102             });
3103             context->RequestFrame();
3104         };
3105         navigationStack_->SetOnStateChangedCallback(callback);
3106     }
3107 }
3108 
GetParentNavigationPattern()3109 RefPtr<NavigationPattern> NavigationPattern::GetParentNavigationPattern()
3110 {
3111     RefPtr<UINode> node = GetHost();
3112     CHECK_NULL_RETURN(node, nullptr);
3113     node = node->GetParent();
3114     while (node) {
3115         if (node->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
3116             break;
3117         }
3118         node = node->GetParent();
3119     }
3120     auto groupNode = AceType::DynamicCast<NavigationGroupNode>(node);
3121     CHECK_NULL_RETURN(groupNode, nullptr);
3122     return AceType::DynamicCast<NavigationPattern>(groupNode->GetPattern());
3123 }
3124 
AttachNavigationStackToParent()3125 void NavigationPattern::AttachNavigationStackToParent()
3126 {
3127     CHECK_NULL_VOID(navigationStack_);
3128     auto parentPattern = GetParentNavigationPattern();
3129     CHECK_NULL_VOID(parentPattern);
3130     auto parentStack = parentPattern->GetNavigationStack();
3131     if (parentStack) {
3132         navigationStack_->OnAttachToParent(parentStack);
3133     }
3134 }
3135 
DetachNavigationStackFromParent()3136 void NavigationPattern::DetachNavigationStackFromParent()
3137 {
3138     if (navigationStack_) {
3139         navigationStack_->OnDetachFromParent();
3140     }
3141 }
3142 
DealTransitionVisibility(const RefPtr<FrameNode> & node,bool isVisible,bool isNavBar)3143 void NavigationPattern::DealTransitionVisibility(const RefPtr<FrameNode>& node, bool isVisible, bool isNavBar)
3144 {
3145     auto renderContext = node->GetRenderContext();
3146     if (!renderContext->HasDisappearTransition()) {
3147         auto layoutProperty = node->GetLayoutProperty();
3148         layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
3149         node->SetJSViewActive(isVisible);
3150         return;
3151     }
3152     auto layoutProperty = node->GetLayoutProperty();
3153     layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE, true);
3154     renderContext->SetTransitionOutCallback([
3155         weakNode = WeakPtr<FrameNode>(node), isVisible] {
3156         auto curNode = weakNode.Upgrade();
3157         CHECK_NULL_VOID(curNode);
3158         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
3159         if (nodeBase && nodeBase->GetTransitionType() != PageTransitionType::EXIT_PUSH) {
3160             return;
3161         }
3162         curNode->SetJSViewActive(isVisible);
3163     });
3164 }
3165 
AddToDumpManager()3166 void NavigationPattern::AddToDumpManager()
3167 {
3168     auto node = GetHost();
3169     auto context = PipelineContext::GetCurrentContext();
3170     if (!node || !context) {
3171         return;
3172     }
3173     auto mgr = context->GetNavigationManager();
3174     if (!mgr) {
3175         return;
3176     }
3177     auto callback = [weakPattern = WeakClaim(this)](int depth) {
3178         auto pattern = weakPattern.Upgrade();
3179         if (!pattern) {
3180             return;
3181         }
3182         const auto& stack = pattern->GetNavigationStack();
3183         if (!stack) {
3184             return;
3185         }
3186         auto infos = stack->DumpStackInfo();
3187     };
3188     mgr->AddNavigationDumpCallback(node, callback);
3189 }
3190 
RemoveFromDumpManager()3191 void NavigationPattern::RemoveFromDumpManager()
3192 {
3193     auto node = GetHost();
3194     auto context = PipelineContext::GetCurrentContext();
3195     if (!node || !context) {
3196         return;
3197     }
3198     auto mgr = context->GetNavigationManager();
3199     if (mgr) {
3200         mgr->RemoveNavigationDumpCallback(node->GetId(), node->GetDepth());
3201     }
3202 }
3203 
FireInterceptionEvent(bool isBefore,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopPath)3204 void NavigationPattern::FireInterceptionEvent(bool isBefore,
3205     const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopPath)
3206 {
3207     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3208     CHECK_NULL_VOID(hostNode);
3209     RefPtr<NavDestinationContext> to;
3210     if (newTopPath.has_value()) {
3211         auto topDestination =
3212             AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavDestinationNode(newTopPath->second));
3213         if (topDestination) {
3214             auto pattern = AceType::DynamicCast<NavDestinationPattern>(topDestination->GetPattern());
3215             to = pattern->GetNavDestinationContext();
3216         }
3217     }
3218     NavigationOperation operation;
3219     if (isReplace_ != 0) {
3220         operation = NavigationOperation::REPLACE;
3221     } else {
3222         operation = lastPreIndex_ == -1 ? NavigationOperation::POP : NavigationOperation::PUSH;
3223     }
3224     auto layoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
3225     // mode is split and stack size is one,don't need to do animation.
3226     if ((layoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO) == NavigationMode::SPLIT
3227         || navigationMode_ == NavigationMode::SPLIT) && !preContext_) {
3228         isAnimated_ = false;
3229     }
3230     navigationStack_->FireNavigationInterception(isBefore, preContext_, to, operation,
3231         isAnimated_);
3232 
3233     if (!isBefore) {
3234         NotifyNavDestinationSwitch(preContext_, to, operation);
3235     }
3236 }
3237 
UpdateIsAnimation(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath)3238 void NavigationPattern::UpdateIsAnimation(const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath)
3239 {
3240     auto disAbleAnimation = navigationStack_->GetDisableAnimation();
3241     auto animated = navigationStack_->GetAnimatedValue();
3242     // current animation flag is false
3243     if (disAbleAnimation || !animated) {
3244         isAnimated_ = false;
3245         return;
3246     }
3247     // check is dialog mode
3248     bool isDialog = false;
3249     if (preTopNavPath.has_value()) {
3250         auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(
3251             NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
3252         if (preDestination) {
3253             isDialog = isDialog || (preDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
3254         }
3255     }
3256     auto topNode = navigationStack_->Get();
3257     if (topNode) {
3258         auto newTopDestination = AceType::DynamicCast<NavDestinationGroupNode>(
3259             NavigationGroupNode::GetNavDestinationNode(topNode));
3260         if (newTopDestination) {
3261             isDialog = isDialog || (newTopDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
3262         }
3263     }
3264     if (!isDialog) {
3265         isAnimated_ = true;
3266         return;
3267     }
3268     isAnimated_ = isCustomAnimation_;
3269 }
3270 
GetHomeDestinationContext()3271 RefPtr<NavDestinationContext> NavigationPattern::GetHomeDestinationContext()
3272 {
3273     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3274     CHECK_NULL_RETURN(host, nullptr);
3275     auto homeDest = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
3276     CHECK_NULL_RETURN(homeDest, nullptr);
3277     auto homePattern = homeDest->GetPattern<NavDestinationPattern>();
3278     CHECK_NULL_RETURN(homePattern, nullptr);
3279     return homePattern->GetNavDestinationContext();
3280 }
3281 
NotifyNavDestinationSwitch(RefPtr<NavDestinationContext> from,RefPtr<NavDestinationContext> to,NavigationOperation operation)3282 void NavigationPattern::NotifyNavDestinationSwitch(RefPtr<NavDestinationContext> from,
3283     RefPtr<NavDestinationContext> to, NavigationOperation operation)
3284 {
3285     auto host = GetHost();
3286     auto NavdestinationSwitchFunc =
3287         UIObserverHandler::GetInstance().GetHandleNavDestinationSwitchFunc();
3288     if (!host || !NavdestinationSwitchFunc) {
3289         return;
3290     }
3291 
3292     bool useHomeDest = false;
3293     if (!from) {
3294         from = GetHomeDestinationContext();
3295         useHomeDest = from != nullptr;
3296     } else if (!to) {
3297         to = GetHomeDestinationContext();
3298     }
3299     std::string navigationId = host->GetInspectorIdValue("");
3300     std::optional<NavDestinationInfo> fromInfo;
3301     std::optional<NavDestinationInfo> toInfo;
3302     RefPtr<NavPathInfo> pathInfo = nullptr;
3303     if (from) {
3304         pathInfo = from->GetNavPathInfo();
3305     } else if (to) {
3306         pathInfo = to->GetNavPathInfo();
3307     }
3308     if (pathInfo) {
3309         pathInfo->OpenScope();
3310     }
3311     auto state = NavDestinationState::ON_HIDDEN;
3312     auto context = host->GetContextRefPtr();
3313     if (((IsForceSplitSupported(context) && forceSplitSuccess_) || useHomeDest) && from) {
3314         auto pattern = from->GetNavDestinationPattern();
3315         if (pattern && pattern->GetIsOnShow()) {
3316             state = NavDestinationState::ON_SHOWN;
3317         }
3318     }
3319     BuildNavDestinationInfoFromContext(navigationId, state, from, true, fromInfo);
3320     BuildNavDestinationInfoFromContext(navigationId, NavDestinationState::ON_SHOWN, to, false, toInfo);
3321     UIObserverHandler::GetInstance().NotifyNavDestinationSwitch(
3322         std::move(fromInfo), std::move(toInfo), operation);
3323     if (pathInfo) {
3324         pathInfo->CloseScope();
3325     }
3326 }
3327 
AppendFilterNodesFromHideNodes(std::set<RefPtr<NavDestinationGroupNode>> & filterNodes)3328 void NavigationPattern::AppendFilterNodesFromHideNodes(std::set<RefPtr<NavDestinationGroupNode>>& filterNodes)
3329 {
3330     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3331     CHECK_NULL_VOID(host);
3332     const auto& hideNodes = host->GetHideNodes();
3333     for (const auto& pair : hideNodes) {
3334         CHECK_NULL_CONTINUE(pair.first);
3335         filterNodes.emplace(pair.first);
3336     }
3337 }
3338 
AppendFilterNodesForWillHideLifecycle(std::set<RefPtr<NavDestinationGroupNode>> & filterNodes)3339 void NavigationPattern::AppendFilterNodesForWillHideLifecycle(std::set<RefPtr<NavDestinationGroupNode>>& filterNodes)
3340 {
3341     AppendFilterNodesFromHideNodes(filterNodes);
3342     for (auto& weakNode : primaryNodes_) {
3343         auto node = weakNode.Upgrade();
3344         CHECK_NULL_CONTINUE(node);
3345         filterNodes.emplace(node);
3346     }
3347 }
3348 
NotifyPrePrimaryNodesOnWillHide(std::set<RefPtr<NavDestinationGroupNode>> && filterNodes)3349 void NavigationPattern::NotifyPrePrimaryNodesOnWillHide(std::set<RefPtr<NavDestinationGroupNode>>&& filterNodes)
3350 {
3351     if (!forceSplitSuccess_ || forceSplitUseNavBar_) {
3352         return;
3353     }
3354 
3355     for (auto it = prePrimaryNodes_.rbegin(); it != prePrimaryNodes_.rend(); ++it) {
3356         auto node = it->Upgrade();
3357         CHECK_NULL_CONTINUE(node);
3358         auto pattern = node->GetPattern<NavDestinationPattern>();
3359         CHECK_NULL_CONTINUE(pattern);
3360         if (filterNodes.find(node) != filterNodes.end()) {
3361             continue;
3362         }
3363         if (!pattern->GetIsOnShow()) {
3364             continue;
3365         }
3366         NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_WILL_HIDE);
3367     }
3368 }
3369 
AppendFilterNodesForWillShowLifecycle(std::set<RefPtr<NavDestinationGroupNode>> & filterNodes)3370 void NavigationPattern::AppendFilterNodesForWillShowLifecycle(std::set<RefPtr<NavDestinationGroupNode>>& filterNodes)
3371 {
3372     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3373     CHECK_NULL_VOID(hostNode);
3374     const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
3375     int32_t lastStandardIndex = hostNode->GetLastStandardIndex();
3376     int32_t standardIndex = lastStandardIndex >= 0 ? lastStandardIndex : 0;
3377     int32_t end = navigationStack_->Size();
3378     for (int32_t index = standardIndex; index < end; index++) {
3379         const auto& uiNode = navDestinationNodes[index].second;
3380         auto destNode = AceType::DynamicCast<NavDestinationGroupNode>(
3381             NavigationGroupNode::GetNavDestinationNode(uiNode));
3382         filterNodes.emplace(destNode);
3383     }
3384 }
3385 
NotifyCurPrimaryNodesOnWillShow(std::set<RefPtr<NavDestinationGroupNode>> && filterNodes)3386 void NavigationPattern::NotifyCurPrimaryNodesOnWillShow(std::set<RefPtr<NavDestinationGroupNode>>&& filterNodes)
3387 {
3388     if (!forceSplitSuccess_ || forceSplitUseNavBar_) {
3389         return;
3390     }
3391 
3392     for (auto it = primaryNodes_.begin(); it != primaryNodes_.end(); ++it) {
3393         auto node = it->Upgrade();
3394         CHECK_NULL_CONTINUE(node);
3395         auto pattern = node->GetPattern<NavDestinationPattern>();
3396         CHECK_NULL_CONTINUE(pattern);
3397         if (filterNodes.find(node) != filterNodes.end()) {
3398             continue;
3399         }
3400         if (pattern->GetIsOnShow()) {
3401             continue;
3402         }
3403         NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_WILL_SHOW);
3404     }
3405 }
3406 
CheckIfNoNeedAnimationForForceSplit(const RefPtr<NavDestinationGroupNode> & preDestination,const RefPtr<NavDestinationGroupNode> & topDestination)3407 bool NavigationPattern::CheckIfNoNeedAnimationForForceSplit(const RefPtr<NavDestinationGroupNode>& preDestination,
3408     const RefPtr<NavDestinationGroupNode>& topDestination)
3409 {
3410     if (!forceSplitSuccess_) {
3411         return false;
3412     }
3413     if (forceSplitUseNavBar_) {
3414         return !preDestination || !topDestination;
3415     }
3416     return (preDestination && preDestination->IsShowInPrimaryPartition()) ||
3417         (topDestination && topDestination->IsShowInPrimaryPartition());
3418 }
3419 
FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle lifecycle)3420 void NavigationPattern::FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle lifecycle)
3421 {
3422     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3423     CHECK_NULL_VOID(host);
3424     auto homeDest = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
3425     CHECK_NULL_VOID(homeDest);
3426     auto homePattern = homeDest->GetPattern<NavDestinationPattern>();
3427     CHECK_NULL_VOID(homePattern);
3428     if (navigationMode_ != NavigationMode::STACK) {
3429         return;
3430     }
3431     auto lastStandardIndex = host->GetLastStandardIndex();
3432     auto preLastStandardIndex = host->GetPreLastStandardIndex();
3433     const auto& preNodes = GetAllNavDestinationNodesPrev();
3434     const auto& curNodes = GetAllNavDestinationNodes();
3435     if (lifecycle == NavDestinationLifecycle::ON_WILL_SHOW || lifecycle == NavDestinationLifecycle::ON_SHOW) {
3436         if (preLastStandardIndex >= 0 && lastStandardIndex < 0 && !homePattern->GetIsOnShow()) {
3437             NotifyDestinationLifecycle(homeDest, lifecycle);
3438         }
3439     } else if (lifecycle == NavDestinationLifecycle::ON_ACTIVE) {
3440         if (!preNodes.empty() && curNodes.empty() && !homePattern->IsActive()) {
3441             NotifyDestinationLifecycle(
3442                 homeDest, NavDestinationLifecycle::ON_ACTIVE, NavDestinationActiveReason::TRANSITION);
3443         }
3444     } else if (lifecycle == NavDestinationLifecycle::ON_INACTIVE) {
3445         if (preNodes.empty() && !curNodes.empty() && homePattern->IsActive()) {
3446             NotifyDestinationLifecycle(
3447                 homeDest, NavDestinationLifecycle::ON_INACTIVE, NavDestinationActiveReason::TRANSITION);
3448         }
3449     } else if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE || lifecycle == NavDestinationLifecycle::ON_HIDE) {
3450         if (preLastStandardIndex < 0 && lastStandardIndex >= 0 && homePattern->GetIsOnShow()) {
3451             NotifyDestinationLifecycle(homeDest, lifecycle);
3452         }
3453     }
3454 }
3455 
GetHomeDestinationName(const RefPtr<FrameNode> & hostNode,std::string & name)3456 bool NavigationPattern::GetHomeDestinationName(const RefPtr<FrameNode>& hostNode, std::string& name)
3457 {
3458     auto host = AceType::DynamicCast<NavigationGroupNode>(hostNode);
3459     CHECK_NULL_RETURN(host, false);
3460     auto homeDest = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
3461     CHECK_NULL_RETURN(homeDest, false);
3462     auto homePattern = homeDest->GetPattern<NavDestinationPattern>();
3463     CHECK_NULL_RETURN(homePattern, false);
3464     name = homePattern->GetName();
3465     return true;
3466 }
3467 
StartTransition(const RefPtr<NavDestinationGroupNode> & preDestination,const RefPtr<NavDestinationGroupNode> & topDestination,bool isAnimated,bool isPopPage,bool isNeedVisible)3468 void NavigationPattern::StartTransition(const RefPtr<NavDestinationGroupNode>& preDestination,
3469     const RefPtr<NavDestinationGroupNode>& topDestination,
3470     bool isAnimated, bool isPopPage, bool isNeedVisible)
3471 {
3472     std::string fromPathInfo;
3473     std::string toPathInfo;
3474     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3475     CHECK_NULL_VOID(hostNode);
3476     bool isNotNeedAnimation = !isAnimated;
3477 #if defined(ENABLE_NAV_SPLIT_MODE)
3478     isNotNeedAnimation = !isAnimated ||
3479         (navigationMode_ == NavigationMode::SPLIT && navigationStack_->Size() <= 1 &&
3480             !isBackPage_ && !isCustomAnimation_);
3481     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "StartTransition navigationMode_:%{public}d isNotNeedAnimation:%{public}d",
3482         navigationMode_, isNotNeedAnimation);
3483 #endif
3484     if (CheckIfNoNeedAnimationForForceSplit(preDestination, topDestination)) {
3485         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "StartTransition don't need animation in forceSplit mode");
3486         isNotNeedAnimation = true;
3487     }
3488 
3489     std::string fromNavDestinationName = "";
3490     std::string toNavDestinationName = "";
3491     if (preDestination) {
3492         fromPathInfo = preDestination->GetNavDestinationPathInfo();
3493         auto preDestinationPattern = preDestination->GetPattern<NavDestinationPattern>();
3494         CHECK_NULL_VOID(preDestinationPattern);
3495         fromNavDestinationName = preDestinationPattern->GetName();
3496         fromPathInfo += ", navDesitinationName: " + fromNavDestinationName;
3497         if ((isPopPage || preDestination->NeedRemoveInPush()) && isNotNeedAnimation) {
3498             /**
3499              * when transition without animation, 'pop' and 'push with remove' need to post
3500              * afterLayoutTask to delay old top's onDisappear. So set this flag to 'false'
3501              */
3502             preDestination->SetIsAnimated(false);
3503         }
3504     } else if (GetHomeDestinationName(hostNode, fromNavDestinationName)) {
3505         fromPathInfo += ", navDesitinationName: " + fromNavDestinationName;
3506     } else {
3507         fromPathInfo = hostNode->GetNavigationPathInfo();
3508     }
3509     if (topDestination) {
3510         toPathInfo = topDestination->GetNavDestinationPathInfo();
3511         auto topDestinationPattern = topDestination->GetPattern<NavDestinationPattern>();
3512         CHECK_NULL_VOID(topDestinationPattern);
3513         toNavDestinationName = topDestinationPattern->GetName();
3514         toPathInfo += ", navDesitinationName: " + toNavDestinationName;
3515     } else if (GetHomeDestinationName(hostNode, toNavDestinationName)) {
3516         toPathInfo += ", navDesitinationName: " + toNavDestinationName;
3517     } else {
3518         toPathInfo = hostNode->GetNavigationPathInfo();
3519     }
3520     ACE_SCOPED_TRACE_COMMERCIAL("NavDestination Page from %s to %s", fromPathInfo.c_str(), toPathInfo.c_str());
3521     if (PerfMonitor::GetPerfMonitor() != nullptr) {
3522         PerfMonitor::GetPerfMonitor()->SetPageName(toNavDestinationName);
3523     }
3524     ResSchedReport::GetInstance().HandlePageTransition(fromNavDestinationName, toNavDestinationName, "navigation");
3525     UiSessionManager::GetInstance()->OnRouterChange(toPathInfo.c_str(), "navigationPathChange");
3526     // fire onWillHide
3527     if (!isPopPage && !preDestination && navigationMode_ == NavigationMode::STACK) {
3528         // NavBar/HomeNavDestination will be covered in STACK mode
3529         auto navBarOrHomeDestNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
3530         ProcessAutoSave(navBarOrHomeDestNode);
3531     }
3532     std::set<RefPtr<NavDestinationGroupNode>> filterNodes;
3533     if (isPopPage || IsDestinationNeedHideInPush(hostNode, preDestination)) {
3534         NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_WILL_HIDE);
3535         filterNodes.emplace(preDestination);
3536     }
3537     AppendFilterNodesForWillHideLifecycle(filterNodes);
3538     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_HIDE);
3539     NotifyPrePrimaryNodesOnWillHide(std::move(filterNodes));
3540 
3541     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_WILL_HIDE);
3542 
3543     auto pipeline = PipelineContext::GetCurrentContext();
3544     CHECK_NULL_VOID(pipeline);
3545     auto navigationManager = pipeline->GetNavigationManager();
3546     navigationManager->FireNavigationUpdateCallback();
3547     auto overlayManager = pipeline->GetOverlayManager();
3548     if (overlayManager) {
3549         overlayManager->RemoveAllModalInOverlay(false);
3550     }
3551     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_WILL_SHOW);
3552 
3553     if (topDestination) {
3554         filterNodes.clear();
3555         AppendFilterNodesForWillShowLifecycle(filterNodes);
3556         NotifyCurPrimaryNodesOnWillShow(std::move(filterNodes));
3557 
3558         NotifyDialogChange(NavDestinationLifecycle::ON_WILL_SHOW, true);
3559         topDestination->SetNodeFreeze(false);
3560     }
3561     if (preDestination) {
3562         preDestination->SetNodeFreeze(false);
3563     }
3564     UpdatePageViewportConfigIfNeeded(preDestination, topDestination);
3565     pipeline->AddAfterLayoutTask([weakPattern = WeakClaim(this)]() {
3566         auto pattern = weakPattern.Upgrade();
3567         CHECK_NULL_VOID(pattern);
3568         pattern->HideSystemBarIfNeeded();
3569     });
3570     if (isNotNeedAnimation) {
3571         FireShowAndHideLifecycle(preDestination, topDestination, isPopPage, false);
3572         TransitionWithOutAnimation(preDestination, topDestination, isPopPage, isNeedVisible);
3573         prePrimaryNodes_.clear();
3574         primaryNodesToBeRemoved_.clear();
3575         RemoveRedundantPrimaryNavDestination();
3576         return;
3577     }
3578 
3579     pipeline->AddAfterLayoutTask([weakNavigation = WeakClaim(this),
3580         weakPreDestination = WeakPtr<NavDestinationGroupNode>(preDestination),
3581         weakTopDestination = WeakPtr<NavDestinationGroupNode>(topDestination),
3582         isPopPage, isNeedVisible]() {
3583         auto navigationPattern = AceType::DynamicCast<NavigationPattern>(weakNavigation.Upgrade());
3584         CHECK_NULL_VOID(navigationPattern);
3585         auto preDestination = weakPreDestination.Upgrade();
3586         auto topDestination = weakTopDestination.Upgrade();
3587 
3588         auto forceSplitSuccess = navigationPattern->IsForceSplitSuccess();
3589         auto forceSplitUseNavBar = navigationPattern->IsForceSplitUseNavBar();
3590         if (forceSplitSuccess && !forceSplitUseNavBar &&
3591             ((preDestination && preDestination->GetNavDestinationType() == NavDestinationType::HOME) ||
3592             (topDestination && topDestination->GetNavDestinationType() == NavDestinationType::HOME))) {
3593             navigationPattern->FireShowAndHideLifecycle(preDestination, topDestination, isPopPage, false);
3594             navigationPattern->TransitionWithOutAnimation(preDestination, topDestination, isPopPage, isNeedVisible);
3595             navigationPattern->prePrimaryNodes_.clear();
3596             navigationPattern->primaryNodesToBeRemoved_.clear();
3597             navigationPattern->RemoveRedundantPrimaryNavDestination();
3598             return;
3599         }
3600 
3601         navigationPattern->FireShowAndHideLifecycle(preDestination, topDestination, isPopPage, true);
3602         navigationPattern->TransitionWithAnimation(preDestination, topDestination, isPopPage, isNeedVisible);
3603         navigationPattern->prePrimaryNodes_.clear();
3604         navigationPattern->primaryNodesToBeRemoved_.clear();
3605         navigationPattern->RemoveRedundantPrimaryNavDestination();
3606     });
3607 }
3608 
ProcessAutoSave(const RefPtr<FrameNode> & node)3609 void NavigationPattern::ProcessAutoSave(const RefPtr<FrameNode>& node)
3610 {
3611     CHECK_NULL_VOID(node);
3612     if (!node->NeedRequestAutoSave()) {
3613         return;
3614     }
3615     auto container = Container::Current();
3616     CHECK_NULL_VOID(container);
3617     container->RequestAutoSave(node);
3618 }
3619 
NotifyDestinationLifecycle(const RefPtr<UINode> & uiNode,NavDestinationLifecycle lifecycle,NavDestinationActiveReason reason)3620 void NavigationPattern::NotifyDestinationLifecycle(const RefPtr<UINode>& uiNode,
3621     NavDestinationLifecycle lifecycle, NavDestinationActiveReason reason)
3622 {
3623     auto curDestination =
3624         AceType::DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(uiNode));
3625     CHECK_NULL_VOID(curDestination);
3626     auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
3627     CHECK_NULL_VOID(eventHub);
3628     if (lifecycle == NavDestinationLifecycle::ON_WILL_DISAPPEAR) {
3629         NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
3630         eventHub->FireOnWillDisAppear();
3631         return;
3632     }
3633     auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
3634     CHECK_NULL_VOID(navDestinationPattern);
3635     if (lifecycle == NavDestinationLifecycle::ON_INACTIVE) {
3636         FireOnInactiveLifecycle(curDestination, reason);
3637         return;
3638     }
3639     if (lifecycle == NavDestinationLifecycle::ON_ACTIVE) {
3640         FireOnActiveLifecycle(curDestination, reason);
3641         return;
3642     }
3643     if ((navDestinationPattern->GetIsOnShow() && (lifecycle == NavDestinationLifecycle::ON_SHOW ||
3644             lifecycle == NavDestinationLifecycle::ON_WILL_SHOW)) ||
3645         (!navDestinationPattern->GetIsOnShow() && (lifecycle == NavDestinationLifecycle::ON_HIDE ||
3646             lifecycle == NavDestinationLifecycle::ON_WILL_HIDE))) {
3647         return;
3648     }
3649     if (lifecycle == NavDestinationLifecycle::ON_WILL_SHOW) {
3650         eventHub->FireOnWillShow();
3651         NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
3652         return;
3653     }
3654     if (lifecycle == NavDestinationLifecycle::ON_SHOW) {
3655         FireOnShowLifecycle(curDestination);
3656         return;
3657     }
3658     NavigationPattern::FireNavigationLifecycleChange(curDestination, lifecycle);
3659     if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE) {
3660         eventHub->FireOnWillHide();
3661         return;
3662     }
3663     if (lifecycle == NavDestinationLifecycle::ON_HIDE) {
3664         eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
3665         NotifyPageHide(navDestinationPattern->GetName());
3666         navDestinationPattern->SetIsOnShow(false);
3667     }
3668 }
3669 
FireOnShowLifecycle(const RefPtr<NavDestinationGroupNode> & curDestination)3670 void NavigationPattern::FireOnShowLifecycle(const RefPtr<NavDestinationGroupNode>& curDestination)
3671 {
3672     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3673     CHECK_NULL_VOID(navigationNode);
3674     auto parentDestinationNode = navigationNode->GetParentDestinationNode().Upgrade();
3675     if (CheckParentDestinationIsOnhide(parentDestinationNode) && CheckDestinationIsPush(parentDestinationNode)) {
3676         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "parentDestinationNode is onhide");
3677         return;
3678     }
3679     auto param = Recorder::EventRecorder::Get().IsPageParamRecordEnable() ? navigationStack_->GetRouteParam() : "";
3680     auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
3681     CHECK_NULL_VOID(eventHub);
3682     auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
3683     CHECK_NULL_VOID(navDestinationPattern);
3684     eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
3685     NotifyPageShow(navDestinationPattern->GetName());
3686     navDestinationPattern->SetIsOnShow(true);
3687     NavigationPattern::FireNavigationLifecycleChange(curDestination, NavDestinationLifecycle::ON_SHOW);
3688 }
3689 
FireOnActiveLifecycle(const RefPtr<NavDestinationGroupNode> & curDestination,NavDestinationActiveReason reason)3690 void NavigationPattern::FireOnActiveLifecycle(const RefPtr<NavDestinationGroupNode>& curDestination,
3691     NavDestinationActiveReason reason)
3692 {
3693     auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
3694     CHECK_NULL_VOID(navDestinationPattern);
3695     if (navDestinationPattern->IsActive() || CheckParentDestinationInactive()) {
3696         return;
3697     }
3698     auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
3699     CHECK_NULL_VOID(eventHub);
3700     navDestinationPattern->SetIsActive(true);
3701     eventHub->FireOnActive(static_cast<int32_t>(reason));
3702     NavigationPattern::FireNavigationLifecycle(curDestination, NavDestinationLifecycle::ON_ACTIVE, reason);
3703 }
3704 
FireOnInactiveLifecycle(const RefPtr<NavDestinationGroupNode> & curDestination,NavDestinationActiveReason reason)3705 void NavigationPattern::FireOnInactiveLifecycle(const RefPtr<NavDestinationGroupNode>& curDestination,
3706     NavDestinationActiveReason reason)
3707 {
3708     auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
3709     CHECK_NULL_VOID(navDestinationPattern);
3710     if (!navDestinationPattern->IsActive()) {
3711         return;
3712     }
3713     auto eventHub = curDestination->GetOrCreateEventHub<NavDestinationEventHub>();
3714     CHECK_NULL_VOID(eventHub);
3715     navDestinationPattern->SetIsActive(false);
3716     NavigationPattern::FireNavigationLifecycle(curDestination, NavDestinationLifecycle::ON_INACTIVE, reason);
3717     eventHub->FireOnInactive(static_cast<int32_t>(reason));
3718 }
3719 
GetNavdestinationJsonArray()3720 std::unique_ptr<JsonValue> NavigationPattern::GetNavdestinationJsonArray()
3721 {
3722     auto allNavdestinationInfo = JsonUtil::CreateArray(true);
3723     const auto& navdestinationNodes = GetAllNavDestinationNodes();
3724     for (auto iter : navdestinationNodes) {
3725         auto navdestinationInfo = JsonUtil::Create(true);
3726         auto navdestinationNode =
3727             AceType::DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(iter.second));
3728         if (!navdestinationNode) {
3729             continue;
3730         }
3731         if (!navdestinationNode->CanRecovery()) {
3732             continue;
3733         }
3734         auto navdestinationPattern = navdestinationNode->GetPattern<NavDestinationPattern>();
3735         if (!navdestinationPattern) {
3736             continue;
3737         }
3738         auto name = navdestinationPattern->GetName();
3739         auto param = navigationStack_->GetStringifyParamByIndex(navdestinationNode->GetIndex());
3740         auto mode = static_cast<int32_t>(navdestinationNode->GetNavDestinationMode());
3741         navdestinationInfo->Put("name", name.c_str());
3742         navdestinationInfo->Put("param", param.c_str());
3743         navdestinationInfo->Put("mode", mode);
3744         allNavdestinationInfo->Put(navdestinationInfo);
3745     }
3746     return allNavdestinationInfo;
3747 }
3748 
GetTopNavdestinationJson(bool needParam)3749 std::unique_ptr<JsonValue> NavigationPattern::GetTopNavdestinationJson(bool needParam)
3750 {
3751     auto topNavdestinationJson = JsonUtil::Create(true);
3752     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3753     CHECK_NULL_RETURN(hostNode, topNavdestinationJson);
3754     auto topNavDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
3755         NavigationGroupNode::GetNavDestinationNode(GetNavDestinationNode()));
3756     if (!topNavDestinationNode) {
3757         return topNavdestinationJson;
3758     }
3759     auto navdestinationPattern = topNavDestinationNode->GetPattern<NavDestinationPattern>();
3760     if (!navdestinationPattern) {
3761         return topNavdestinationJson;
3762     }
3763     auto name = navdestinationPattern->GetName();
3764     auto mode = static_cast<int32_t>(topNavDestinationNode->GetNavDestinationMode());
3765     topNavdestinationJson->Put("name", name.c_str());
3766     topNavdestinationJson->Put("mode", mode);
3767     topNavdestinationJson->Put("navigationId", hostNode->GetCurId().c_str());
3768     std::string param = "";
3769     if (needParam) {
3770         param = navdestinationPattern->GetSerializedParam();
3771         topNavdestinationJson->Put("param", param.c_str());
3772     }
3773     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get top navDestinationInfo success, name: %{public}s, mode: %{public}d, "
3774         "navigationId: %{public}s, hasParam? %{public}s", name.c_str(), mode, hostNode->GetCurId().c_str(),
3775         param.empty() ? "no" : "yes");
3776     return topNavdestinationJson;
3777 }
3778 
RestoreJsStackIfNeeded()3779 void NavigationPattern::RestoreJsStackIfNeeded()
3780 {
3781     auto pipeline = PipelineContext::GetCurrentContext();
3782     CHECK_NULL_VOID(pipeline);
3783     auto navigationManager = pipeline->GetNavigationManager();
3784     CHECK_NULL_VOID(navigationManager);
3785     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3786     CHECK_NULL_VOID(hostNode);
3787     auto navdestinationsInfo = navigationManager->GetNavigationRecoveryInfo(hostNode->GetCurId());
3788     if (navdestinationsInfo.empty()) {
3789         return;
3790     }
3791     navigationStack_->SetPathArray(navdestinationsInfo);
3792 }
3793 
PerformanceEventReport(int32_t nodeCount,int32_t depth,const std::string & navDestinationName)3794 void NavigationPattern::PerformanceEventReport(int32_t nodeCount, int32_t depth, const std::string& navDestinationName)
3795 {
3796     if (nodeCount >= PAGE_NODES) {
3797         EventReport::ReportPageNodeOverflow(navDestinationName, nodeCount, PAGE_NODES);
3798     }
3799     if (depth >= PAGE_DEPTH) {
3800         EventReport::ReportPageDepthOverflow(navDestinationName, depth, PAGE_DEPTH);
3801     }
3802 }
3803 
IsTopPrimaryNode(const RefPtr<NavDestinationGroupNode> & node)3804 bool NavigationPattern::IsTopPrimaryNode(const RefPtr<NavDestinationGroupNode>& node)
3805 {
3806     return forceSplitSuccess_ && !forceSplitUseNavBar_ &&
3807         !primaryNodes_.empty() && node == primaryNodes_.back().Upgrade();
3808 }
3809 
FireShowAndHideLifecycle(const RefPtr<NavDestinationGroupNode> & preDestination,const RefPtr<NavDestinationGroupNode> & topDestination,bool isPopPage,bool isAnimated)3810 void NavigationPattern::FireShowAndHideLifecycle(const RefPtr<NavDestinationGroupNode>& preDestination,
3811     const RefPtr<NavDestinationGroupNode>& topDestination, bool isPopPage, bool isAnimated)
3812 {
3813     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3814     CHECK_NULL_VOID(hostNode);
3815     // don't move position hide lifecycle is from top to end
3816     if (preDestination) {
3817         if (!IsTopPrimaryNode(preDestination)) {
3818             NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_INACTIVE);
3819         }
3820         if (isPopPage || IsDestinationNeedHideInPush(hostNode, preDestination)) {
3821             // fire preTop Destination lifecycle
3822             NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_HIDE);
3823         }
3824     }
3825     // fire remove navDestination and invisible navDestination lifecycle for pop or clear
3826     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
3827     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_INACTIVE);
3828     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_HIDE);
3829     FirePreTopPrimaryNodeInactiveIfNeeded();
3830     FirePrePrimaryNodesOnHide();
3831     std::set<RefPtr<NavDestinationGroupNode>> filterNodes;
3832     if (isPopPage || (preDestination && preDestination->NeedRemoveInPush())) {
3833         // fire removed preDestination lifecycle for pop many times or clear
3834         filterNodes.emplace(preDestination);
3835         NotifyDestinationLifecycle(preDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
3836     }
3837     AppendFilterNodesFromHideNodes(filterNodes);
3838     // fire removed navDestination lifecycle
3839     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
3840     FirePrePrimaryNodesOnWillDisappear(std::move(filterNodes));
3841     FirePrimaryNodesOnShowAndActive();
3842     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_SHOW);
3843     FireHomeDestinationLifecycleForTransition(NavDestinationLifecycle::ON_ACTIVE);
3844     if (!isAnimated) {
3845         auto pipelineContext = PipelineContext::GetCurrentContext();
3846         CHECK_NULL_VOID(pipelineContext);
3847         pipelineContext->AddAfterLayoutTask([weakNavigation = WeakClaim(this),
3848             weakTopDestination = WeakPtr<NavDestinationGroupNode>(topDestination)]() {
3849             auto navigation = weakNavigation.Upgrade();
3850             CHECK_NULL_VOID(navigation);
3851             auto topDestination = weakTopDestination.Upgrade();
3852             navigation->NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true);
3853             navigation->NotifyDestinationLifecycle(topDestination, NavDestinationLifecycle::ON_ACTIVE);
3854         });
3855     } else {
3856         NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true);
3857         NotifyDestinationLifecycle(topDestination, NavDestinationLifecycle::ON_ACTIVE);
3858     }
3859     FireInterceptionEvent(false, navigationStack_->GetTopNavPath());
3860 }
3861 
OnWindowSizeChanged(int32_t,int32_t,WindowSizeChangeReason type)3862 void NavigationPattern::OnWindowSizeChanged(int32_t  /*width*/, int32_t  /*height*/, WindowSizeChangeReason type)
3863 {
3864     if (WindowSizeChangeReason::ROTATION == type) {
3865         auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3866         CHECK_NULL_VOID(hostNode);
3867         AbortAnimation(hostNode);
3868         CloseLongPressDialog();
3869     }
3870 }
3871 
OnWindowHide()3872 void NavigationPattern::OnWindowHide()
3873 {
3874     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3875     CHECK_NULL_VOID(hostNode);
3876     auto navigationPattern = hostNode->GetPattern<NavigationPattern>();
3877     CHECK_NULL_VOID(navigationPattern);
3878     navigationPattern->SyncWithJsStackIfNeeded();
3879 }
3880 
NotifyPerfMonitorPageMsg(const std::string & pageName)3881 void NavigationPattern::NotifyPerfMonitorPageMsg(const std::string& pageName)
3882 {
3883     auto container = Container::Current();
3884     if (container != nullptr && PerfMonitor::GetPerfMonitor() != nullptr) {
3885         std::string bundleName = container->GetBundleName();
3886         PerfMonitor::GetPerfMonitor()->ReportPageShowMsg("", bundleName, pageName);
3887     }
3888 }
3889 
RefreshFocusToDestination()3890 void NavigationPattern::RefreshFocusToDestination()
3891 {
3892     auto newTopNavPath = navigationStack_->GetTopNavPath();
3893     if (!newTopNavPath.has_value()) {
3894         return;
3895     }
3896     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3897     CHECK_NULL_VOID(hostNode);
3898     auto navBarOrHomeDestNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
3899     CHECK_NULL_VOID(navBarOrHomeDestNode);
3900     auto navBarOrHomeDestFocus = navBarOrHomeDestNode->GetFocusHub();
3901     CHECK_NULL_VOID(navBarOrHomeDestFocus);
3902     if (!navBarOrHomeDestFocus->IsCurrentFocus()) {
3903         return;
3904     }
3905     auto newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
3906         NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
3907     CHECK_NULL_VOID(newTopNavDestination);
3908     if (!GetIsFocusable(newTopNavDestination)) {
3909         return;
3910     }
3911     auto navDestinationFocusView = newTopNavDestination->GetPattern<FocusView>();
3912     CHECK_NULL_VOID(navDestinationFocusView);
3913     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
3914         navDestinationFocusView->SetIsViewRootScopeFocused(false);
3915     }
3916     navDestinationFocusView->FocusViewShow();
3917 }
3918 
RecoveryToLastStack(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopDestination)3919 void NavigationPattern::RecoveryToLastStack(
3920     const RefPtr<NavDestinationGroupNode>& preTopDestination,
3921     const RefPtr<NavDestinationGroupNode>& newTopDestination)
3922 {
3923     if (preTopDestination) {
3924         preTopDestination->SetIsOnAnimation(false);
3925         preTopDestination->SetInCurrentStack(true);
3926     }
3927     if (newTopDestination) {
3928         newTopDestination->SetIsOnAnimation(false);
3929     }
3930     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3931     CHECK_NULL_VOID(hostNode);
3932     hostNode->CleanHideNodes();
3933     CHECK_NULL_VOID(navigationStack_);
3934     navigationStack_->SetNavPathList(navigationStack_->GetRecoveryList());
3935 
3936     // update cached node
3937     auto destinationNodes = navigationStack_->GetAllNavDestinationNodes();
3938     for (uint32_t index = 0; index < destinationNodes.size(); index++) {
3939         auto childNode = destinationNodes[index];
3940         if (!childNode.second) {
3941             continue;
3942         }
3943         auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
3944             NavigationGroupNode::GetNavDestinationNode(childNode.second));
3945         if (!navDestinationNode) {
3946             continue;
3947         }
3948         // update pre cache node to cache node list
3949         auto cacheNode = navigationStack_->GetFromCacheNode(childNode.first);
3950         if (cacheNode && cacheNode == childNode.second) {
3951             navigationStack_->AddCacheNode(childNode.first, childNode.second);
3952         }
3953     }
3954     hostNode->UpdateNavDestinationNodeWithoutMarkDirty(nullptr, navigationModeChange_);
3955 
3956     // recover lifecycle state before transition
3957     NotifyDestinationLifecycle(preTopDestination, NavDestinationLifecycle::ON_INACTIVE);
3958     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_HIDE);
3959     hostNode->FireHideNodeChange(NavDestinationLifecycle::ON_WILL_DISAPPEAR);
3960     NotifyDialogChange(NavDestinationLifecycle::ON_SHOW, true);
3961     NotifyDestinationLifecycle(newTopDestination, NavDestinationLifecycle::ON_ACTIVE);
3962     hostNode->RemoveDialogDestination(false, true);
3963     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
3964 
3965     // update name index
3966     navigationStack_->RecoveryNavigationStack();
3967     ACE_SCOPED_TRACE_COMMERCIAL("Navigation page transition end");
3968     PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
3969     hostNode->SetIsOnAnimation(false);
3970     auto id = hostNode->GetTopDestination() ? hostNode->GetTopDestination()->GetAccessibilityId() : -1;
3971     hostNode->OnAccessibilityEvent(
3972         AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
3973 }
3974 
ExecuteAddAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,RefPtr<NavDestinationGroupNode> newTopNavDestination,bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy,NavigationTransition navigationTransition)3975 bool NavigationPattern::ExecuteAddAnimation(RefPtr<NavDestinationGroupNode> preTopNavDestination,
3976     RefPtr<NavDestinationGroupNode> newTopNavDestination,
3977     bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy,
3978     NavigationTransition navigationTransition)
3979 {
3980     // custom animation return undefined,finish this transition
3981     if (!navigationTransition.isValid) {
3982         proxy->SetIsSuccess(false);
3983         proxy->SetIsFinished(true);
3984         return false;
3985     }
3986     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
3987     RefPtr<NavDestinationGroupNode> homeDestination = host ?
3988         AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode()) : nullptr;
3989     if (!preTopNavDestination) {
3990         preTopNavDestination = homeDestination;
3991     } else if (!newTopNavDestination) {
3992         newTopNavDestination = homeDestination;
3993     }
3994     if (preTopNavDestination) {
3995         preTopNavDestination->SetIsOnAnimation(true);
3996         if (!isPopPage) {
3997             auto renderContext = preTopNavDestination->GetRenderContext();
3998             CHECK_NULL_RETURN(renderContext, false);
3999             renderContext->RemoveClipWithRRect();
4000         }
4001     }
4002     if (newTopNavDestination) {
4003         newTopNavDestination->SetIsOnAnimation(true);
4004     }
4005     auto proxyId = proxy->GetProxyId();
4006     proxy->SetInteractive(navigationTransition.interactive);
4007     // set on transition end callback
4008     proxy->SetEndCallback(std::move(navigationTransition.endCallback));
4009     std::function<void()> onFinish = [weakNavigation = WeakClaim(this),
4010                      weakPreNavDestination = WeakPtr<NavDestinationGroupNode>(preTopNavDestination),
4011                      weakNewNavDestination = WeakPtr<NavDestinationGroupNode>(newTopNavDestination),
4012                      isPopPage, proxyId]() {
4013         auto pattern = weakNavigation.Upgrade();
4014         CHECK_NULL_VOID(pattern);
4015         auto proxy = pattern->GetProxyById(proxyId);
4016         auto preDestination = weakPreNavDestination.Upgrade();
4017         auto topDestination = weakNewNavDestination.Upgrade();
4018         // disable render group for text node after the custom animation
4019         if (isPopPage && preDestination) {
4020             preDestination->ReleaseTextNodeList();
4021         }
4022         if (!isPopPage && topDestination) {
4023             topDestination->ReleaseTextNodeList();
4024         }
4025         // to avoid call finishTransition many times
4026         if (proxy == nullptr) {
4027             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "custom animation proxy is empty or is finished");
4028             return;
4029         }
4030         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom animation finish end");
4031         proxy->SetIsFinished(true);
4032         // update pre navigation stack
4033         ACE_SCOPED_TRACE_COMMERCIAL("navigation page custom transition end");
4034         PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
4035         pattern->ClearRecoveryList();
4036         pattern->OnCustomAnimationFinish(preDestination, topDestination, isPopPage);
4037         pattern->RemoveProxyById(proxyId);
4038     };
4039     auto finishWrapper = [onFinishCb = std::move(onFinish), weakNavigation = WeakClaim(this)]() {
4040         auto pattern = weakNavigation.Upgrade();
4041         if (onFinishCb) {
4042             onFinishCb();
4043         }
4044         CHECK_NULL_VOID(pattern);
4045         pattern->OnFinishOneTransitionAnimation();
4046     };
4047     proxy->SetFinishTransitionEvent(finishWrapper);
4048     // add timeout callback
4049     auto timeout = navigationTransition.timeout;
4050     auto hostNode = GetHost();
4051     CHECK_NULL_RETURN(hostNode, false);
4052     auto pipeline = hostNode->GetContext();
4053     CHECK_NULL_RETURN(pipeline, false);
4054     auto taskExecutor = pipeline->GetTaskExecutor();
4055     CHECK_NULL_RETURN(taskExecutor, false);
4056     if (timeout < 0) {
4057         return true;
4058     }
4059     // deal timeout callback
4060     taskExecutor->PostDelayedTask(
4061         [weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] {
4062             auto transitionProxy = weakProxy.Upgrade();
4063             CHECK_NULL_VOID(transitionProxy);
4064             transitionProxy->FireFinishCallback();
4065         },
4066         TaskExecutor::TaskType::UI, timeout, "ArkUINavigationTransitionProxyFinish");
4067     return true;
4068 }
4069 
GetIsFocusable(const RefPtr<FrameNode> & frameNode)4070 bool NavigationPattern::GetIsFocusable(const RefPtr<FrameNode>& frameNode)
4071 {
4072     CHECK_NULL_RETURN(frameNode, false);
4073     auto hostNode = AceType::DynamicCast<FrameNode>(GetHost());
4074     CHECK_NULL_RETURN(hostNode, false);
4075     auto focusHub = hostNode->GetFocusHub();
4076     CHECK_NULL_RETURN(focusHub, false);
4077     if (!focusHub->IsFocusableWholePath()) {
4078         return false;
4079     }
4080     auto currentFocusHub = frameNode->GetFocusHub();
4081     CHECK_NULL_RETURN(currentFocusHub, false);
4082     return currentFocusHub->IsFocusableNode();
4083 }
4084 
IsLastStdChange()4085 bool NavigationPattern::IsLastStdChange()
4086 {
4087     // check whether last std navdestination id is changed, change return true, not change return false
4088     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4089     CHECK_NULL_RETURN(navigationNode, false);
4090     auto& navPathList = navigationStack_->GetAllNavDestinationNodes();
4091     auto& preNavPathList = navigationStack_->GetAllNavDestinationNodesPrev();
4092     auto lastStdIndex = navigationNode->GetLastStandardIndex();
4093     auto preLastStdIndex = navigationNode->GetPreLastStandardIndex();
4094     if (preLastStdIndex == -1 && lastStdIndex == -1) {
4095         return false;
4096     }
4097     if (preLastStdIndex != -1 && lastStdIndex != -1) {
4098         // check new and pre std navdestination id changed or not
4099         auto preStd = NavigationGroupNode::GetNavDestinationNode(preNavPathList[preLastStdIndex].second.Upgrade());
4100         auto newStd = NavigationGroupNode::GetNavDestinationNode(navPathList[lastStdIndex].second);
4101         if (preStd && newStd) {
4102             return preStd != newStd;
4103         }
4104     }
4105     return true;
4106 }
4107 
FollowStdNavdestinationAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)4108 void NavigationPattern::FollowStdNavdestinationAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
4109     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
4110 {
4111     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4112     CHECK_NULL_VOID(navigationNode);
4113     if (preTopNavDestination && newTopNavDestination) {
4114         if (isPopPage) {
4115             navigationNode->TransitionWithDialogPop(preTopNavDestination, newTopNavDestination);
4116         } else {
4117             navigationNode->TransitionWithDialogPush(preTopNavDestination, newTopNavDestination);
4118         }
4119         return;
4120     }
4121     if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
4122         auto navBarOrHomeDestNode =
4123             AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
4124         CHECK_NULL_VOID(navBarOrHomeDestNode);
4125         navigationNode->TransitionWithDialogPush(navBarOrHomeDestNode, newTopNavDestination, true);
4126         return;
4127     }
4128     if (preTopNavDestination) {
4129         if (navigationMode_ == NavigationMode::SPLIT) {
4130             navigationNode->TransitionWithDialogPop(preTopNavDestination, nullptr);
4131         }
4132         if (navigationMode_ == NavigationMode::STACK) {
4133             auto navBarOrHomeDestNode =
4134                 AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
4135             CHECK_NULL_VOID(navBarOrHomeDestNode);
4136             navigationNode->TransitionWithDialogPop(preTopNavDestination, navBarOrHomeDestNode, true);
4137         }
4138     }
4139 }
4140 
TransitionWithDialogAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)4141 void NavigationPattern::TransitionWithDialogAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
4142     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
4143 {
4144     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4145     CHECK_NULL_VOID(navigationNode);
4146 
4147     // if last standard id is not changed and new top navdestination is standard
4148     if (!isPopPage && !IsLastStdChange() && newTopNavDestination &&
4149         newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
4150         return;
4151     }
4152     auto replaceVal = navigationStack_->GetReplaceValue();
4153     if (replaceVal != 0) {
4154         ReplaceAnimation(preTopNavDestination, newTopNavDestination);
4155         return;
4156     }
4157     // last std id is not change, but new dialogs came into stack and upward animation
4158     if (!IsLastStdChange()) {
4159         if (isPopPage) {
4160             navigationNode->StartDialogtransition(preTopNavDestination, newTopNavDestination, false);
4161         } else {
4162             if (!preTopNavDestination && navigationMode_ == NavigationMode::SPLIT) {
4163                 // if split mode and push one dialog at the first time, no animation
4164                 return;
4165             }
4166             navigationNode->StartDialogtransition(preTopNavDestination, newTopNavDestination, true);
4167         }
4168         return;
4169     }
4170     FollowStdNavdestinationAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
4171 }
4172 
DumpInfo(std::unique_ptr<JsonValue> & json)4173 void NavigationPattern::DumpInfo(std::unique_ptr<JsonValue>& json)
4174 {
4175     if (!navigationStack_) {
4176         return;
4177     }
4178     json->Put("size", std::to_string(navigationStack_->Size()).c_str());
4179 }
4180 
CreateDragBarNode(const RefPtr<NavigationGroupNode> & navigationGroupNode)4181 void NavigationPattern::CreateDragBarNode(const RefPtr<NavigationGroupNode>& navigationGroupNode)
4182 {
4183     auto dragBarNode = FrameNode::GetOrCreateFrameNode("DragBar", ElementRegister::GetInstance()->MakeUniqueId(),
4184         []() { return AceType::MakeRefPtr<NavigationDragBarPattern>(); });
4185     auto dragBarLayoutProperty = dragBarNode->GetLayoutProperty();
4186     CHECK_NULL_VOID(dragBarLayoutProperty);
4187     auto theme = NavigationGetTheme();
4188     CHECK_NULL_VOID(theme);
4189     auto renderContext = dragBarNode->GetRenderContext();
4190     CHECK_NULL_VOID(renderContext);
4191     renderContext->UpdateBackBlurRadius(DRAG_BAR_BLUR_RADIUS);
4192     renderContext->UpdateBorderRadius(BorderRadiusProperty(DRAG_BAR_RADIUS));
4193     renderContext->UpdateZIndex(1);
4194     dragBarNode->MarkModifyDone();
4195     auto dragBarItem = CreateDragBarItemNode();
4196     dragBarItem->MountToParent(dragBarNode);
4197     dragBarNode->MountToParent(navigationGroupNode);
4198     navigationGroupNode->SetDragBarNode(dragBarNode);
4199 
4200     auto dragBarPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
4201     CHECK_NULL_VOID(dragBarPattern);
4202     dragBarPattern->UpdateDefaultColor();
4203 }
4204 
CreateDragBarItemNode()4205 RefPtr<FrameNode> NavigationPattern::CreateDragBarItemNode()
4206 {
4207     auto dragBarItemNode = FrameNode::GetOrCreateFrameNode("DragBarItem",
4208         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<Pattern>(); });
4209     auto dragBarItemLayoutProperty = dragBarItemNode->GetLayoutProperty();
4210     CHECK_NULL_RETURN(dragBarItemLayoutProperty, nullptr);
4211     dragBarItemLayoutProperty->UpdateAlignment(Alignment::CENTER);
4212     auto renderContext = dragBarItemNode->GetRenderContext();
4213     CHECK_NULL_RETURN(renderContext, nullptr);
4214     renderContext->UpdateZIndex(SECOND_ZINDEX_VALUE);
4215     renderContext->UpdateBorderRadius(BorderRadiusProperty(DRAG_BAR_ITEM_RADIUS));
4216     dragBarItemNode->MarkModifyDone();
4217     return dragBarItemNode;
4218 }
4219 
GetProxyById(uint64_t id) const4220 RefPtr<NavigationTransitionProxy> NavigationPattern::GetProxyById(uint64_t id) const
4221 {
4222     for (auto proxy : proxyList_) {
4223         if (proxy && proxy->GetProxyId() == id) {
4224             return proxy;
4225         }
4226     }
4227     return nullptr;
4228 }
4229 
RemoveProxyById(uint64_t id)4230 void NavigationPattern::RemoveProxyById(uint64_t id)
4231 {
4232     for (auto it = proxyList_.begin(); it != proxyList_.end(); ++it) {
4233         if (*it && (*it)->GetProxyId() == id) {
4234             it = proxyList_.erase(it);
4235             return;
4236         }
4237     }
4238 }
4239 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)4240 void NavigationPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
4241 {
4242     if (touchEvent_) {
4243         return;
4244     }
4245     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
4246         auto pattern = weak.Upgrade();
4247         CHECK_NULL_VOID(pattern);
4248         pattern->HandleTouchEvent(info);
4249     };
4250     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
4251     gestureHub->AddTouchEvent(touchEvent_);
4252 }
4253 
HandleTouchEvent(const TouchEventInfo & info)4254 void NavigationPattern::HandleTouchEvent(const TouchEventInfo& info)
4255 {
4256     auto touchType = info.GetTouches().front().GetTouchType();
4257     if (touchType == TouchType::DOWN) {
4258         HandleTouchDown();
4259     }
4260     if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
4261         HandleTouchUp();
4262     }
4263 }
4264 
HandleTouchDown()4265 void NavigationPattern::HandleTouchDown()
4266 {
4267     auto dragBarNode = GetDragBarNode();
4268     CHECK_NULL_VOID(dragBarNode);
4269     auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
4270     CHECK_NULL_VOID(dragPattern);
4271     dragPattern->UpdateActiveColor();
4272 
4273     auto dividerNode = GetDividerNode();
4274     CHECK_NULL_VOID(dividerNode);
4275     auto dividerRenderContext = dividerNode->GetRenderContext();
4276     CHECK_NULL_VOID(dividerRenderContext);
4277     auto theme = NavigationGetTheme();
4278     CHECK_NULL_VOID(theme);
4279     NG::Gradient gradient;
4280     gradient.CreateGradientWithType(NG::GradientType::LINEAR);
4281     gradient.AddColor(CreatePercentGradientColor(0, theme->GetDviderLightBlueColor()));
4282     gradient.AddColor(CreatePercentGradientColor(HALF_POSITION, theme->GetDviderDarkBlueColor()));
4283     gradient.AddColor(CreatePercentGradientColor(END_POSITION, theme->GetDviderLightBlueColor()));
4284     dividerRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
4285     dividerRenderContext->UpdateLinearGradient(gradient);
4286 }
4287 
HandleTouchUp()4288 void NavigationPattern::HandleTouchUp()
4289 {
4290     auto dragBarNode = GetDragBarNode();
4291     CHECK_NULL_VOID(dragBarNode);
4292     auto dragPattern = dragBarNode->GetPattern<NavigationDragBarPattern>();
4293     CHECK_NULL_VOID(dragPattern);
4294     dragPattern->UpdateDefaultColor();
4295 
4296     auto theme = NavigationGetTheme();
4297     CHECK_NULL_VOID(theme);
4298     auto dividerNode = GetDividerNode();
4299     CHECK_NULL_VOID(dividerNode);
4300     NG::Gradient gradient;
4301     gradient.CreateGradientWithType(NG::GradientType::LINEAR);
4302     gradient.AddColor(CreatePercentGradientColor(0, Color::TRANSPARENT));
4303     dividerNode->GetRenderContext()->UpdateLinearGradient(gradient);
4304     dividerNode->GetRenderContext()->UpdateBackgroundColor(theme->GetNavigationDividerColor());
4305 }
4306 
CheckContentNeedMeasure(const RefPtr<FrameNode> & node)4307 void NavigationPattern::CheckContentNeedMeasure(const RefPtr<FrameNode>& node)
4308 {
4309     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(node);
4310     CHECK_NULL_VOID(navigationNode);
4311     auto navigationLayoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
4312     CHECK_NULL_VOID(navigationLayoutProperty);
4313     if (!NavigationLayoutAlgorithm::IsAutoHeight(navigationLayoutProperty)) {
4314         return;
4315     }
4316     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Navigation height is auto, content need to measure after pushAnimation ends");
4317     auto contentNode = navigationNode->GetContentNode();
4318     CHECK_NULL_VOID(contentNode);
4319     contentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4320 }
4321 
CloseLongPressDialog()4322 void NavigationPattern::CloseLongPressDialog()
4323 {
4324     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4325     CHECK_NULL_VOID(hostNode);
4326     auto pipeline = hostNode->GetContext();
4327     CHECK_NULL_VOID(pipeline);
4328     auto overlayManager = pipeline->GetOverlayManager();
4329     CHECK_NULL_VOID(overlayManager);
4330 
4331     auto navBarOrHomeDestNode =
4332         AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
4333     CHECK_NULL_VOID(navBarOrHomeDestNode);
4334     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarOrHomeDestNode->GetTitleBarNode());
4335     CHECK_NULL_VOID(titleBarNode);
4336     auto titleBarPattern = AceType::DynamicCast<TitleBarPattern>(titleBarNode->GetPattern());
4337     CHECK_NULL_VOID(titleBarPattern);
4338     auto backButtonDialogNode = titleBarPattern->GetBackButtonDialogNode();
4339     if (backButtonDialogNode) {
4340         overlayManager->CloseDialog(backButtonDialogNode);
4341         titleBarPattern->SetBackButtonDialogNode(nullptr);
4342     }
4343 
4344     auto menuItemDialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
4345     if (menuItemDialogNode) {
4346         overlayManager->CloseDialog(menuItemDialogNode);
4347         titleBarPattern->SetLargeFontPopUpDialogNode(nullptr);
4348     }
4349 
4350     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(navBarOrHomeDestNode->GetToolBarNode());
4351     CHECK_NULL_VOID(toolBarNode);
4352     auto toolBarPattern = AceType::DynamicCast<NavToolbarPattern>(toolBarNode->GetPattern());
4353     CHECK_NULL_VOID(toolBarPattern);
4354     auto toolBarItemDialogNode = toolBarPattern->GetDialogNode();
4355     if (toolBarItemDialogNode) {
4356         overlayManager->CloseDialog(toolBarItemDialogNode);
4357         toolBarPattern->SetToolBarItemDialogNode(nullptr);
4358     }
4359 }
4360 
FindInCurStack(const RefPtr<FrameNode> & navDestinationNode)4361 bool NavigationPattern::FindInCurStack(const RefPtr<FrameNode>& navDestinationNode)
4362 {
4363     const auto& navdestinationNodes = GetAllNavDestinationNodes();
4364     for (auto navdestination : navdestinationNodes) {
4365         if (navDestinationNode == NavigationGroupNode::GetNavDestinationNode(navdestination.second)) {
4366             return true;
4367         }
4368     }
4369     return false;
4370 }
4371 
SetMouseStyle(MouseFormat format)4372 void NavigationPattern::SetMouseStyle(MouseFormat format)
4373 {
4374     auto host = GetHost();
4375     CHECK_NULL_VOID(host);
4376     auto pipeline = host->GetContextWithCheck();
4377     CHECK_NULL_VOID(pipeline);
4378     auto frameNodeId = host->GetId();
4379     int32_t windowId = static_cast<int32_t>(pipeline->GetFocusWindowId());
4380 #ifdef WINDOW_SCENE_SUPPORTED
4381     windowId = static_cast<int32_t>(WindowSceneHelper::GetFocusSystemWindowId(host));
4382 #endif
4383     pipeline->SetMouseStyleHoldNode(frameNodeId);
4384     pipeline->ChangeMouseStyle(frameNodeId, format, windowId);
4385     pipeline->FreeMouseStyleHoldNode(frameNodeId);
4386 }
4387 
OnAvoidInfoChange(const ContainerModalAvoidInfo & info)4388 void NavigationPattern::OnAvoidInfoChange(const ContainerModalAvoidInfo& info)
4389 {
4390     if (!isFullPageNavigation_) {
4391         return;
4392     }
4393     MarkAllNavDestinationDirtyIfNeeded(GetHost(), true);
4394 }
4395 
RegisterAvoidInfoChangeListener(const RefPtr<FrameNode> & hostNode)4396 void NavigationPattern::RegisterAvoidInfoChangeListener(const RefPtr<FrameNode>& hostNode)
4397 {
4398     CHECK_NULL_VOID(hostNode);
4399     auto pipeline = hostNode->GetContext();
4400     CHECK_NULL_VOID(pipeline);
4401     auto mgr = pipeline->GetAvoidInfoManager();
4402     CHECK_NULL_VOID(mgr);
4403     mgr->AddAvoidInfoListener(WeakClaim(this));
4404 }
4405 
UnregisterAvoidInfoChangeListener(const RefPtr<FrameNode> & hostNode)4406 void NavigationPattern::UnregisterAvoidInfoChangeListener(const RefPtr<FrameNode>& hostNode)
4407 {
4408     CHECK_NULL_VOID(hostNode);
4409     auto pipeline = hostNode->GetContext();
4410     CHECK_NULL_VOID(pipeline);
4411     auto mgr = pipeline->GetAvoidInfoManager();
4412     CHECK_NULL_VOID(mgr);
4413     mgr->RemoveAvoidInfoListener(WeakClaim(this));
4414 }
4415 
MarkAllNavDestinationDirtyIfNeeded(const RefPtr<FrameNode> & hostNode,bool skipCheck)4416 void NavigationPattern::MarkAllNavDestinationDirtyIfNeeded(const RefPtr<FrameNode>& hostNode, bool skipCheck)
4417 {
4418     auto groupNode = AceType::DynamicCast<NavigationGroupNode>(hostNode);
4419     CHECK_NULL_VOID(groupNode);
4420     if (!skipCheck) {
4421         auto pipeline = groupNode->GetContext();
4422         CHECK_NULL_VOID(pipeline);
4423         auto avoidInfoMgr = pipeline->GetAvoidInfoManager();
4424         CHECK_NULL_VOID(avoidInfoMgr);
4425         if (!avoidInfoMgr->NeedAvoidContainerModal()) {
4426             return;
4427         }
4428     }
4429 
4430     auto contentNode = AceType::DynamicCast<FrameNode>(groupNode->GetContentNode());
4431     CHECK_NULL_VOID(contentNode);
4432     auto& childrens = contentNode->GetChildren();
4433     for (auto& child : childrens) {
4434         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(child);
4435         if (!navDestination) {
4436             continue;
4437         }
4438         if (!navDestination->IsVisible()) {
4439             navDestination->SetNeedForceMeasure(true);
4440             continue;
4441         }
4442         navDestination->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
4443         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
4444         if (titleBarNode) {
4445             titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
4446         }
4447     }
4448 }
4449 
FireNavigationLifecycle(const RefPtr<UINode> & uiNode,NavDestinationLifecycle lifecycle,NavDestinationActiveReason reason)4450 void NavigationPattern::FireNavigationLifecycle(const RefPtr<UINode>& uiNode, NavDestinationLifecycle lifecycle,
4451     NavDestinationActiveReason reason)
4452 {
4453     auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
4454     CHECK_NULL_VOID(frameNode);
4455     auto context = frameNode->GetContextRefPtr();
4456     CHECK_NULL_VOID(context);
4457     auto navigationManager = context->GetNavigationManager();
4458     CHECK_NULL_VOID(navigationManager);
4459     auto navigationIds = navigationManager->FindNavigationInTargetParent(frameNode->GetId());
4460     for (auto navigationId: navigationIds) {
4461         auto navigation = AceType::DynamicCast<NavigationGroupNode>(
4462             FrameNode::GetFrameNode(V2::NAVIGATION_VIEW_ETS_TAG, navigationId));
4463         if (!navigation) {
4464             continue;
4465         }
4466         auto pattern = navigation->GetPattern<NavigationPattern>();
4467         if (!pattern) {
4468             continue;
4469         }
4470         auto navigationStack = pattern->GetNavigationStack();
4471         if (navigationStack) {
4472             pattern->NotifyDestinationLifecycle(AceType::DynamicCast<NavDestinationGroupNode>(
4473                 NavigationGroupNode::GetNavDestinationNode(navigationStack->Get())), lifecycle, reason);
4474         }
4475     }
4476 }
4477 
GenerateLastStandardPage(NavPathList & navPathList)4478 void NavigationPattern::GenerateLastStandardPage(NavPathList& navPathList)
4479 {
4480     int64_t lastPageIndex = static_cast<int64_t>(navPathList.size()) - 1;
4481     // if top page is nullptr or is dialog node, we need to generate node util standard page is found.
4482     while (lastPageIndex >= 0 &&
4483         (navPathList[lastPageIndex].second == nullptr || !IsStandardPage(navPathList[lastPageIndex].second))) {
4484         auto pageNode = navPathList[lastPageIndex].second;
4485         // existed dialog node is no need to generate
4486         bool isExistedNode = (pageNode != nullptr);
4487         if (!pageNode && !GenerateUINodeByIndex(lastPageIndex, pageNode)) {
4488             std::string replacedName;
4489             int32_t replacedIndex = -1;
4490             if (navigationStack_->CheckIsReplacedDestination(lastPageIndex, replacedName, replacedIndex)) {
4491                 navigationStack_->SetRecoveryFromReplaceDestination(lastPageIndex, false);
4492                 continue;
4493             }
4494             navPathList.erase(navPathList.begin() + lastPageIndex);
4495             lastPageIndex--;
4496             continue;
4497         }
4498         navPathList[lastPageIndex].second = pageNode;
4499         auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
4500             NavigationGroupNode::GetNavDestinationNode(pageNode));
4501         if (!isExistedNode && navDestinationNode && navigationStack_->GetIsForceSet(lastPageIndex)) {
4502             navigationStack_->ResetIsForceSetFlag(lastPageIndex);
4503         }
4504         if (navDestinationNode && navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
4505             break;
4506         }
4507         lastPageIndex--;
4508     }
4509 }
4510 
IsStandardPage(const RefPtr<UINode> & uiNode) const4511 bool NavigationPattern::IsStandardPage(const RefPtr<UINode>& uiNode) const
4512 {
4513     auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
4514         NavigationGroupNode::GetNavDestinationNode(uiNode));
4515     CHECK_NULL_RETURN(navDestinationNode, false);
4516     return navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD;
4517 }
4518 
FindNavDestinationNodeInPreList(const uint64_t navDestinationId) const4519 RefPtr<UINode> NavigationPattern::FindNavDestinationNodeInPreList(const uint64_t navDestinationId) const
4520 {
4521     CHECK_NULL_RETURN(navigationStack_, nullptr);
4522     auto preNavDestinationList = navigationStack_->GetPreNavPathList();
4523     for (auto preNavDestinationInfo : preNavDestinationList) {
4524         auto preNavDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(
4525             NavigationGroupNode::GetNavDestinationNode(preNavDestinationInfo.second));
4526         CHECK_NULL_CONTINUE(preNavDestinationNode);
4527         auto pattern = preNavDestinationNode->GetPattern<NavDestinationPattern>();
4528         CHECK_NULL_CONTINUE(pattern);
4529         auto preId = pattern->GetNavDestinationId();
4530         if (preId == navDestinationId) {
4531             return preNavDestinationInfo.second;
4532         }
4533     }
4534     return nullptr;
4535 }
4536 
ClearRecoveryList()4537 void NavigationPattern::ClearRecoveryList()
4538 {
4539     if (!isFinishInteractiveAnimation_) {
4540         return;
4541     }
4542     CHECK_NULL_VOID(navigationStack_);
4543     navigationStack_->ClearRecoveryList();
4544 }
4545 
FireOnNewParam(const RefPtr<UINode> & uiNode)4546 void NavigationPattern::FireOnNewParam(const RefPtr<UINode>& uiNode)
4547 {
4548     CHECK_NULL_VOID(uiNode);
4549     auto navDestination = DynamicCast<NavDestinationGroupNode>(NavigationGroupNode::GetNavDestinationNode(uiNode));
4550     CHECK_NULL_VOID(navDestination);
4551     auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
4552     CHECK_NULL_VOID(navDestinationPattern);
4553     auto navPathInfo = navDestinationPattern->GetNavPathInfo();
4554     CHECK_NULL_VOID(navPathInfo);
4555     auto eventHub = navDestination->GetOrCreateEventHub<NavDestinationEventHub>();
4556     CHECK_NULL_VOID(eventHub);
4557     eventHub->FireOnNewParam(navPathInfo->GetParamObj());
4558 }
4559 
GetVisibleNodes(bool isPre,std::vector<WeakPtr<NavDestinationNodeBase>> & visibleNodes)4560 void NavigationPattern::GetVisibleNodes(bool isPre, std::vector<WeakPtr<NavDestinationNodeBase>>& visibleNodes)
4561 {
4562     visibleNodes.clear();
4563     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4564     CHECK_NULL_VOID(navigationNode);
4565     CHECK_NULL_VOID(navigationStack_);
4566     const auto& pathList = isPre ?
4567         navigationStack_->GetPreNavPathList() : navigationStack_->GetAllNavDestinationNodes();
4568     int32_t lastStandardIndex = navigationNode->GetLastStandardIndex();
4569     if (lastStandardIndex < 0) {
4570         auto navBarOrHomeDest =
4571             AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
4572         if (navBarOrHomeDest) {
4573             visibleNodes.push_back(WeakPtr(navBarOrHomeDest));
4574         }
4575         lastStandardIndex = 0;
4576     }
4577     for (int32_t idx = lastStandardIndex; idx < static_cast<int32_t>(pathList.size()); ++idx) {
4578         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
4579             NavigationGroupNode::GetNavDestinationNode(pathList[idx].second));
4580         if (!node) {
4581             continue;
4582         }
4583         visibleNodes.push_back(WeakPtr(node));
4584     }
4585 }
4586 
CalcRotateAngleWithDisplayOrientation(DisplayOrientation curOri,DisplayOrientation targetOri)4587 std::optional<int32_t> NavigationPattern::CalcRotateAngleWithDisplayOrientation(
4588     DisplayOrientation curOri, DisplayOrientation targetOri)
4589 {
4590     if (curOri == targetOri) {
4591         return std::nullopt;
4592     }
4593     if (!IsValidDisplayOrientation(curOri) || !IsValidDisplayOrientation(targetOri)) {
4594         return std::nullopt;
4595     }
4596 
4597     auto curAngle = ConvertDisplayOrientationToRotationAngle(curOri);
4598     auto targetAngle = ConvertDisplayOrientationToRotationAngle(targetOri);
4599     int32_t rotationAngle = targetAngle - curAngle;
4600     if (rotationAngle < 0) {
4601         rotationAngle += FULL_CIRCLE_ANGLE;
4602     }
4603     rotationAngle = rotationAngle % FULL_CIRCLE_ANGLE;
4604     return rotationAngle;
4605 }
4606 
UpdatePageViewportConfigIfNeeded(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & topDestination)4607 void NavigationPattern::UpdatePageViewportConfigIfNeeded(const RefPtr<NavDestinationGroupNode>& preTopDestination,
4608     const RefPtr<NavDestinationGroupNode>& topDestination)
4609 {
4610     if (!IsPageLevelConfigEnabled()) {
4611         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "conditions are not met, don't update PageViewportConfig");
4612         return;
4613     }
4614 
4615     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4616     CHECK_NULL_VOID(navigationNode);
4617     auto context = navigationNode->GetContext();
4618     CHECK_NULL_VOID(context);
4619     auto container = Container::GetContainer(context->GetInstanceId());
4620     CHECK_NULL_VOID(container);
4621     auto manager = context->GetWindowManager();
4622     CHECK_NULL_VOID(manager);
4623 
4624     std::vector<WeakPtr<NavDestinationNodeBase>> newVisibleNodes;
4625     GetVisibleNodes(false, newVisibleNodes);
4626     if (preVisibleNodes_.empty() || newVisibleNodes.empty()) {
4627         return;
4628     }
4629 
4630     auto preFirstVisibleNode = preVisibleNodes_[0].Upgrade();
4631     auto curFirstVisibleNode = newVisibleNodes[0].Upgrade();
4632     if (!preFirstVisibleNode || !curFirstVisibleNode || preFirstVisibleNode == curFirstVisibleNode) {
4633         return;
4634     }
4635 
4636     auto preNodeOri = preFirstVisibleNode->GetOrientation();
4637     auto curNodeOri = curFirstVisibleNode->GetOrientation();
4638     if (curNodeOri == preNodeOri) {
4639         return;
4640     }
4641 
4642     auto statusBarConfig = curFirstVisibleNode->GetStatusBarConfig();
4643     auto navIndicatorConfig = curFirstVisibleNode->GetNavigationIndicatorConfig();
4644     std::optional<bool> enableStatusBar;
4645     std::optional<bool> statusBarAnimated;
4646     if (statusBarConfig.has_value()) {
4647         enableStatusBar = statusBarConfig.value().first;
4648         statusBarAnimated = statusBarConfig.value().second;
4649     }
4650     std::optional<bool> enableNavIndicator;
4651     if (navIndicatorConfig.has_value()) {
4652         enableNavIndicator = navIndicatorConfig.value();
4653     }
4654     auto currConfig = manager->GetCurrentViewportConfig();
4655     auto config = manager->GetTargetViewportConfig(curNodeOri, enableStatusBar, statusBarAnimated, enableNavIndicator);
4656     if (!currConfig || !config) {
4657         return;
4658     }
4659 
4660     auto curDisplayOrientation = container->GetCurrentDisplayOrientation();
4661     auto targetDisplayOrientation = config->GetOrientation();
4662     auto angle = CalcRotateAngleWithDisplayOrientation(curDisplayOrientation, targetDisplayOrientation);
4663     if (!angle.has_value()) {
4664         return;
4665     }
4666 
4667     auto pageNode = AceType::DynamicCast<PageNode>(pageNode_.Upgrade());
4668     if (pageNode) {
4669         auto pageConfig = pageNode->GetPageViewportConfig();
4670         if (!pageConfig) {
4671             pageNode->SetPageViewportConfig(currConfig->Clone());
4672         }
4673     }
4674     if (!viewportConfig_) {
4675         SetPageViewportConfig(currConfig->Clone());
4676     }
4677 
4678     for (auto& weakNode : preVisibleNodes_) {
4679         auto node = weakNode.Upgrade();
4680         CHECK_NULL_CONTINUE(node);
4681         auto preConfig = node->GetPageViewportConfig();
4682         if (!preConfig) {
4683             node->SetPageViewportConfig(currConfig->Clone());
4684             node->SetPageRotateAngle(ROTATION_0);
4685         }
4686     }
4687     for (auto& weakNode : newVisibleNodes) {
4688         auto node = weakNode.Upgrade();
4689         CHECK_NULL_CONTINUE(node);
4690         node->SetPageViewportConfig(config->Clone());
4691         node->SetPageRotateAngle(angle);
4692         node->SetIsRotated(false);
4693     }
4694 }
4695 
IsPageLevelConfigEnabled(bool considerSize)4696 bool NavigationPattern::IsPageLevelConfigEnabled(bool considerSize)
4697 {
4698     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_NINETEEN)) {
4699         return false;
4700     }
4701 
4702     if (!IsEquivalentToStackMode()) {
4703         return false;
4704     }
4705     if (considerSize && !isFullPageNavigation_) {
4706         return false;
4707     }
4708     if (pageNode_.Upgrade() == nullptr) {
4709         return false;
4710     }
4711 
4712     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4713     CHECK_NULL_RETURN(navigationNode, false);
4714     auto context = navigationNode->GetContext();
4715     CHECK_NULL_RETURN(context, false);
4716     auto manager = context->GetWindowManager();
4717     CHECK_NULL_RETURN(manager, false);
4718     auto container = Container::GetContainer(context->GetInstanceId());
4719     CHECK_NULL_RETURN(container, false);
4720     if (manager->IsPcOrPadFreeMultiWindowMode() || container->IsUIExtensionWindow()) {
4721         return false;
4722     }
4723 
4724     return container->IsMainWindow() && manager->IsFullScreenWindow();
4725 }
4726 
OnStartOneTransitionAnimation()4727 void NavigationPattern::OnStartOneTransitionAnimation()
4728 {
4729     runningTransitionCount_++;
4730 }
4731 
OnFinishOneTransitionAnimation()4732 void NavigationPattern::OnFinishOneTransitionAnimation()
4733 {
4734     runningTransitionCount_--;
4735     if (runningTransitionCount_ == 0) {
4736         OnAllTransitionAnimationFinish();
4737     }
4738 }
4739 
GetAllNodes(std::vector<WeakPtr<NavDestinationNodeBase>> & invisibleNodes,std::vector<WeakPtr<NavDestinationNodeBase>> & visibleNodes)4740 void NavigationPattern::GetAllNodes(
4741     std::vector<WeakPtr<NavDestinationNodeBase>>& invisibleNodes,
4742     std::vector<WeakPtr<NavDestinationNodeBase>>& visibleNodes)
4743 {
4744     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4745     CHECK_NULL_VOID(navigationNode);
4746     auto stackNodes = GetAllNavDestinationNodes();
4747     int32_t lastStandardIndex = navigationNode->GetLastStandardIndex();
4748     auto navBarOrHomeDest =
4749         AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
4750     if (navBarOrHomeDest) {
4751         if (lastStandardIndex < 0) {
4752             visibleNodes.push_back(navBarOrHomeDest);
4753         } else {
4754             invisibleNodes.push_back(navBarOrHomeDest);
4755         }
4756     }
4757     for (int32_t idx = 0; idx < static_cast<int32_t>(stackNodes.size()); ++idx) {
4758         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
4759             NavigationGroupNode::GetNavDestinationNode(stackNodes[idx].second));
4760         if (!node) {
4761             continue;
4762         }
4763         if (idx < lastStandardIndex) {
4764             invisibleNodes.push_back(node);
4765         } else {
4766             visibleNodes.push_back(node);
4767         }
4768     }
4769 }
4770 
OnAllTransitionAnimationFinish()4771 void NavigationPattern::OnAllTransitionAnimationFinish()
4772 {
4773     bool animationAborted = isTransitionAnimationAborted_;
4774     isTransitionAnimationAborted_ = false;
4775     if (!IsPageLevelConfigEnabled()) {
4776         ClearPageAndNavigationConfig();
4777         return;
4778     }
4779 
4780     ShowOrRestoreSystemBarIfNeeded();
4781     std::vector<WeakPtr<NavDestinationNodeBase>> invisibleNodes;
4782     std::vector<WeakPtr<NavDestinationNodeBase>> visibleNodes;
4783     GetAllNodes(invisibleNodes, visibleNodes);
4784     for (auto& weakNode : invisibleNodes) {
4785         auto node = weakNode.Upgrade();
4786         CHECK_NULL_CONTINUE(node);
4787         node->RestoreRenderContext();
4788     }
4789 
4790     if (visibleNodes.empty()) {
4791         ClearPageAndNavigationConfig();
4792         return;
4793     }
4794     auto firstVisibleNode = visibleNodes[0].Upgrade();
4795     CHECK_NULL_VOID(firstVisibleNode);
4796     auto context = firstVisibleNode->GetContext();
4797     CHECK_NULL_VOID(context);
4798     auto taskExecutor = context->GetTaskExecutor();
4799     CHECK_NULL_VOID(taskExecutor);
4800     auto navigationMgr = context->GetNavigationManager();
4801     CHECK_NULL_VOID(navigationMgr);
4802     auto windowMgr = context->GetWindowManager();
4803     CHECK_NULL_VOID(windowMgr);
4804     auto targetOrientation = firstVisibleNode->GetOrientation();
4805     auto restoreTask = [nodes = std::move(visibleNodes), weakPattern = WeakClaim(this), animationAborted]() {
4806         ACE_SCOPED_TRACE("NavigationPattern restoreTask");
4807         for (auto& weakNode : nodes) {
4808             auto node = weakNode.Upgrade();
4809             CHECK_NULL_CONTINUE(node);
4810             node->RestoreRenderContext();
4811         }
4812 
4813         auto pattern = weakPattern.Upgrade();
4814         CHECK_NULL_VOID(pattern);
4815         pattern->ClearPageAndNavigationConfig();
4816         if (!animationAborted) {
4817             return;
4818         }
4819         auto pageNode = pattern->GetNavBasePageNode();
4820         CHECK_NULL_VOID(pageNode);
4821         auto geometryNode = pageNode->GetGeometryNode();
4822         CHECK_NULL_VOID(geometryNode);
4823         geometryNode->ResetParentLayoutConstraint();
4824     };
4825     if (!windowMgr->IsSetOrientationNeeded(targetOrientation)) {
4826         restoreTask();
4827         return;
4828     }
4829     navigationMgr->AddBeforeOrientationChangeTask(std::move(restoreTask));
4830     windowMgr->SetRequestedOrientation(targetOrientation, false);
4831 }
4832 
UpdatePageLevelConfigForSizeChanged()4833 void NavigationPattern::UpdatePageLevelConfigForSizeChanged()
4834 {
4835     if (!IsPageLevelConfigEnabled(false)) {
4836         return;
4837     }
4838     if (runningTransitionCount_ > 0) {
4839         if (isFullPageNavigation_) {
4840             return;
4841         }
4842         // full page -> partial page
4843         std::vector<WeakPtr<NavDestinationNodeBase>> invisibleNodes;
4844         std::vector<WeakPtr<NavDestinationNodeBase>> visibleNodes;
4845         GetAllNodes(invisibleNodes, visibleNodes);
4846         for (auto& weakNode : invisibleNodes) {
4847             auto node = weakNode.Upgrade();
4848             CHECK_NULL_CONTINUE(node);
4849             node->RestoreRenderContext();
4850         }
4851         for (auto& weakNode : visibleNodes) {
4852             auto node = weakNode.Upgrade();
4853             CHECK_NULL_CONTINUE(node);
4854             node->RestoreRenderContext();
4855             node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
4856         }
4857         return;
4858     }
4859 
4860     UpdatePageLevelConfigForSizeChangedWhenNoAnimation();
4861 }
4862 
UpdatePageLevelConfigForSizeChangedWhenNoAnimation()4863 void NavigationPattern::UpdatePageLevelConfigForSizeChangedWhenNoAnimation()
4864 {
4865     auto lastNode = GetLastStandardNodeOrNavBar();
4866     if (!lastNode) {
4867         return;
4868     }
4869 
4870     auto context = lastNode->GetContext();
4871     CHECK_NULL_VOID(context);
4872     auto mgr = context->GetWindowManager();
4873     CHECK_NULL_VOID(mgr);
4874 
4875     auto statusBarConfig = lastNode->GetStatusBarConfig();
4876     std::optional<bool> enableStatusBar;
4877     std::optional<bool> statusBarAnimated;
4878     if (isFullPageNavigation_ && statusBarConfig.has_value()) {
4879         enableStatusBar = statusBarConfig.value().first;
4880         statusBarAnimated = statusBarConfig.value().second;
4881     }
4882     mgr->SetWindowSystemBarEnabled(SystemBarType::STATUS, enableStatusBar, statusBarAnimated);
4883 
4884     auto navIndicatorConfig = lastNode->GetNavigationIndicatorConfig();
4885     std::optional<bool> enableNavIndicator;
4886     if (isFullPageNavigation_ && navIndicatorConfig.has_value()) {
4887         enableNavIndicator = navIndicatorConfig.value();
4888     }
4889     mgr->SetWindowSystemBarEnabled(SystemBarType::NAVIGATION_INDICATOR, enableNavIndicator, std::nullopt);
4890 
4891     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4892     CHECK_NULL_VOID(host);
4893     auto homeDest = AceType::DynamicCast<NavDestinationNodeBase>(host->GetHomeDestinationNode());
4894     if (lastNode != homeDest) {
4895         return;
4896     }
4897     auto windowMgr = context->GetWindowManager();
4898     CHECK_NULL_VOID(windowMgr);
4899     context->AddAfterLayoutTask([weakNode = WeakPtr(lastNode), weakMgr = WeakPtr(windowMgr)]() {
4900         auto node = weakNode.Upgrade();
4901         CHECK_NULL_VOID(node);
4902         auto manager = weakMgr.Upgrade();
4903         CHECK_NULL_VOID(manager);
4904         auto orientation = node->GetOrientation();
4905         manager->SetRequestedOrientation(orientation, false);
4906     });
4907 }
4908 
GetLastStandardNodeOrNavBar()4909 RefPtr<NavDestinationNodeBase> NavigationPattern::GetLastStandardNodeOrNavBar()
4910 {
4911     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
4912     CHECK_NULL_RETURN(navigationNode, nullptr);
4913     auto stackNodes = GetAllNavDestinationNodes();
4914     int32_t lastStandardIndex = navigationNode->GetLastStandardIndex();
4915     if (lastStandardIndex < 0) {
4916         return AceType::DynamicCast<NavDestinationNodeBase>(navigationNode->GetNavBarOrHomeDestinationNode());
4917     } else if (lastStandardIndex < static_cast<int32_t>(stackNodes.size())) {
4918         return AceType::DynamicCast<NavDestinationGroupNode>(
4919             NavigationGroupNode::GetNavDestinationNode(stackNodes[lastStandardIndex].second));
4920     } else {
4921         return nullptr;
4922     }
4923 }
4924 
HideSystemBarIfNeeded()4925 void NavigationPattern::HideSystemBarIfNeeded()
4926 {
4927     if (!IsPageLevelConfigEnabled()) {
4928         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "conditions are not met, don't enable/disable SystemBar");
4929         return;
4930     }
4931 
4932     auto lastNode = GetLastStandardNodeOrNavBar();
4933     if (!lastNode || !lastNode->IsSizeMatchNavigation()) {
4934         return;
4935     }
4936     auto context = lastNode->GetContext();
4937     CHECK_NULL_VOID(context);
4938     auto mgr = context->GetWindowManager();
4939     CHECK_NULL_VOID(mgr);
4940 
4941     auto statusBarConfig = lastNode->GetStatusBarConfig();
4942     if (statusBarConfig.has_value() && !statusBarConfig.value().first) {
4943         mgr->SetWindowSystemBarEnabled(SystemBarType::STATUS, false, statusBarConfig.value().second);
4944     }
4945     auto navIndicatorConfig = lastNode->GetNavigationIndicatorConfig();
4946     if (navIndicatorConfig.has_value() && !navIndicatorConfig.value()) {
4947         mgr->SetWindowSystemBarEnabled(SystemBarType::NAVIGATION_INDICATOR, false, false);
4948     }
4949 }
4950 
ShowOrRestoreSystemBarIfNeeded()4951 void NavigationPattern::ShowOrRestoreSystemBarIfNeeded()
4952 {
4953     if (!IsPageLevelConfigEnabled()) {
4954         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "conditions are not met, don't enable/disable SystemBar");
4955         return;
4956     }
4957 
4958     auto lastNode = GetLastStandardNodeOrNavBar();
4959     if (!lastNode) {
4960         return;
4961     }
4962     auto context = lastNode->GetContext();
4963     CHECK_NULL_VOID(context);
4964     auto mgr = context->GetWindowManager();
4965     CHECK_NULL_VOID(mgr);
4966 
4967     auto statusBarConfig = lastNode->GetStatusBarConfig();
4968     if (statusBarConfig.has_value()) {
4969         if (statusBarConfig.value().first) {
4970             // If NavDestination explicitly sets the statusBar to be enabled, then we enable the statusBar.
4971             std::optional<bool> enableStatusBar = true;
4972             std::optional<bool> animatedStatusBar = statusBarConfig.value().second;
4973             mgr->SetWindowSystemBarEnabled(SystemBarType::STATUS, enableStatusBar, animatedStatusBar);
4974         }
4975     } else {
4976         /**
4977          * Otherwise, Arkui informs the window subsystem that the page-level configuration of the statusBar
4978          * is no longer effective (after which the window decides whether to display the statuBar)
4979          */
4980         mgr->SetWindowSystemBarEnabled(SystemBarType::STATUS, std::nullopt, std::nullopt);
4981     }
4982     auto navIndicatorConfig = lastNode->GetNavigationIndicatorConfig();
4983     if (navIndicatorConfig.has_value()) {
4984         if (navIndicatorConfig.value()) {
4985             /**
4986              * If NavDestination explicitly sets the navigationIndicator to be enabled,
4987              * then we enable the navigationIndicator.
4988              */
4989             std::optional<bool> enableNavIndicator = true;
4990             mgr->SetWindowSystemBarEnabled(SystemBarType::NAVIGATION_INDICATOR, enableNavIndicator, std::nullopt);
4991         }
4992     } else {
4993         /**
4994          * Otherwise, Arkui informs the window subsystem that the page-level configuration of the navigationIndicator
4995          * is no longer effective (after which the window decides whether to display the navigationIndicator)
4996          */
4997         mgr->SetWindowSystemBarEnabled(SystemBarType::NAVIGATION_INDICATOR, std::nullopt, std::nullopt);
4998     }
4999 }
5000 
IsEquivalentToStackMode()5001 bool NavigationPattern::IsEquivalentToStackMode()
5002 {
5003     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5004     CHECK_NULL_RETURN(navigationNode, false);
5005     auto property = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
5006     CHECK_NULL_RETURN(property, false);
5007     auto userNavMode = property->GetUsrNavigationModeValue(NavigationMode::AUTO);
5008     auto hideNavBar = property->GetHideNavBarValue(false);
5009     if (userNavMode == NavigationMode::STACK || hideNavBar) {
5010         return true;
5011     }
5012     auto homeDest = AceType::DynamicCast<FrameNode>(navigationNode->GetHomeDestinationNode());
5013     if (homeDest) {
5014         return navigationMode_ == NavigationMode::STACK;
5015     }
5016     auto navBarNode = AceType::DynamicCast<FrameNode>(navigationNode->GetNavBarNode());
5017     CHECK_NULL_RETURN(navBarNode, false);
5018     auto navBarProperty = navBarNode->GetLayoutProperty();
5019     CHECK_NULL_RETURN(navBarProperty, false);
5020     auto geometry = navBarNode->GetGeometryNode();
5021     CHECK_NULL_RETURN(geometry, false);
5022     auto visibility = navBarProperty->GetVisibilityValue(VisibleType::VISIBLE);
5023     auto size = geometry->GetFrameSize();
5024     return visibility != VisibleType::VISIBLE || NearEqual(size.Width(), 0.0f) || NearEqual(size.Height(), 0.0f);
5025 }
5026 
CustomizeExpandSafeArea()5027 bool NavigationPattern::CustomizeExpandSafeArea()
5028 {
5029     auto host = GetHost();
5030     CHECK_NULL_RETURN(host, false);
5031     return RunCustomizeExpandIfNeeded(host);
5032 }
5033 
SetPageViewportConfig(const RefPtr<PageViewportConfig> & config)5034 void NavigationPattern::SetPageViewportConfig(const RefPtr<PageViewportConfig>& config)
5035 {
5036     CustomSafeAreaExpander::SetPageViewportConfig(config);
5037     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5038     CHECK_NULL_VOID(host);
5039     do {
5040         auto contentNode = AceType::DynamicCast<FrameNode>(host->GetContentNode());
5041         CHECK_NULL_BREAK(contentNode);
5042         auto contentPattern = contentNode->GetPattern<NavigationContentPattern>();
5043         CHECK_NULL_BREAK(contentPattern);
5044         contentPattern->SetPageViewportConfig(config ? config->Clone() : nullptr);
5045     } while (false);
5046 }
5047 
ClearPageAndNavigationConfig()5048 void NavigationPattern::ClearPageAndNavigationConfig()
5049 {
5050     auto pageNode = AceType::DynamicCast<PageNode>(pageNode_.Upgrade());
5051     if (pageNode) {
5052         pageNode->SetPageViewportConfig(nullptr);
5053     }
5054     SetPageViewportConfig(nullptr);
5055 }
5056 
UpdateNavigationStatus()5057 void NavigationPattern::UpdateNavigationStatus()
5058 {
5059     auto host = GetHost();
5060     CHECK_NULL_VOID(host);
5061     auto geometryNode = host->GetGeometryNode();
5062     CHECK_NULL_VOID(geometryNode);
5063     auto frameWidth = geometryNode->GetFrameSize().Width();
5064     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
5065     SetNavigationWidthToolBarManager(initNavBarWidth_, frameWidth - initNavBarWidth_ - dividerWidth, dividerWidth);
5066 }
5067 
SetNavigationWidthToolBarManager(float navBarWidth,float navDestWidth,float dividerWidth)5068 void NavigationPattern::SetNavigationWidthToolBarManager(float navBarWidth, float navDestWidth, float dividerWidth)
5069 {
5070     CHECK_NULL_VOID(toolbarManager_);
5071     toolbarManager_->SetNavigationNode(GetNavigationNode());
5072     auto navBarInfo = toolbarManager_->GetNavBarInfo();
5073     if (!NearEqual(navBarWidth, navBarInfo.width)) {
5074         navBarInfo.isShow = true;
5075         navBarInfo.width = navBarWidth;
5076         toolbarManager_->SetHasNavBar(true);
5077         toolbarManager_->SetNavBarInfo(navBarInfo);
5078         toolbarManager_->SetNavBarNode(GetNavBarNodeOrHomeDestination());
5079     }
5080     auto navDestInfo = toolbarManager_->GetNavDestInfo();
5081     if (!NearEqual(navDestWidth, navDestInfo.width)) {
5082         navDestInfo.isShow = true;
5083         navDestInfo.width = navDestWidth;
5084         toolbarManager_->SetHasNavDest(true);
5085         toolbarManager_->SetNavDestInfo(navDestInfo);
5086         toolbarManager_->SetNavDestNode(GetContentNode());
5087     }
5088     auto dividerInfo = toolbarManager_->GetNavBarDividerInfo();
5089     if (!NearEqual(dividerWidth, dividerInfo.width)) {
5090         dividerInfo.width = dividerWidth;
5091         toolbarManager_->SetNavBarDividerInfo(dividerInfo);
5092         toolbarManager_->SetNavBarDividerNode(GetDividerNode());
5093     }
5094 }
5095 
NavigationModifyDoneToolBarManager()5096 void NavigationPattern::NavigationModifyDoneToolBarManager()
5097 {
5098     CHECK_NULL_VOID(toolbarManager_);
5099     toolbarManager_->OnToolBarManagerModifyDone();
5100 }
5101 
SetToolbarManagerNavigationMode(NavigationMode mode)5102 void NavigationPattern::SetToolbarManagerNavigationMode(NavigationMode mode)
5103 {
5104     CHECK_NULL_VOID(toolbarManager_);
5105     auto navigationMode = toolbarManager_->GetNavigationMode();
5106     if (navigationMode != mode) {
5107         toolbarManager_->SetNavigationMode(mode);
5108         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "update navigationMode successful, new mode: %{public}d",
5109             static_cast<int>(mode));
5110     }
5111 }
5112 
HandleIntent(bool needTransition)5113 bool NavigationPattern::HandleIntent(bool needTransition)
5114 {
5115     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5116     CHECK_NULL_RETURN(host, false);
5117     auto context = host->GetContext();
5118     CHECK_NULL_RETURN(context, false);
5119     auto navigationManager = context->GetNavigationManager();
5120     CHECK_NULL_RETURN(navigationManager, false);
5121     auto navigationIntentInfo = navigationManager->GetNavigationIntentInfo();
5122     if (!navigationIntentInfo.has_value()) {
5123         return false;
5124     }
5125     if (navigationIntentInfo.value().navigationInspectorId != host->GetCurId()) {
5126         return false;
5127     }
5128     navigationManager->ResetNavigationIntentInfo();
5129     // add the intentInfo into navPathStack
5130     navigationStack_->PushIntentNavDestination(navigationIntentInfo.value().navDestinationName,
5131         navigationIntentInfo.value().param, needTransition && !navigationIntentInfo.value().isColdStart);
5132     return true;
5133 }
5134 
RegisterForceSplitListener(PipelineContext * context,int32_t nodeId)5135 void NavigationPattern::RegisterForceSplitListener(PipelineContext* context, int32_t nodeId)
5136 {
5137     CHECK_NULL_VOID(context);
5138     auto mgr = context->GetNavigationManager();
5139     CHECK_NULL_VOID(mgr);
5140     auto listener = [weakPattern = WeakClaim(this)]() {
5141         auto pattern = weakPattern.Upgrade();
5142         CHECK_NULL_VOID(pattern);
5143         auto hostNode = pattern->GetHost();
5144         CHECK_NULL_VOID(hostNode);
5145         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
5146     };
5147     mgr->AddForceSplitListener(nodeId, std::move(listener));
5148 }
5149 
UnregisterForceSplitListener(PipelineContext * context,int32_t nodeId)5150 void NavigationPattern::UnregisterForceSplitListener(PipelineContext* context, int32_t nodeId)
5151 {
5152     CHECK_NULL_VOID(context);
5153     auto mgr = context->GetNavigationManager();
5154     CHECK_NULL_VOID(mgr);
5155     mgr->RemoveForceSplitListener(nodeId);
5156 }
5157 
TryForceSplitIfNeeded(const SizeF & frameSize)5158 void NavigationPattern::TryForceSplitIfNeeded(const SizeF& frameSize)
5159 {
5160     /**
5161      * If do not support forced split,
5162      * or the force split navigation is not the current navigation,
5163      * return directly.
5164      */
5165     if (!GetIsTargetForceSplitNav()) {
5166         return;
5167     }
5168     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5169     auto context = hostNode->GetContext();
5170     CHECK_NULL_VOID(context);
5171     bool forceSplitSuccess = false;
5172     bool forceSplitUseNavBar = false;
5173     auto navManager = context->GetNavigationManager();
5174     CHECK_NULL_VOID(navManager);
5175     if (navManager->IsForceSplitEnable()) {
5176         /**
5177          * The force split mode must meet the following conditions to take effect:
5178          *   1. Belonging to the main window of the application
5179          *   2. Belonging to the main page of the application (excluding container model, popups, etc.)
5180          *   3. The application is in landscape mode or ignore orientation
5181          *   4. The application is not in split screen mode
5182          *   5. Navigation width greater than 600vp
5183          *   6. It belongs to the outermost Navigation or specified Navigation within the page
5184          */
5185         auto container = Container::GetContainer(context->GetInstanceId());
5186         CHECK_NULL_VOID(container);
5187         bool isMainWindow = container->IsMainWindow();
5188         bool isInAppMainPage = pageNode_.Upgrade() != nullptr;
5189         auto thresholdWidth = SPLIT_THRESHOLD_WIDTH.ConvertToPx();
5190         auto dipScale = context->GetDipScale();
5191         bool ignoreOrientation = navManager->GetIgnoreOrientation();
5192         auto orientation = SystemProperties::GetDeviceOrientation();
5193         auto windowManager = context->GetWindowManager();
5194         CHECK_NULL_VOID(windowManager);
5195         auto windowMode = windowManager->GetWindowMode();
5196         bool isInSplitScreenMode = windowMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
5197             windowMode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY;
5198         forceSplitSuccess = isMainWindow && isInAppMainPage &&
5199             (ignoreOrientation || orientation == DeviceOrientation::LANDSCAPE) &&
5200             thresholdWidth < frameSize.Width() && !isInSplitScreenMode;
5201         bool isNavBarValid = IsNavBarValid();
5202         forceSplitUseNavBar = forceSplitSuccess && isNavBarValid && navBarIsHome_;
5203         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "calc splitMode, isMainWindow:%{public}d, isInAppMainPage:%{public}d, "
5204             "isInSplitScreenMode:%{public}d, ignoreOrientation:%{public}d, orientation: %{public}s, "
5205             "dipScale: %{public}f, thresholdWidth: %{public}f, curWidth: %{public}f, isNavBarValid:%{public}d, "
5206             "navBarIsHome:%{public}d, forceSplitSuccess:%{public}d, forceSplitUseNavBar:%{public}d",
5207             isMainWindow, isInAppMainPage, isInSplitScreenMode, ignoreOrientation,
5208             DeviceOrientationToString(orientation), dipScale, thresholdWidth, frameSize.Width(), isNavBarValid,
5209             navBarIsHome_, forceSplitSuccess, forceSplitUseNavBar);
5210     }
5211     if (forceSplitSuccess == forceSplitSuccess_ && forceSplitUseNavBar_ == forceSplitUseNavBar) {
5212         return;
5213     }
5214     forceSplitSuccess_ = forceSplitSuccess;
5215     forceSplitUseNavBar_ = forceSplitUseNavBar;
5216     context->SetIsCurrentInForceSplitMode(forceSplitSuccess_);
5217     SwapNavDestinationAndProxyNode(true);
5218 }
5219 
IsNavBarValid()5220 bool NavigationPattern::IsNavBarValid()
5221 {
5222     /**
5223      * When NavBar is not hidden and its width is greater than 0,
5224      * it is considered that the NavBar is valid.
5225      */
5226     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5227     CHECK_NULL_RETURN(hostNode, false);
5228     auto property = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
5229     CHECK_NULL_RETURN(property, false);
5230     return !property->GetHideNavBarValue(false) &&
5231         (!userSetNavBarWidthFlag_ || GreatNotEqual(initNavBarWidthValue_.Value(), 0)) &&
5232         (GreatNotEqual(property->GetMaxNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH).Value(), 0));
5233 }
5234 
SwapNavDestinationAndProxyNode(bool needFireLifecycle)5235 void NavigationPattern::SwapNavDestinationAndProxyNode(bool needFireLifecycle)
5236 {
5237     if (forceSplitSuccess_ && !forceSplitUseNavBar_) {
5238         // switch to ForceSplit mode(use NavDestination as homepage or no homepage recognized)
5239         AdjustNodeForDestForceSplit(needFireLifecycle);
5240     } else {
5241         // switch to Non-forceSplit mode or ForceSplit mode but use NavBar as homepage.
5242         AdjustNodeForNonDestForceSplit(needFireLifecycle);
5243     }
5244 }
5245 
GetNavDestinationsAndHomeIndex(std::vector<RefPtr<NavDestinationGroupNode>> & destNodes,std::optional<int32_t> & homeIndex)5246 void NavigationPattern::GetNavDestinationsAndHomeIndex(
5247     std::vector<RefPtr<NavDestinationGroupNode>>& destNodes, std::optional<int32_t>& homeIndex)
5248 {
5249     homeIndex = std::nullopt;
5250     auto homeNode = homeNode_.Upgrade();
5251     const auto& stackNodePairs = GetAllNavDestinationNodes();
5252     for (int32_t idx = 0; idx < static_cast<int32_t>(stackNodePairs.size()); ++idx) {
5253         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
5254             NavigationGroupNode::GetNavDestinationNode(stackNodePairs[idx].second));
5255         CHECK_NULL_CONTINUE(node);
5256         auto curIdx = static_cast<int32_t>(destNodes.size());
5257         if (node == homeNode) {
5258             homeIndex = curIdx;
5259         }
5260         destNodes.push_back(node);
5261     }
5262 }
5263 
AdjustNodeForDestForceSplit(bool needFireLifecycle)5264 void NavigationPattern::AdjustNodeForDestForceSplit(bool needFireLifecycle)
5265 {
5266     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5267     CHECK_NULL_VOID(host);
5268     auto navProperty = host->GetLayoutProperty<NavigationLayoutProperty>();
5269     CHECK_NULL_VOID(navProperty);
5270     auto navBar = AceType::DynamicCast<FrameNode>(host->GetNavBarNode());
5271     CHECK_NULL_VOID(navBar);
5272     auto navBarProperty = navBar->GetLayoutProperty();
5273     CHECK_NULL_VOID(navBarProperty);
5274     auto navContentNode = AceType::DynamicCast<FrameNode>(host->GetContentNode());
5275     CHECK_NULL_VOID(navContentNode);
5276     auto navContentProperty = navContentNode->GetLayoutProperty();
5277     CHECK_NULL_VOID(navContentProperty);
5278     auto primaryContentNode = AceType::DynamicCast<FrameNode>(host->GetPrimaryContentNode());
5279     CHECK_NULL_VOID(primaryContentNode);
5280     auto primaryProperty = primaryContentNode->GetLayoutProperty();
5281     CHECK_NULL_VOID(primaryProperty);
5282     auto phNode = AceType::DynamicCast<FrameNode>(host->GetForceSplitPlaceHolderNode());
5283     CHECK_NULL_VOID(phNode);
5284     auto phProperty = phNode->GetLayoutProperty();
5285     CHECK_NULL_VOID(phProperty);
5286 
5287     auto prePrimaryNodes = primaryNodes_;
5288     primaryNodes_.clear();
5289     std::optional<int32_t> homeIndex;
5290     std::vector<RefPtr<NavDestinationGroupNode>> destNodes;
5291     bool hideNavBar = navProperty->GetHideNavBarValue(false);
5292     GetNavDestinationsAndHomeIndex(destNodes, homeIndex);
5293     if (destNodes.empty()) {
5294         navBarProperty->UpdateVisibility(hideNavBar ? VisibleType::INVISIBLE : VisibleType::VISIBLE);
5295         phProperty->UpdateVisibility(VisibleType::VISIBLE);
5296         primaryProperty->UpdateVisibility(VisibleType::INVISIBLE);
5297         navContentProperty->UpdateVisibility(VisibleType::INVISIBLE);
5298         return;
5299     }
5300 
5301     AdjustPrimaryAndProxyNodePosition(primaryContentNode, navContentNode, destNodes, homeIndex);
5302 
5303     ReorderPrimaryNodes(primaryContentNode, primaryNodes_);
5304 
5305     if (needFireLifecycle) {
5306         FirePrimaryNodesLifecycle(NavDestinationLifecycle::ON_SHOW);
5307     }
5308     if (primaryNodes_.empty()) {
5309         navBarProperty->UpdateVisibility(hideNavBar ? VisibleType::INVISIBLE : VisibleType::VISIBLE);
5310         primaryProperty->UpdateVisibility(VisibleType::INVISIBLE);
5311     } else {
5312         navBarProperty->UpdateVisibility(VisibleType::INVISIBLE);
5313         primaryProperty->UpdateVisibility(VisibleType::VISIBLE);
5314     }
5315 
5316     UpdatePrimaryContentIfNeeded(primaryContentNode, prePrimaryNodes);
5317     if (primaryNodes_.empty() || primaryNodes_.back().Upgrade() != destNodes.back()) {
5318         phProperty->UpdateVisibility(VisibleType::INVISIBLE);
5319         navContentProperty->UpdateVisibility(VisibleType::VISIBLE);
5320     } else {
5321         phProperty->UpdateVisibility(VisibleType::VISIBLE);
5322         navContentProperty->UpdateVisibility(VisibleType::INVISIBLE);
5323     }
5324 }
5325 
AdjustPrimaryAndProxyNodePosition(const RefPtr<FrameNode> & primaryContentNode,const RefPtr<FrameNode> & navContentNode,const std::vector<RefPtr<NavDestinationGroupNode>> & destNodes,std::optional<int32_t> homeIndex)5326 void NavigationPattern::AdjustPrimaryAndProxyNodePosition(
5327     const RefPtr<FrameNode>& primaryContentNode, const RefPtr<FrameNode>& navContentNode,
5328     const std::vector<RefPtr<NavDestinationGroupNode>>& destNodes, std::optional<int32_t> homeIndex)
5329 {
5330     int32_t nodeCount = static_cast<int32_t>(destNodes.size());
5331     if (homeIndex.has_value()) {
5332         for (int32_t index = 0; index < nodeCount; ++index) {
5333             auto node = destNodes[index];
5334             if (homeIndex.value() == index) {
5335                 ReplaceNodeWithProxyNodeIfNeeded(navContentNode, node);
5336                 primaryNodes_.push_back(node);
5337                 continue;
5338             }
5339             RestoreNodeFromProxyNodeIfNeeded(primaryContentNode, navContentNode, node);
5340         }
5341         return;
5342     }
5343     bool meetStandard = false;
5344     for (int32_t index = nodeCount - 1; index >= 0; --index) {
5345         auto node = destNodes[index];
5346         if (!meetStandard) {
5347             ReplaceNodeWithProxyNodeIfNeeded(navContentNode, node);
5348             primaryNodes_.insert(primaryNodes_.begin(), node);
5349             if (node->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
5350                 meetStandard = true;
5351             }
5352             continue;
5353         }
5354         RestoreNodeFromProxyNodeIfNeeded(primaryContentNode, navContentNode, node);
5355     }
5356 }
5357 
UpdatePrimaryContentIfNeeded(const RefPtr<FrameNode> & primaryContentNode,const std::vector<WeakPtr<NavDestinationGroupNode>> & prePrimaryNodes)5358 void NavigationPattern::UpdatePrimaryContentIfNeeded(const RefPtr<FrameNode>& primaryContentNode,
5359     const std::vector<WeakPtr<NavDestinationGroupNode>>& prePrimaryNodes)
5360 {
5361     CHECK_NULL_VOID(primaryContentNode);
5362     auto property = primaryContentNode->GetLayoutProperty();
5363     CHECK_NULL_VOID(property);
5364     property->UpdateVisibility(primaryNodes_.empty() ? VisibleType::INVISIBLE : VisibleType::VISIBLE);
5365 
5366     bool needMarkDirty = false;
5367     if (prePrimaryNodes.size() != primaryNodes_.size()) {
5368         needMarkDirty = true;
5369     } else {
5370         for (size_t idx = 0; idx < prePrimaryNodes.size(); ++idx) {
5371             auto preNode = prePrimaryNodes[idx].Upgrade();
5372             auto curNode = primaryNodes_[idx].Upgrade();
5373             if (preNode != curNode) {
5374                 needMarkDirty = true;
5375                 break;
5376             }
5377         }
5378     }
5379     if (needMarkDirty) {
5380         primaryContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
5381         primaryContentNode->MarkNeedSyncRenderTree();
5382     }
5383 }
5384 
AdjustNodeForNonDestForceSplit(bool needFireLifecycle)5385 void NavigationPattern::AdjustNodeForNonDestForceSplit(bool needFireLifecycle)
5386 {
5387     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5388     CHECK_NULL_VOID(host);
5389     auto navProperty = host->GetLayoutProperty<NavigationLayoutProperty>();
5390     CHECK_NULL_VOID(navProperty);
5391     auto navBar = AceType::DynamicCast<FrameNode>(host->GetNavBarNode());
5392     CHECK_NULL_VOID(navBar);
5393     auto navBarProperty = navBar->GetLayoutProperty();
5394     CHECK_NULL_VOID(navBarProperty);
5395     auto navContentNode = AceType::DynamicCast<FrameNode>(host->GetContentNode());
5396     CHECK_NULL_VOID(navContentNode);
5397     auto navContentProperty = navContentNode->GetLayoutProperty();
5398     CHECK_NULL_VOID(navContentProperty);
5399     auto primaryContentNode = AceType::DynamicCast<FrameNode>(host->GetPrimaryContentNode());
5400     CHECK_NULL_VOID(primaryContentNode);
5401     auto phNode = AceType::DynamicCast<FrameNode>(host->GetForceSplitPlaceHolderNode());
5402     CHECK_NULL_VOID(phNode);
5403     auto phProperty = phNode->GetLayoutProperty();
5404     CHECK_NULL_VOID(phProperty);
5405     if (needFireLifecycle) {
5406         FirePrimaryNodesLifecycle(NavDestinationLifecycle::ON_HIDE);
5407     }
5408     const auto& stackNodePairs = GetAllNavDestinationNodes();
5409     primaryNodes_.clear();
5410     for (int32_t index = (int32_t)(stackNodePairs.size() - 1); index >= 0; index--) {
5411         auto node = AceType::DynamicCast<NavDestinationGroupNode>(
5412             NavigationGroupNode::GetNavDestinationNode(stackNodePairs[index].second));
5413         CHECK_NULL_CONTINUE(node);
5414         RestoreNodeFromProxyNodeIfNeeded(primaryContentNode, navContentNode, node);
5415     }
5416     if (forceSplitUseNavBar_) {
5417         navBarProperty->UpdateVisibility(VisibleType::VISIBLE);
5418     } else {
5419         bool hideNavBar = navProperty->GetHideNavBarValue(false);
5420         navBarProperty->UpdateVisibility(hideNavBar ? VisibleType::INVISIBLE : VisibleType::VISIBLE);
5421     }
5422     if (forceSplitSuccess_ && stackNodePairs.empty()) {
5423         phProperty->UpdateVisibility(VisibleType::VISIBLE);
5424         navContentProperty->UpdateVisibility(VisibleType::INVISIBLE);
5425     } else {
5426         phProperty->UpdateVisibility(VisibleType::INVISIBLE);
5427         navContentProperty->UpdateVisibility(VisibleType::VISIBLE);
5428     }
5429 }
5430 
IsHideNavBarInForceSplitModeNeeded()5431 bool NavigationPattern::IsHideNavBarInForceSplitModeNeeded()
5432 {
5433     if (primaryNodes_.empty()) {
5434         auto navProperty = GetLayoutProperty<NavigationLayoutProperty>();
5435         CHECK_NULL_RETURN(navProperty, false);
5436         return navProperty->GetHideNavBarValue(false);
5437     }
5438     for (auto weakNode : primaryNodes_) {
5439         auto node = weakNode.Upgrade();
5440         CHECK_NULL_CONTINUE(node);
5441         if (node->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
5442             return true;
5443         }
5444     }
5445     return false;
5446 }
5447 
IsDestinationNeedHideInPush(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavDestinationGroupNode> & destNode) const5448 bool NavigationPattern::IsDestinationNeedHideInPush(
5449     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavDestinationGroupNode>& destNode) const
5450 {
5451     CHECK_NULL_RETURN(hostNode, false);
5452     CHECK_NULL_RETURN(destNode, false);
5453     if (destNode->NeedRemoveInPush()) {
5454         return true;
5455     }
5456     if (destNode->GetIndex() >= hostNode->GetLastStandardIndex()) {
5457         return false;
5458     }
5459     if (destNode->IsShowInPrimaryPartition()) {
5460         return false;
5461     }
5462     return true;
5463 }
5464 
FirePrimaryNodesLifecycle(NavDestinationLifecycle lifecycle)5465 void NavigationPattern::FirePrimaryNodesLifecycle(NavDestinationLifecycle lifecycle)
5466 {
5467     if (lifecycle != NavDestinationLifecycle::ON_SHOW && lifecycle != NavDestinationLifecycle::ON_HIDE) {
5468         return;
5469     }
5470     auto navigation = DynamicCast<NavigationGroupNode>(GetHost());
5471     CHECK_NULL_VOID(navigation);
5472     auto homeNode = homeNode_.Upgrade();
5473     CHECK_NULL_VOID(homeNode);
5474     if (homeNode->GetIndex() >= navigation->GetLastStandardIndex()) {
5475         return;
5476     }
5477     std::vector<WeakPtr<NavDestinationGroupNode>> primaryNodes;
5478     if (lifecycle == NavDestinationLifecycle::ON_SHOW) {
5479         primaryNodes = primaryNodes_;
5480         for (size_t idx = 0; idx < primaryNodes.size(); ++idx) {
5481             auto node = primaryNodes[idx].Upgrade();
5482             CHECK_NULL_CONTINUE(node);
5483             auto pattern = node->GetPattern<NavDestinationPattern>();
5484             CHECK_NULL_CONTINUE(pattern);
5485             if (!pattern->GetIsOnShow()) {
5486                 NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_SHOW);
5487                 pattern->SetIsOnShow(true);
5488             }
5489             if (idx == primaryNodes.size() - 1 && !pattern->IsActive()) {
5490                 NotifyDestinationLifecycle(node,
5491                     NavDestinationLifecycle::ON_ACTIVE, NavDestinationActiveReason::TRANSITION);
5492                 pattern->SetIsActive(true);
5493             }
5494         }
5495         return;
5496     }
5497 
5498     std::copy(primaryNodes_.rbegin(), primaryNodes_.rend(), std::back_inserter(primaryNodes));
5499     for (size_t idx = 0; idx < primaryNodes.size(); ++idx) {
5500         auto node = primaryNodes[idx].Upgrade();
5501         CHECK_NULL_CONTINUE(node);
5502         auto pattern = node->GetPattern<NavDestinationPattern>();
5503         CHECK_NULL_CONTINUE(pattern);
5504         if (idx == 0 && pattern->IsActive()) {
5505             NotifyDestinationLifecycle(node,
5506                 NavDestinationLifecycle::ON_INACTIVE, NavDestinationActiveReason::TRANSITION);
5507             pattern->SetIsActive(false);
5508         }
5509         if (pattern->GetIsOnShow()) {
5510             NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_HIDE);
5511             pattern->SetIsOnShow(false);
5512         }
5513     }
5514 }
5515 
IsPrimaryNode(const RefPtr<NavDestinationGroupNode> & destNode) const5516 bool NavigationPattern::IsPrimaryNode(const RefPtr<NavDestinationGroupNode>& destNode) const
5517 {
5518     return std::find_if(primaryNodes_.begin(), primaryNodes_.end(),
5519         [destNode](WeakPtr<NavDestinationGroupNode> primaryNode) {
5520             return destNode == primaryNode.Upgrade();
5521         }) != primaryNodes_.end();
5522 }
5523 
FirePreTopPrimaryNodeInactiveIfNeeded()5524 void NavigationPattern::FirePreTopPrimaryNodeInactiveIfNeeded()
5525 {
5526     if (prePrimaryNodes_.empty()) {
5527         return;
5528     }
5529     auto preTopPrimaryNode = prePrimaryNodes_.back().Upgrade();
5530     CHECK_NULL_VOID(preTopPrimaryNode);
5531     if (!preTopPrimaryNode->IsActive()) {
5532         return;
5533     }
5534     RefPtr<NavDestinationGroupNode> topPrimaryNode = nullptr;
5535     if (!primaryNodes_.empty()) {
5536         topPrimaryNode = primaryNodes_.back().Upgrade();
5537     }
5538     RefPtr<NavDestinationGroupNode> topNode = nullptr;
5539     if (navigationStack_) {
5540         const auto& nodeList = navigationStack_->GetAllNavDestinationNodes();
5541         topNode = nodeList.empty() ? nullptr : AceType::DynamicCast<NavDestinationGroupNode>(
5542             NavigationGroupNode::GetNavDestinationNode(nodeList.back().second));
5543     }
5544     if (preTopPrimaryNode != topPrimaryNode && preTopPrimaryNode != topNode) {
5545         NotifyDestinationLifecycle(preTopPrimaryNode,
5546             NavDestinationLifecycle::ON_INACTIVE, NavDestinationActiveReason::TRANSITION);
5547     }
5548 }
5549 
FirePrePrimaryNodesOnHide()5550 void NavigationPattern::FirePrePrimaryNodesOnHide()
5551 {
5552     std::vector<RefPtr<NavDestinationGroupNode>> nodeNeedToHide;
5553     for (auto it = prePrimaryNodes_.rbegin(); it != prePrimaryNodes_.rend(); ++it) {
5554         auto node = it->Upgrade();
5555         CHECK_NULL_CONTINUE(node);
5556         auto pattern = node->GetPattern<NavDestinationPattern>();
5557         CHECK_NULL_CONTINUE(pattern);
5558         if (!node->IsShowInPrimaryPartition() && pattern->GetIsOnShow()) {
5559             NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_HIDE);
5560         }
5561     }
5562 
5563     for (auto& primaryNode : primaryNodesToBeRemoved_) {
5564         CHECK_NULL_CONTINUE(primaryNode);
5565         auto pattern = primaryNode->GetPattern<NavDestinationPattern>();
5566         CHECK_NULL_CONTINUE(pattern);
5567         if (!pattern->GetIsOnShow()) {
5568             continue;
5569         }
5570         NotifyDestinationLifecycle(primaryNode, NavDestinationLifecycle::ON_HIDE);
5571     }
5572 }
5573 
FirePrePrimaryNodesOnWillDisappear(std::set<RefPtr<NavDestinationGroupNode>> && filterNodes)5574 void NavigationPattern::FirePrePrimaryNodesOnWillDisappear(std::set<RefPtr<NavDestinationGroupNode>>&& filterNodes)
5575 {
5576     for (auto& primaryNode : primaryNodesToBeRemoved_) {
5577         CHECK_NULL_CONTINUE(primaryNode);
5578         if (filterNodes.find(primaryNode) != filterNodes.end()) {
5579             continue;
5580         }
5581         NotifyDestinationLifecycle(primaryNode, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
5582     }
5583 }
5584 
FirePrimaryNodesOnShowAndActive()5585 void NavigationPattern::FirePrimaryNodesOnShowAndActive()
5586 {
5587     RefPtr<NavDestinationGroupNode> topNode = nullptr;
5588     for (auto it = primaryNodes_.begin(); it != primaryNodes_.end(); ++it) {
5589         auto node = it->Upgrade();
5590         CHECK_NULL_CONTINUE(node);
5591         auto pattern = node->GetPattern<NavDestinationPattern>();
5592         CHECK_NULL_CONTINUE(pattern);
5593         if (!pattern->GetIsOnShow()) {
5594             NotifyDestinationLifecycle(node, NavDestinationLifecycle::ON_SHOW);
5595         }
5596         topNode = node;
5597     }
5598     CHECK_NULL_VOID(topNode);
5599     auto pattern = topNode->GetPattern<NavDestinationPattern>();
5600     CHECK_NULL_VOID(pattern);
5601     if (!pattern->IsActive()) {
5602         NotifyDestinationLifecycle(topNode, NavDestinationLifecycle::ON_ACTIVE, NavDestinationActiveReason::TRANSITION);
5603     }
5604 }
5605 
RemoveRedundantPrimaryNavDestination()5606 void NavigationPattern::RemoveRedundantPrimaryNavDestination()
5607 {
5608     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5609     CHECK_NULL_VOID(host);
5610     auto primaryContentNode = host->GetPrimaryContentNode();
5611     CHECK_NULL_VOID(primaryContentNode);
5612     bool hasRemoveNode = false;
5613     while (primaryContentNode->GetChildren().size() > primaryNodes_.size()) {
5614         auto lastNode = AceType::DynamicCast<NavDestinationGroupNode>(primaryContentNode->GetLastChild());
5615         CHECK_NULL_CONTINUE(lastNode);
5616         lastNode->CleanContent();
5617         primaryContentNode->RemoveChild(lastNode, true);
5618         hasRemoveNode = true;
5619     }
5620     if (hasRemoveNode) {
5621         primaryContentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
5622         primaryContentNode->MarkNeedSyncRenderTree();
5623     }
5624 }
5625 
IsHomeDestinationVisible()5626 bool NavigationPattern::IsHomeDestinationVisible()
5627 {
5628     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5629     CHECK_NULL_RETURN(host, false);
5630     auto property = host->GetLayoutProperty<NavigationLayoutProperty>();
5631     CHECK_NULL_RETURN(property, false);
5632     if (property->GetHideNavBarValue(false)) {
5633         return false;
5634     }
5635     if (navigationMode_ == NavigationMode::STACK) {
5636         CHECK_NULL_RETURN(navigationStack_, false);
5637         return navigationStack_->Empty();
5638     }
5639     return navigationMode_ == NavigationMode::SPLIT;
5640 }
5641 
ShouldFireHomeDestiationLifecycle(NavDestinationLifecycle lifecycle,const RefPtr<NavDestinationPattern> & destPattern,int32_t lastStandardIndex,int32_t curStackSize,bool isModeChange)5642 bool NavigationPattern::ShouldFireHomeDestiationLifecycle(NavDestinationLifecycle lifecycle,
5643     const RefPtr<NavDestinationPattern>& destPattern, int32_t lastStandardIndex,
5644     int32_t curStackSize, bool isModeChange)
5645 {
5646     if (isModeChange || navigationMode_ == NavigationMode::SPLIT) {
5647         switch (lifecycle) {
5648             case NavDestinationLifecycle::ON_SHOW:
5649                 return !destPattern->GetIsOnShow();
5650             case NavDestinationLifecycle::ON_ACTIVE:
5651                 return !destPattern->IsActive();
5652             case NavDestinationLifecycle::ON_INACTIVE:
5653                 return destPattern->IsActive();
5654             case NavDestinationLifecycle::ON_HIDE:
5655                 return destPattern->GetIsOnShow();
5656             default:
5657                 return false;
5658         }
5659     }
5660     if (navigationMode_ == NavigationMode::STACK) {
5661         switch (lifecycle) {
5662             case NavDestinationLifecycle::ON_SHOW:
5663                 return lastStandardIndex < 0 && !destPattern->GetIsOnShow();
5664             case NavDestinationLifecycle::ON_ACTIVE:
5665                 return curStackSize == 0 && !destPattern->IsActive();
5666             case NavDestinationLifecycle::ON_INACTIVE:
5667                 return curStackSize == 0 && destPattern->IsActive();
5668             case NavDestinationLifecycle::ON_HIDE:
5669                 return lastStandardIndex < 0 && destPattern->GetIsOnShow();
5670             default:
5671                 return false;
5672         }
5673     }
5674     return false;
5675 }
5676 
FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle lifecycle,bool isModeChange,NavDestinationActiveReason reason)5677 void NavigationPattern::FireHomeDestinationLifeCycleIfNeeded(
5678     NavDestinationLifecycle lifecycle, bool isModeChange, NavDestinationActiveReason reason)
5679 {
5680     auto host = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5681     CHECK_NULL_VOID(host);
5682     auto destNode = AceType::DynamicCast<NavDestinationGroupNode>(host->GetHomeDestinationNode());
5683     CHECK_NULL_VOID(destNode);
5684     auto destPattern = destNode->GetPattern<NavDestinationPattern>();
5685     CHECK_NULL_VOID(destPattern);
5686     auto lastStandardIndex = host->GetLastStandardIndex();
5687     int32_t curStackSize = static_cast<int32_t>(GetAllNavDestinationNodes().size());
5688     if (!ShouldFireHomeDestiationLifecycle(lifecycle, destPattern, lastStandardIndex, curStackSize, isModeChange)) {
5689         return;
5690     }
5691     NotifyDestinationLifecycle(destNode, lifecycle, reason);
5692 }
UpdateChildLayoutPolicy()5693 void NavigationPattern::UpdateChildLayoutPolicy()
5694 {
5695     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
5696     CHECK_NULL_VOID(hostNode);
5697     auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
5698     CHECK_NULL_VOID(navBarNode);
5699     auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
5700     CHECK_NULL_VOID(navigationContentNode);
5701     auto layoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
5702     CHECK_NULL_VOID(layoutProperty);
5703     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
5704     if (layoutPolicy.has_value()) {
5705         navigationContentNode->GetLayoutProperty()->UpdateLayoutPolicyProperty(
5706             layoutPolicy.value().widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH), true);
5707         navigationContentNode->GetLayoutProperty()->UpdateLayoutPolicyProperty(
5708             layoutPolicy.value().heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH), false);
5709         navBarNode->GetLayoutProperty()->UpdateLayoutPolicyProperty(
5710             layoutPolicy.value().widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH), true);
5711         navBarNode->GetLayoutProperty()->UpdateLayoutPolicyProperty(
5712             layoutPolicy.value().heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH), false);
5713     }
5714 }
5715 
ClearNavigationCustomTransition()5716 void NavigationPattern::ClearNavigationCustomTransition()
5717 {
5718     auto currentProxy = GetTopNavigationProxy();
5719     if (currentProxy) {
5720         currentProxy->SetIsFinished(true);
5721         RemoveProxyById(currentProxy->GetProxyId());
5722     }
5723     ClearRecoveryList();
5724 }
5725 
CheckNeedCreate(int32_t index)5726 bool NavigationPattern::CheckNeedCreate(int32_t index)
5727 {
5728     CHECK_NULL_RETURN(navigationStack_, false);
5729     auto pathListSize = navigationStack_->Size();
5730     RefPtr<UINode> uiNode = nullptr;
5731     if (navigationStack_->IsFromRecovery(index)) {
5732         return true;
5733     }
5734     if (navigationStack_->NeedBuildNewInstance(index)) {
5735         return true;
5736     }
5737     if (index == pathListSize - 1 && addByNavRouter_) {
5738         addByNavRouter_ = false;
5739         uiNode = navigationStack_->Get();
5740     } else {
5741         uiNode = navigationStack_->Get(index);
5742     }
5743     return uiNode == nullptr;
5744 }
5745 } // namespace OHOS::Ace::NG
5746