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