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