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