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