1 /*
2 * Copyright (c) 2022-2024 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_group_node.h"
17
18 #include "base/log/ace_checker.h"
19 #include "base/log/ace_performance_check.h"
20 #include "base/memory/ace_type.h"
21 #include "base/memory/referenced.h"
22 #include "base/perfmonitor/perf_constants.h"
23 #include "base/perfmonitor/perf_monitor.h"
24 #include "base/utils/utils.h"
25 #include "core/animation/page_transition_common.h"
26 #include "core/common/container.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components/theme/app_theme.h"
29
30 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
31 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
32 #endif
33
34 #if !defined(ACE_UNITTEST)
35 #include "core/components_ng/base/transparent_node_detector.h"
36 #endif
37
38 #include "core/components_ng/base/view_stack_processor.h"
39 #include "core/components_ng/event/focus_hub.h"
40 #include "core/components_ng/pattern/button/button_layout_property.h"
41 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
42 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
43 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
44 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
45 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
46 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
47 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
48 #include "core/components_ng/pattern/navrouter/navdestination_event_hub.h"
49 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
50 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
51 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
52 #include "core/components_ng/pattern/navrouter/navrouter_event_hub.h"
53 #include "core/components_ng/pattern/navrouter/navrouter_group_node.h"
54 #include "core/components_ng/pattern/stack/stack_layout_property.h"
55 #include "core/components_ng/pattern/stack/stack_model_ng.h"
56 #include "core/components_ng/pattern/stack/stack_pattern.h"
57 #include "core/components_ng/pattern/stage/page_pattern.h"
58 #include "core/components_ng/property/measure_property.h"
59 #include "core/components_ng/property/property.h"
60 #include "core/components_ng/render/render_context.h"
61 #include "core/components_v2/inspector/inspector_constants.h"
62
63 namespace OHOS::Ace::NG {
64 namespace {
65 constexpr int32_t MASK_DURATION = 350;
66 constexpr int32_t DEFAULT_ANIMATION_DURATION = 450;
67 constexpr int32_t DEFAULT_REPLACE_DURATION = 150;
68 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
69 const RefPtr<InterpolatingSpring> springCurve = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f);
70 const RefPtr<CubicCurve> replaceCurve = AceType::MakeRefPtr<CubicCurve>(0.33, 0.0, 0.67, 1.0);
71 } // namespace
72 class InspectorFilter;
73
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)74 RefPtr<NavigationGroupNode> NavigationGroupNode::GetOrCreateGroupNode(
75 const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
76 {
77 auto frameNode = GetFrameNode(tag, nodeId);
78 CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavigationGroupNode>(frameNode));
79 auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
80 auto navigationGroupNode = AceType::MakeRefPtr<NavigationGroupNode>(tag, nodeId, pattern);
81 navigationGroupNode->InitializePatternAndContext();
82 ElementRegister::GetInstance()->AddUINode(navigationGroupNode);
83 return navigationGroupNode;
84 }
85
~NavigationGroupNode()86 NavigationGroupNode::~NavigationGroupNode()
87 {
88 auto navigationPattern = GetPattern<NavigationPattern>();
89 const auto& navDestinationNodes = navigationPattern->GetAllNavDestinationNodes();
90 for (auto iter : navDestinationNodes) {
91 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(iter.second));
92 if (navDestinationNode) {
93 navDestinationNode->GetPattern<NavDestinationPattern>()->SetCustomNode(nullptr);
94 }
95 }
96 auto context = PipelineContext::GetCurrentContext();
97 CHECK_NULL_VOID(context);
98 auto stageManager = context->GetStageManager();
99 CHECK_NULL_VOID(stageManager);
100 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
101 CHECK_NULL_VOID(pageNode);
102 auto pagePattern = pageNode->GetPattern<PagePattern>();
103 CHECK_NULL_VOID(pagePattern);
104 CHECK_NULL_VOID(pagePattern->GetPageInfo());
105 int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
106 context->RemoveNavigationNode(pageId, GetId());
107 context->DeleteNavigationNode(curId_);
108 }
109
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)110 void NavigationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
111 {
112 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
113 CHECK_NULL_VOID(pattern);
114 auto navBar = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
115 CHECK_NULL_VOID(navBar);
116 auto contentNode = navBar->GetContentNode();
117 if (!contentNode) {
118 auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
119 contentNode = FrameNode::GetOrCreateFrameNode(
120 V2::NAVBAR_CONTENT_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
121 navBar->SetContentNode(contentNode);
122 navBar->AddChild(contentNode);
123
124 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
125 auto navBarContentNode = AceType::DynamicCast<FrameNode>(contentNode);
126 SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
127 .edges = SAFE_AREA_EDGE_ALL };
128 navBarContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
129 }
130 }
131 contentNode->AddChild(child);
132 }
133
UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode> & remainChild,bool modeChange)134 void NavigationGroupNode::UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode>& remainChild, bool modeChange)
135 {
136 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
137 CHECK_NULL_VOID(pattern);
138 const auto& navDestinationNodes = pattern->GetAllNavDestinationNodes();
139
140 auto navigationContentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
141 CHECK_NULL_VOID(navigationContentNode);
142 bool hasChanged = false;
143 int32_t slot = 0;
144 int32_t beforeLastStandardIndex = lastStandardIndex_;
145 auto preLastStandardNode = AceType::DynamicCast<NavDestinationGroupNode>(
146 navigationContentNode->GetChildAtIndex(beforeLastStandardIndex));
147
148 // save preLastStandardIndex_ before update and check whether standard page changed
149 preLastStandardIndex_ = lastStandardIndex_;
150 UpdateLastStandardIndex();
151
152 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "last standard page index is %{public}d", lastStandardIndex_);
153 if (!ReorderNavDestination(navDestinationNodes, navigationContentNode, slot, hasChanged)) {
154 return;
155 }
156
157 for (uint32_t index = 0; index < navDestinationNodes.size(); index++) {
158 const auto& childNode = navDestinationNodes[index];
159 const auto& uiNode = childNode.second;
160 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
161 hasChanged = (UpdateNavDestinationVisibility(navDestination, remainChild, index,
162 navDestinationNodes.size(), preLastStandardNode) || hasChanged);
163 }
164
165 RemoveRedundantNavDestination(
166 navigationContentNode, remainChild, static_cast<int32_t>(slot), hasChanged, preLastStandardNode);
167 if (modeChange) {
168 navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
169 } else if (hasChanged) {
170 navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
171 }
172 }
173
ReorderNavDestination(const std::vector<std::pair<std::string,RefPtr<UINode>>> & navDestinationNodes,RefPtr<FrameNode> & navigationContentNode,int32_t & slot,bool & hasChanged)174 bool NavigationGroupNode::ReorderNavDestination(
175 const std::vector<std::pair<std::string, RefPtr<UINode>>>& navDestinationNodes,
176 RefPtr<FrameNode>& navigationContentNode, int32_t& slot, bool& hasChanged)
177 {
178 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
179 CHECK_NULL_RETURN(pattern, false);
180 for (uint32_t i = 0; i != navDestinationNodes.size(); ++i) {
181 const auto& childNode = navDestinationNodes[i];
182 const auto& uiNode = childNode.second;
183 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
184 if (navDestination == nullptr) {
185 if (pattern->GetNavigationStack()->IsFromRecovery(i)) {
186 continue;
187 }
188 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "get destination node failed");
189 return false;
190 }
191 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
192 CHECK_NULL_RETURN(navDestinationPattern, false);
193 navDestinationPattern->SetName(childNode.first);
194 navDestinationPattern->SetCustomNode(uiNode);
195 navDestinationPattern->SetIndex(static_cast<int32_t>(i));
196 SetBackButtonEvent(navDestination);
197 navDestination->SetIndex(i);
198 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
199 CHECK_NULL_RETURN(eventHub, false);
200 if (!eventHub->GetOnStateChange()) {
201 auto onStateChangeMap = pattern->GetOnStateChangeMap();
202 auto iter = onStateChangeMap.find(uiNode->GetId());
203 if (iter != onStateChangeMap.end()) {
204 eventHub->SetOnStateChange(iter->second);
205 pattern->DeleteOnStateChangeItem(iter->first);
206 }
207 }
208 int32_t childIndex = navigationContentNode->GetChildIndex(navDestination);
209 if (childIndex < 0) {
210 navDestination->MountToParent(navigationContentNode, slot);
211 hasChanged = true;
212 } else if (childIndex != slot) {
213 navDestination->MovePosition(slot);
214 hasChanged = true;
215 }
216 slot++;
217 }
218 return true;
219 }
220
RemoveRedundantNavDestination(RefPtr<FrameNode> & navigationContentNode,const RefPtr<UINode> & remainChild,int32_t slot,bool & hasChanged,const RefPtr<NavDestinationGroupNode> & preLastStandardNode)221 void NavigationGroupNode::RemoveRedundantNavDestination(RefPtr<FrameNode>& navigationContentNode,
222 const RefPtr<UINode>& remainChild, int32_t slot, bool& hasChanged,
223 const RefPtr<NavDestinationGroupNode>& preLastStandardNode)
224 {
225 auto pattern = GetPattern<NavigationPattern>();
226 RefPtr<UINode> maxAnimatingDestination = nullptr;
227 RefPtr<UINode> remainDestination = GetNavDestinationNode(remainChild);
228 RefPtr<UINode> curTopDestination = navigationContentNode->GetChildAtIndex(slot - 1);
229 // record remove destination size
230 int32_t removeSize = 0;
231 bool hideNodesFinish = false;
232 // record animating destination size
233 int32_t animatingSize = 0;
234 int32_t remainNodeIndex = -1;
235 int32_t beforeLastStandardIndex = preLastStandardNode == nullptr ? -1 : preLastStandardNode->GetIndex();
236 while (slot + removeSize + animatingSize < static_cast<int32_t>(navigationContentNode->GetChildren().size())) {
237 // delete useless nodes that are not at the top
238 int32_t candidateIndex = static_cast<int32_t>(navigationContentNode->GetChildren().size()) - 1 - animatingSize;
239 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
240 navigationContentNode->GetChildAtIndex(candidateIndex));
241 if (!navDestination) {
242 navigationContentNode->RemoveChildAtIndex(candidateIndex);
243 hasChanged = true;
244 continue;
245 }
246 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
247 if (eventHub) {
248 eventHub->FireChangeEvent(false);
249 }
250 if (navDestination == remainDestination) {
251 if (pattern->IsCurTopNewInstance()) {
252 // remain the last child for push animation, and this child
253 // will be remove in push's animation finish callback
254 navDestination->SetNeedRemoveInPush(true);
255 remainNodeIndex = slot - 1;
256 navDestination->MovePosition(remainNodeIndex);
257 } else {
258 // remain the last child for pop animation
259 remainNodeIndex = slot;
260 navDestination->MovePosition(slot);
261 }
262 ++slot;
263 continue;
264 }
265 // The NavDestination in the EXIT animation needs to be cleaned in the animation onfinish callback.
266 if (navDestination->IsOnAnimation()) {
267 if (navDestination->GetTransitionType() == PageTransitionType::EXIT_POP) {
268 ++animatingSize;
269 continue;
270 }
271 if (navDestination->NeedRemoveInPush()) {
272 if (maxAnimatingDestination == nullptr) {
273 maxAnimatingDestination = navDestination;
274 }
275 ++animatingSize;
276 continue;
277 }
278 }
279 // remove content child
280 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
281 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "remove child: %{public}s", navDestinationPattern->GetName().c_str());
282 if (navDestination->GetIndex() >= beforeLastStandardIndex && !hideNodesFinish) {
283 if (navDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD
284 && preLastStandardNode != navDestination) {
285 hideNodesFinish = true;
286 DealRemoveDestination(navDestination);
287 hasChanged = true;
288 continue;
289 }
290 hideNodes_.emplace_back(std::make_pair(navDestination, true));
291 navDestination->SetCanReused(false);
292 removeSize++;
293 auto index = slot + removeSize - 1;
294 // move current destination position to navigation stack size + remove navDestination nodes
295 if (index >= 0) {
296 navDestination->MovePosition(remainNodeIndex);
297 }
298 continue;
299 }
300 DealRemoveDestination(navDestination);
301 hasChanged = true;
302 }
303 if (pattern->IsCurTopNewInstance()) {
304 ReorderAnimatingDestination(
305 navigationContentNode, maxAnimatingDestination, remainDestination, curTopDestination);
306 }
307 }
308
ReorderAnimatingDestination(RefPtr<FrameNode> & navigationContentNode,RefPtr<UINode> & maxAnimatingDestination,RefPtr<UINode> & remainDestination,RefPtr<UINode> & curTopDestination)309 void NavigationGroupNode::ReorderAnimatingDestination(RefPtr<FrameNode>& navigationContentNode,
310 RefPtr<UINode>& maxAnimatingDestination, RefPtr<UINode>& remainDestination, RefPtr<UINode>& curTopDestination)
311 {
312 auto maxAnimatingIndex = navigationContentNode->GetChildIndex(maxAnimatingDestination);
313 if (maxAnimatingIndex != -1 && remainDestination) {
314 remainDestination->MovePosition(maxAnimatingIndex + 1);
315 }
316 auto remainIndex = navigationContentNode->GetChildIndex(remainDestination);
317 if (remainIndex != -1 && curTopDestination) {
318 curTopDestination->MovePosition(remainIndex + 1);
319 }
320 }
321
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const322 void NavigationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
323 {
324 FrameNode::ToJsonValue(json, filter);
325 auto navBarNode = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
326 CHECK_NULL_VOID(navBarNode);
327 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
328 if (titleBarNode) {
329 std::string title = NavigationTitleUtil::GetTitleString(titleBarNode,
330 navBarNode->GetPrevTitleIsCustomValue(false));
331 std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
332 json->PutExtAttr("title", title.c_str(), filter);
333 json->PutExtAttr("subtitle", subtitle.c_str(), filter);
334 }
335 json->PutExtAttr("menus", navBarNode->GetBarItemsString(true).c_str(), filter);
336 json->PutExtAttr("toolBar", navBarNode->GetBarItemsString(false).c_str(), filter);
337 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
338 CHECK_NULL_VOID(navBarLayoutProperty);
339 json->PutExtAttr("titleMode", navBarLayoutProperty->GetTitleModeString().c_str(), filter);
340 json->PutExtAttr("hideBackButton", navBarLayoutProperty->GetHideBackButtonValue(false), filter);
341 json->PutExtAttr("hideTitleBar", navBarLayoutProperty->GetHideTitleBarValue(false), filter);
342 json->PutExtAttr("hideToolBar", navBarLayoutProperty->GetHideToolBarValue(false), filter);
343 }
344
GetNavDestinationNode(RefPtr<UINode> uiNode)345 RefPtr<UINode> NavigationGroupNode::GetNavDestinationNode(RefPtr<UINode> uiNode)
346 {
347 if (!uiNode) {
348 return nullptr;
349 }
350 // create NavDestinationNode from uiNode stored in NavigationStack
351 while (uiNode) {
352 if (uiNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
353 // this is a navDestination node
354 return uiNode;
355 }
356 if (AceType::DynamicCast<UINode>(uiNode)) {
357 // this is an UINode, go deep further for navDestination node
358 auto children = uiNode->GetChildren();
359 uiNode = children.front();
360 continue;
361 }
362 }
363 CHECK_NULL_RETURN(uiNode, nullptr);
364 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get navDestination node failed: id: %{public}d, %{public}s",
365 uiNode->GetId(), uiNode->GetTag().c_str());
366 return nullptr;
367 }
368
SetBackButtonEvent(const RefPtr<NavDestinationGroupNode> & navDestination)369 void NavigationGroupNode::SetBackButtonEvent(const RefPtr<NavDestinationGroupNode>& navDestination)
370 {
371 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
372 CHECK_NULL_VOID(titleBarNode);
373 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
374 CHECK_NULL_VOID(backButtonNode);
375 auto backButtonEventHub = backButtonNode->GetEventHub<EventHub>();
376 CHECK_NULL_VOID(backButtonEventHub);
377 auto onBackButtonEvent = [navDestinationWeak = WeakPtr<NavDestinationGroupNode>(navDestination),
378 navigationWeak = WeakClaim(this)](GestureEvent& /*info*/) -> bool {
379 auto navDestination = navDestinationWeak.Upgrade();
380 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "click navigation back button");
381 CHECK_NULL_RETURN(navDestination, false);
382 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
383 CHECK_NULL_RETURN(eventHub, false);
384 eventHub->SetState(NavDestinationState::ON_BACKPRESS);
385 auto navdestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
386 UIObserverHandler::GetInstance().NotifyNavigationStateChange(
387 navdestinationPattern, NavDestinationState::ON_BACKPRESS);
388 auto isOverride = eventHub->GetOnBackPressedEvent();
389 auto result = false;
390 if (isOverride) {
391 result = eventHub->FireOnBackPressedEvent();
392 }
393 if (result) {
394 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation user onBackPress return true");
395 return true;
396 }
397 auto navigation = navigationWeak.Upgrade();
398 CHECK_NULL_RETURN(navigation, false);
399 // if set hideNavBar and stack size is one, return false
400 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(navigation->GetLayoutProperty());
401 auto pattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
402 auto stack = pattern->GetNavigationStack();
403 CHECK_NULL_RETURN(stack, false);
404 if (navigationLayoutProperty->GetHideNavBarValue(false) && stack->Size() <= 1) {
405 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "set hideNavBar and stack size is no more than one");
406 return false;
407 }
408 auto isLastChild = stack->Size() == 1;
409 if (isOverride) {
410 result = navigation->HandleBack(navDestination, isLastChild, true);
411 } else {
412 result = navigation->HandleBack(navDestination, isLastChild, false);
413 }
414 // when js navigationStack is provided, modifyDone will be called by state manager.
415 auto navigationPattern = navigation->GetPattern<NavigationPattern>();
416 CHECK_NULL_RETURN(navigationPattern, false);
417 if (!navigationPattern->GetNavigationStackProvided()) {
418 navigation->MarkModifyDone();
419 navigation->MarkDirtyNode();
420 }
421
422 return result;
423 }; // backButton event
424
425 navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
426 backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
427 }
428
GetTopDestination()429 RefPtr<FrameNode> NavigationGroupNode::GetTopDestination()
430 {
431 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
432 CHECK_NULL_RETURN(pattern, nullptr);
433 auto navigationStack = pattern->GetNavigationStack();
434 CHECK_NULL_RETURN(navigationStack, nullptr);
435 auto topNavdestination = AceType::DynamicCast<FrameNode>(GetNavDestinationNode(navigationStack->Get()));
436 return topNavdestination;
437 }
438
CheckCanHandleBack(bool & isEntry)439 bool NavigationGroupNode::CheckCanHandleBack(bool& isEntry)
440 {
441 auto navigation = AceType::WeakClaim(this).Upgrade();
442 CHECK_NULL_RETURN(navigation, false);
443 auto navigationPattern = GetPattern<NavigationPattern>();
444 CHECK_NULL_RETURN(navigationPattern, false);
445
446 auto navigationStack = navigationPattern->GetNavigationStack();
447 CHECK_NULL_RETURN(navigationStack, false);
448 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
449 NavigationGroupNode::GetNavDestinationNode(navigationStack->Get()));
450 if (!navDestination) {
451 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find destination node to process back press");
452 return false;
453 }
454 if (!navigationPattern->IsFinishInteractiveAnimation()) {
455 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't handle back press during interactive animation");
456 return true;
457 }
458 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
459 if (navDestinationPattern->OverlayOnBackPressed()) {
460 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination's ovelay consume backPressed event: %{public}s",
461 navDestinationPattern->GetName().c_str());
462 return true;
463 }
464 auto navDestinationContext = navDestinationPattern->GetNavDestinationContext();
465 CHECK_NULL_RETURN(navDestinationContext, false);
466 auto navPathInfo = navDestinationContext->GetNavPathInfo();
467 CHECK_NULL_RETURN(navPathInfo, false);
468 auto isPathEntry = navPathInfo->GetIsEntry();
469 if (isPathEntry) {
470 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s is entry navDestination, do not consume backPressed event",
471 navDestinationPattern->GetName().c_str());
472 navPathInfo->SetIsEntry(false);
473 auto index = navDestinationContext->GetIndex();
474 navigationStack->SetIsEntryByIndex(index, false);
475 isEntry = true;
476 return false;
477 }
478 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination consume back button event: %{public}s",
479 navDestinationPattern->GetName().c_str());
480 GestureEvent gestureEvent;
481 return navDestination->GetNavDestinationBackButtonEvent()(gestureEvent);
482 }
483
HandleBack(const RefPtr<FrameNode> & node,bool isLastChild,bool isOverride)484 bool NavigationGroupNode::HandleBack(const RefPtr<FrameNode>& node, bool isLastChild, bool isOverride)
485 {
486 auto navigationPattern = GetPattern<NavigationPattern>();
487 if (!isOverride && !isLastChild) {
488 navigationPattern->RemoveNavDestination();
489 return true;
490 }
491 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
492 CHECK_NULL_RETURN(navDestination, false);
493
494 auto mode = navigationPattern->GetNavigationMode();
495 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
496 if (isLastChild && (mode == NavigationMode::SPLIT ||
497 (mode == NavigationMode::STACK && layoutProperty->GetHideNavBar().value_or(false)))) {
498 return false;
499 }
500
501 navigationPattern->RemoveNavDestination();
502 return true;
503 }
504
CreateAnimationWithPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,const AnimationFinishCallback finishCallback,bool isNavBar)505 void NavigationGroupNode::CreateAnimationWithPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
506 const AnimationFinishCallback finishCallback, bool isNavBar)
507 {
508 // this function has been override for different device type
509 CHECK_NULL_VOID(preNode);
510 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
511 CHECK_NULL_VOID(preNavDestination);
512 preNavDestination->InitSystemTransitionPop(false);
513 if (curNode) {
514 if (isNavBar) {
515 auto navbarNode = AceType::DynamicCast<NavBarNode>(curNode);
516 CHECK_NULL_VOID(navbarNode);
517 navbarNode->InitSystemTransitionPop();
518 } else {
519 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
520 CHECK_NULL_VOID(curNavDestination);
521 curNavDestination->InitSystemTransitionPop(true);
522 }
523 }
524 // start transition animation
525 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
526 finishCallback);
527 auto newPopAnimation = AnimationUtils::StartAnimation(option, [
528 this, preNode, curNode, isNavBar]() {
529 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition start");
530 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
531 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation start");
532
533 // ENTER_POP nodes animation
534 if (curNode) {
535 if (isNavBar) {
536 auto curNavBar = AceType::DynamicCast<NavBarNode>(curNode);
537 CHECK_NULL_VOID(curNavBar);
538 curNavBar->StartSystemTransitionPop();
539 } else {
540 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
541 CHECK_NULL_VOID(curNavDestination);
542 curNavDestination->StartSystemTransitionPop(true);
543 }
544 }
545 // EXIT_POP nodes finish animation
546 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
547 CHECK_NULL_VOID(preNavDestination);
548 preNavDestination->StartSystemTransitionPop(false);
549 }, option.GetOnFinishEvent());
550 if (newPopAnimation) {
551 popAnimations_.emplace_back(newPopAnimation);
552 }
553 auto titleOpacityAnimation = preNavDestination->TitleOpacityAnimation(false);
554 if (titleOpacityAnimation) {
555 popAnimations_.emplace_back(titleOpacityAnimation);
556 }
557 auto backButtonAnimation = preNavDestination->BackButtonAnimation(false);
558 if (backButtonAnimation) {
559 popAnimations_.emplace_back(backButtonAnimation);
560 }
561 auto maskAnimation = MaskAnimation(curNode, true);
562 if (maskAnimation) {
563 popAnimations_.emplace_back(maskAnimation);
564 }
565 }
566
TransitionWithPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)567 void NavigationGroupNode::TransitionWithPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
568 bool isNavBar)
569 {
570 CHECK_NULL_VOID(preNode);
571 /* create animation finish callback */
572 CleanPopAnimations();
573 AnimationFinishCallback callback = [weakPreNode = WeakPtr<FrameNode>(preNode),
574 weakNavigation = WeakClaim(this)] {
575 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition end");
576 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation end");
577 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
578 auto navigation = weakNavigation.Upgrade();
579 if (navigation) {
580 navigation->isOnAnimation_ = false;
581 auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
582 navigation->OnAccessibilityEvent(
583 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
584 navigation->CleanPopAnimations();
585 }
586
587 auto preNavDesNode = weakPreNode.Upgrade();
588 CHECK_NULL_VOID(preNavDesNode);
589 auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNavDesNode);
590 CHECK_NULL_VOID(preNavdestination);
591 if (preNavdestination->SystemTransitionPopCallback()) {
592 // return true means need to remove the poped navdestination
593 auto parent = preNavDesNode->GetParent();
594 CHECK_NULL_VOID(parent);
595 parent->RemoveChild(preNavDesNode);
596 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
597 }
598 auto context = PipelineContext::GetCurrentContext();
599 CHECK_NULL_VOID(context);
600 context->MarkNeedFlushMouseEvent();
601 };
602 CreateAnimationWithPop(preNode, curNode, callback, isNavBar);
603
604 // clear this flag for navBar layout only
605 if (isNavBar) {
606 SetNeedSetInvisible(false);
607 }
608 isOnAnimation_ = true;
609 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
610 UiSessionManager::GetInstance().OnRouterChange(navigationPathInfo_, "navigationPopPage");
611 #endif
612 }
613
CreateAnimationWithPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,const AnimationFinishCallback finishCallback,bool isNavBar)614 void NavigationGroupNode::CreateAnimationWithPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
615 const AnimationFinishCallback finishCallback, bool isNavBar)
616 {
617 // this function has been override for different device type
618 if (isNavBar) {
619 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
620 CHECK_NULL_VOID(navBarNode);
621 navBarNode->SystemTransitionPushAction(true);
622 } else {
623 if (preNode) {
624 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
625 CHECK_NULL_VOID(navDestination);
626 navDestination->InitSystemTransitionPush(false);
627 }
628 }
629 if (curNode) {
630 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
631 CHECK_NULL_VOID(curNavDestination);
632 curNavDestination->InitSystemTransitionPush(true);
633 }
634
635 // start transition animation
636 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
637 finishCallback);
638 auto newPushAnimation = AnimationUtils::StartAnimation(option, [
639 this, preNode, curNode, isNavBar]() {
640 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition start");
641 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
642 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation start");
643 if (isNavBar) {
644 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
645 CHECK_NULL_VOID(navBarNode);
646 navBarNode->StartSystemTransitionPush();
647 } else {
648 if (preNode) {
649 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
650 CHECK_NULL_VOID(navDestination);
651 navDestination->StartSystemTransitionPush(false);
652 }
653 }
654 // curNode
655 if (curNode) {
656 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
657 CHECK_NULL_VOID(curNavdestination);
658 curNavdestination->StartSystemTransitionPush(true);
659 }
660 }, option.GetOnFinishEvent());
661 if (newPushAnimation) {
662 pushAnimations_.emplace_back(newPushAnimation);
663 }
664 auto maskAnimation = MaskAnimation(preNode, false);
665 if (maskAnimation) {
666 pushAnimations_.emplace_back(maskAnimation);
667 }
668 CHECK_NULL_VOID(curNode);
669 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
670 CHECK_NULL_VOID(curNavdestination);
671
672 // title opacity
673 auto titleOpacityAnimation = curNavdestination->TitleOpacityAnimation(true);
674 if (titleOpacityAnimation) {
675 pushAnimations_.emplace_back(titleOpacityAnimation);
676 }
677 // backIcon opacity
678 auto backButtonAnimation = curNavdestination->BackButtonAnimation(true);
679 if (backButtonAnimation) {
680 pushAnimations_.emplace_back(backButtonAnimation);
681 }
682 }
683
TransitionAnimationIsValid(const RefPtr<FrameNode> & node,bool isNavBar)684 RefPtr<FrameNode> NavigationGroupNode::TransitionAnimationIsValid(const RefPtr<FrameNode>& node, bool isNavBar)
685 {
686 if (isNavBar) {
687 return node;
688 }
689 auto destination = AceType::DynamicCast<NavDestinationGroupNode>(node);
690 if (destination && destination->GetSystemTransitionType() == NavigationSystemTransitionType::NONE) {
691 return nullptr;
692 }
693 return node;
694 }
695
TransitionWithPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)696 void NavigationGroupNode::TransitionWithPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
697 bool isNavBar)
698 {
699 CHECK_NULL_VOID(preNode);
700 CHECK_NULL_VOID(curNode);
701
702 // Create animation callback
703 CleanPushAnimations();
704 AnimationFinishCallback callback = [weakPreNode = WeakPtr<FrameNode>(preNode),
705 weakNavigation = WeakClaim(this),
706 weakCurNode = WeakPtr<FrameNode>(curNode),
707 isNavBar] {
708 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition end");
709 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
710 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation end");
711 auto navigation = weakNavigation.Upgrade();
712 CHECK_NULL_VOID(navigation);
713 auto preNode = weakPreNode.Upgrade();
714 while (preNode) {
715 if (isNavBar) {
716 auto navbar = AceType::DynamicCast<NavBarNode>(preNode);
717 CHECK_NULL_VOID(navbar);
718 navbar->SystemTransitionPushAction(false);
719 bool needSetInvisible = navbar->GetTransitionType() == PageTransitionType::EXIT_PUSH;
720 navigation->SetNeedSetInvisible(needSetInvisible);
721 bool isInvisible = navbar->IsNodeInvisible(navigation);
722 if (needSetInvisible && isInvisible) {
723 preNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
724 preNode->SetJSViewActive(false);
725 navigation->NotifyPageHide();
726 }
727 } else {
728 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
729 CHECK_NULL_VOID(preDestination);
730 if (preDestination->NeedRemoveInPush()) {
731 navigation->hideNodes_.emplace_back(std::make_pair(preDestination, true));
732 break;
733 }
734 preDestination->SystemTransitionPushCallback(false);
735 }
736 break;
737 }
738 auto curNode = weakCurNode.Upgrade();
739 if (curNode) {
740 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
741 CHECK_NULL_VOID(curNavDestination);
742 curNavDestination->SystemTransitionPushCallback(true);
743 }
744 navigation->RemoveDialogDestination();
745 auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
746 navigation->OnAccessibilityEvent(
747 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
748 navigation->isOnAnimation_ = false;
749 navigation->CleanPushAnimations();
750 auto pattern = navigation->GetPattern<NavigationPattern>();
751 CHECK_NULL_VOID(pattern);
752 pattern->CheckContentNeedMeasure(navigation);
753 };
754
755 auto preNodeNew = TransitionAnimationIsValid(preNode, isNavBar);
756 auto curNodeNew = TransitionAnimationIsValid(curNode, isNavBar);
757 if (preNodeNew != nullptr || curNodeNew != nullptr) {
758 CreateAnimationWithPush(preNodeNew, curNodeNew, callback, isNavBar);
759 }
760
761 isOnAnimation_ = true;
762 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
763 CHECK_NULL_VOID(curNavDestination);
764 if (AceChecker::IsPerformanceCheckEnabled()) {
765 int64_t startTime = GetSysTimestamp();
766 auto pipeline = AceType::DynamicCast<NG::PipelineContext>(PipelineContext::GetCurrentContext());
767 // After completing layout tasks at all nodes on the page, perform performance testing and management
768 pipeline->AddAfterLayoutTask([weakNav = WeakClaim(this), weakNode = WeakPtr<FrameNode>(curNode), startTime,
769 path = curNavDestination->GetNavDestinationPathInfo()]() {
770 auto navigation = weakNav.Upgrade();
771 CHECK_NULL_VOID(navigation);
772 auto curNode = weakNode.Upgrade();
773 int64_t endTime = GetSysTimestamp();
774 CHECK_NULL_VOID(curNode);
775 PerformanceCheckNodeMap nodeMap;
776 curNode->GetPerformanceCheckData(nodeMap);
777 AceScopedPerformanceCheck::RecordPerformanceCheckData(nodeMap, endTime - startTime, path);
778 });
779 }
780 #if !defined(ACE_UNITTEST)
781 TransparentNodeDetector::GetInstance().PostCheckNodeTransparentTask(curNode);
782 #endif
783 #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM)
784 UiSessionManager::GetInstance().OnRouterChange(navigationPathInfo_, "navigationPushPage");
785 #endif
786 }
787
MaskAnimation(const RefPtr<FrameNode> & node,bool isTransitionIn)788 std::shared_ptr<AnimationUtils::Animation> NavigationGroupNode::MaskAnimation(const RefPtr<FrameNode>& node,
789 bool isTransitionIn)
790 {
791 CHECK_NULL_RETURN(node, nullptr);
792 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
793 if (navDestination && navDestination->TransitionContentInValid()) {
794 return nullptr;
795 }
796 AnimationOption maskOption;
797 maskOption.SetCurve(Curves::FRICTION);
798 maskOption.SetDuration(MASK_DURATION);
799 maskOption.SetFillMode(FillMode::FORWARDS);
800 auto renderContext = node->GetRenderContext();
801 CHECK_NULL_RETURN(renderContext, nullptr);
802 if (isTransitionIn) {
803 renderContext->SetActualForegroundColor(MASK_COLOR);
804 return AnimationUtils::StartAnimation(
805 maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
806 auto context = weakRender.Upgrade();
807 CHECK_NULL_VOID(context);
808 context->SetActualForegroundColor(Color::TRANSPARENT);
809 });
810 }
811 renderContext->SetActualForegroundColor(Color::TRANSPARENT);
812 return AnimationUtils::StartAnimation(
813 maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
814 auto context = weakRender.Upgrade();
815 CHECK_NULL_VOID(context);
816 context->SetActualForegroundColor(MASK_COLOR);
817 });
818 }
819
TransitionWithReplace(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)820 void NavigationGroupNode::TransitionWithReplace(
821 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode, bool isNavBar)
822 {
823 CHECK_NULL_VOID(preNode);
824 CHECK_NULL_VOID(curNode);
825 AnimationOption option;
826 option.SetCurve(replaceCurve);
827 option.SetFillMode(FillMode::FORWARDS);
828 option.SetDuration(DEFAULT_REPLACE_DURATION);
829 option.SetOnFinishEvent([weakPreNode = WeakPtr<FrameNode>(preNode), weakNavigation = WeakClaim(this),
830 isNavBar]() {
831 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation replace animation end");
832 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition end");
833 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
834 auto preNode = weakPreNode.Upgrade();
835 CHECK_NULL_VOID(preNode);
836 auto navigationNode = weakNavigation.Upgrade();
837 CHECK_NULL_VOID(navigationNode);
838 navigationNode->isOnAnimation_ = false;
839 auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
840 navigationNode->OnAccessibilityEvent(
841 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
842 navigationNode->DealNavigationExit(preNode, isNavBar);
843 auto context = PipelineContext::GetCurrentContext();
844 CHECK_NULL_VOID(context);
845 context->MarkNeedFlushMouseEvent();
846 });
847 preNode->GetEventHub<EventHub>()->SetEnabledInternal(false);
848 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
849 if (curNavDestination && curNavDestination->IsNeedContentTransition()) {
850 curNode->GetRenderContext()->UpdateOpacity(0.0f);
851 }
852 if (!isNavBar) {
853 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
854 if (navDestination) {
855 navDestination->SetIsOnAnimation(true);
856 }
857 }
858 AnimationUtils::Animate(
859 option,
860 [curNode]() {
861 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition start");
862 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
863 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
864 if (curNavDestination && curNavDestination->IsNeedContentTransition()) {
865 curNode->GetRenderContext()->UpdateOpacity(1.0f);
866 }
867 },
868 option.GetOnFinishEvent());
869 isOnAnimation_ = true;
870 }
871
OnInspectorIdUpdate(const std::string & id)872 void NavigationGroupNode::OnInspectorIdUpdate(const std::string& id)
873 {
874 auto context = PipelineContext::GetCurrentContext();
875 CHECK_NULL_VOID(context);
876 context->AddOrReplaceNavigationNode(id, WeakClaim(this));
877 curId_ = id;
878 }
879
DealNavigationExit(const RefPtr<FrameNode> & preNode,bool isNavBar,bool isAnimated)880 void NavigationGroupNode::DealNavigationExit(const RefPtr<FrameNode>& preNode, bool isNavBar, bool isAnimated)
881 {
882 CHECK_NULL_VOID(preNode);
883 if (preNode->GetEventHub<EventHub>()) {
884 preNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
885 }
886 if (isNavBar && isAnimated) {
887 SetNeedSetInvisible(true);
888 return;
889 }
890 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
891 CHECK_NULL_VOID(navDestinationNode);
892 navDestinationNode->SetIsOnAnimation(false);
893 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
894 CHECK_NULL_VOID(navDestinationPattern);
895 auto navigationPattern = GetPattern<NavigationPattern>();
896 CHECK_NULL_VOID(navigationPattern);
897 auto stack = navigationPattern->GetNavigationStack();
898 bool isInStack = stack->FindIndex(navDestinationPattern->GetName(),
899 navDestinationPattern->GetCustomNode(), true) != -1;
900 if (isInStack) {
901 RemoveDialogDestination(true);
902 auto preContext = navDestinationNode->GetRenderContext();
903 CHECK_NULL_VOID(preContext);
904 preContext->UpdateZIndex(0);
905 return;
906 }
907 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
908 if (shallowBuilder) {
909 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
910 }
911 // remove old navdestination node
912 if (navDestinationNode->GetContentNode()) {
913 navDestinationNode->GetContentNode()->Clean();
914 }
915 auto parent = AceType::DynamicCast<FrameNode>(preNode->GetParent());
916 CHECK_NULL_VOID(parent);
917 parent->RemoveChild(preNode);
918 RemoveDialogDestination(true);
919 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
920 }
921
NotifyPageHide()922 void NavigationGroupNode::NotifyPageHide()
923 {
924 auto context = PipelineContext::GetCurrentContext();
925 CHECK_NULL_VOID(context);
926 auto stageManager = context->GetStageManager();
927 CHECK_NULL_VOID(stageManager);
928 auto container = Container::Current();
929 CHECK_NULL_VOID(container);
930 auto pageUrlChecker = container->GetPageUrlChecker();
931 CHECK_NULL_VOID(pageUrlChecker);
932 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
933 CHECK_NULL_VOID(pageNode);
934 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
935 CHECK_NULL_VOID(pagePattern);
936 auto pageInfo = pagePattern->GetPageInfo();
937 CHECK_NULL_VOID(pageInfo);
938 pageUrlChecker->NotifyPageHide(pageInfo->GetPageUrl());
939 }
940
UpdateLastStandardIndex()941 void NavigationGroupNode::UpdateLastStandardIndex()
942 {
943 // remove the impact of last standard index
944 lastStandardIndex_ = -1;
945 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
946 CHECK_NULL_VOID(navigationPattern);
947 auto navigationStack = navigationPattern->GetNavigationStack();
948 CHECK_NULL_VOID(navigationStack);
949 const auto& navDestinationNodes = navigationStack->GetAllNavDestinationNodes();
950 if (navDestinationNodes.size() == 0) {
951 return;
952 }
953 for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1; index >= 0; index--) {
954 const auto& curPath = navDestinationNodes[index];
955 const auto& uiNode = curPath.second;
956 if (!uiNode) {
957 continue;
958 }
959 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
960 if (navDestinationNode && navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
961 lastStandardIndex_ = index;
962 return;
963 }
964 }
965 }
966
UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode> & navDestination,const RefPtr<UINode> & remainChild,int32_t index,size_t destinationSize,const RefPtr<UINode> & preLastStandardNode)967 bool NavigationGroupNode::UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode>& navDestination,
968 const RefPtr<UINode>& remainChild, int32_t index, size_t destinationSize, const RefPtr<UINode>& preLastStandardNode)
969 {
970 CHECK_NULL_RETURN(navDestination, false);
971 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
972 CHECK_NULL_RETURN(eventHub, false);
973 if (index == static_cast<int32_t>(destinationSize) - 1) {
974 // process shallow builder
975 navDestination->ProcessShallowBuilder();
976 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE, true);
977 navDestination->SetJSViewActive(true);
978 navDestination->GetEventHub<EventHub>()->SetEnabledInternal(true);
979 // for the navDestination at the top, FireChangeEvent
980 eventHub->FireChangeEvent(true);
981 bool hasChanged = CheckNeedMeasure(navDestination->GetLayoutProperty()->GetPropertyChangeFlag());
982 if (!hasChanged && NavigationLayoutAlgorithm::IsAutoHeight(GetLayoutProperty<NavigationLayoutProperty>())) {
983 hasChanged = true;
984 }
985 return hasChanged;
986 }
987 if (index < lastStandardIndex_) {
988 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
989 if (navDestination->IsOnAnimation()) {
990 return false;
991 }
992 if (!pattern || !pattern->GetIsOnShow()) {
993 // push more than one standard navDestination, need to set invisible below newTopDestination
994 auto navDestinationLayoutProperty = navDestination->GetLayoutProperty();
995 CHECK_NULL_RETURN(navDestinationLayoutProperty, false);
996 navDestinationLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
997 navDestination->SetJSViewActive(false);
998 return false;
999 }
1000 eventHub->FireChangeEvent(false);
1001 if (pattern->GetCustomNode() != remainChild) {
1002 if (navDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG ||
1003 navDestination == AceType::DynamicCast<NavDestinationGroupNode>(preLastStandardNode)) {
1004 hideNodes_.insert(hideNodes_.begin(), std::pair(navDestination, false));
1005 } else {
1006 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1007 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1008 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1009 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1010 }
1011 }
1012 return false;
1013 }
1014 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1015 if (navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode() != remainChild &&
1016 !navDestination->IsOnAnimation()) {
1017 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
1018 navDestination->SetJSViewActive(true);
1019 }
1020 return false;
1021 }
1022
CreateAnimationOption(const RefPtr<Curve> & curve,FillMode mode,int32_t duration,const AnimationFinishCallback & callback)1023 AnimationOption NavigationGroupNode::CreateAnimationOption(const RefPtr<Curve>& curve, FillMode mode,
1024 int32_t duration, const AnimationFinishCallback& callback)
1025 {
1026 AnimationOption option;
1027 option.SetCurve(curve);
1028 option.SetFillMode(mode);
1029 option.SetDuration(duration);
1030 if (callback != nullptr) {
1031 option.SetOnFinishEvent(callback);
1032 }
1033 return option;
1034 }
1035
GetNavigationMode()1036 NavigationMode NavigationGroupNode::GetNavigationMode()
1037 {
1038 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1039 CHECK_NULL_RETURN(navigationPattern, NavigationMode::AUTO);
1040 return navigationPattern->GetNavigationMode();
1041 }
1042
OnDetachFromMainTree(bool recursive,PipelineContext * context)1043 void NavigationGroupNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
1044 {
1045 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1046 if (pattern) {
1047 pattern->DetachNavigationStackFromParent();
1048 pattern->RemoveFromDumpManager();
1049 }
1050
1051 GroupNode::OnDetachFromMainTree(recursive, context);
1052 }
1053
FindNavigationParent(const std::string & parentName)1054 bool NavigationGroupNode::FindNavigationParent(const std::string& parentName)
1055 {
1056 auto parent = GetParent();
1057 while (parent) {
1058 if (parent->GetTag() == parentName) {
1059 AddDestinationNode(parent);
1060 return true;
1061 }
1062 parent = parent->GetParent();
1063 }
1064 return parent != nullptr;
1065 }
1066
AddDestinationNode(const RefPtr<UINode> & parent)1067 void NavigationGroupNode::AddDestinationNode(const RefPtr<UINode>& parent)
1068 {
1069 auto destinationNode = AceType::DynamicCast<NavDestinationGroupNode>(parent);
1070 if (destinationNode) {
1071 parentDestinationNode_ = destinationNode;
1072 }
1073 }
1074
OnAttachToMainTree(bool recursive)1075 void NavigationGroupNode::OnAttachToMainTree(bool recursive)
1076 {
1077 GroupNode::OnAttachToMainTree(recursive);
1078
1079 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1080 if (pattern) {
1081 pattern->AttachNavigationStackToParent();
1082 pattern->AddToDumpManager();
1083 }
1084 auto parent = GetParent();
1085 while (parent) {
1086 if (parent->GetTag() == V2::JS_VIEW_ETS_TAG) {
1087 break;
1088 }
1089 parent = parent->GetParent();
1090 }
1091 if (parent) {
1092 pattern->SetParentCustomNode(parent);
1093 } else {
1094 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "parent custom node is nullptr");
1095 }
1096 bool findNavdestination = FindNavigationParent(V2::NAVDESTINATION_VIEW_ETS_TAG);
1097 auto pipelineContext = PipelineContext::GetCurrentContext();
1098 CHECK_NULL_VOID(pipelineContext);
1099 auto stageManager = pipelineContext->GetStageManager();
1100 CHECK_NULL_VOID(stageManager);
1101 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1102 CHECK_NULL_VOID(pageNode);
1103 auto pagePattern = pageNode->GetPattern<PagePattern>();
1104 CHECK_NULL_VOID(pagePattern);
1105 CHECK_NULL_VOID(pagePattern->GetPageInfo());
1106 int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
1107 if (!findNavdestination) {
1108 pipelineContext->AddNavigationNode(pageId, WeakClaim(this));
1109 }
1110 }
1111
FireHideNodeChange(NavDestinationLifecycle lifecycle)1112 void NavigationGroupNode::FireHideNodeChange(NavDestinationLifecycle lifecycle)
1113 {
1114 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1115 for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); ++iter) {
1116 auto navDestination = iter->first;
1117 if (!navDestination) {
1118 continue;
1119 }
1120 if (lifecycle == NavDestinationLifecycle::ON_WILL_DISAPPEAR) {
1121 if (iter->second) {
1122 navigationPattern->NotifyDestinationLifecycle(
1123 navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1124 }
1125 continue;
1126 }
1127 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1128 if (!pattern->GetIsOnShow()) {
1129 continue;
1130 }
1131 if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE) {
1132 navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1133 continue;
1134 }
1135 if (lifecycle == NavDestinationLifecycle::ON_HIDE) {
1136 navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1137 }
1138 }
1139 }
1140
RemoveDialogDestination(bool isReplace)1141 void NavigationGroupNode::RemoveDialogDestination(bool isReplace)
1142 {
1143 for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); iter++) {
1144 auto navDestination = iter->first;
1145 if (!navDestination) {
1146 continue;
1147 }
1148 if (!iter->second) {
1149 // navDestination node don't need to remove, update visibility invisible
1150 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1151 navDestination->SetJSViewActive(false);
1152 if (!isReplace) {
1153 continue;
1154 }
1155 auto context = navDestination->GetRenderContext();
1156 if (!context) {
1157 continue;
1158 }
1159 context->UpdateZIndex(0);
1160 continue;
1161 }
1162 auto parent = navDestination->GetParent();
1163 if (!parent) {
1164 continue;
1165 }
1166 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1167 if (!navDestinationPattern) {
1168 continue;
1169 }
1170 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
1171 if (shallowBuilder) {
1172 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
1173 }
1174 if (navDestination->GetContentNode()) {
1175 navDestination->GetContentNode()->Clean();
1176 }
1177 parent->RemoveChild(navDestination);
1178 }
1179 hideNodes_.clear();
1180 }
1181
DealRemoveDestination(const RefPtr<NavDestinationGroupNode> & navDestination)1182 void NavigationGroupNode::DealRemoveDestination(const RefPtr<NavDestinationGroupNode>& navDestination)
1183 {
1184 // remove content child
1185 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
1186 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1187 if (navDestinationPattern->GetIsOnShow()) {
1188 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1189 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1190 navDestinationPattern->SetIsOnShow(false);
1191 }
1192 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1193 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
1194 if (shallowBuilder) {
1195 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
1196 }
1197 if (navDestination->GetContentNode()) {
1198 navDestination->GetContentNode()->Clean();
1199 }
1200 contentNode_->RemoveChild(navDestination, true);
1201 }
1202
CreateAnimationWithDialogPop(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> preNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1203 void NavigationGroupNode::CreateAnimationWithDialogPop(const AnimationFinishCallback callback,
1204 const std::vector<WeakPtr<FrameNode>> preNavList,
1205 const std::vector<WeakPtr<FrameNode>> curNavList)
1206 {
1207 // start transition animation
1208 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1209 callback);
1210 auto newPopAnimation = AnimationUtils::StartAnimation(option, [
1211 weakNavigation = WeakClaim(this), curNavList, preNavList]() {
1212 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1213 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation start");
1214
1215 // do preNode transition
1216 auto navigation = weakNavigation.Upgrade();
1217 CHECK_NULL_VOID(navigation);
1218 for (auto iter: preNavList) {
1219 auto preNode = iter.Upgrade();
1220 CHECK_NULL_VOID(preNode);
1221 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1222 if (preNavDesNode) {
1223 preNavDesNode->StartSystemTransitionPop(false);
1224 }
1225 }
1226
1227 // do currentNode transition
1228 for (auto iter: curNavList) {
1229 auto curNode = iter.Upgrade();
1230 CHECK_NULL_VOID(curNode);
1231 if (curNode->GetTag() == V2::NAVBAR_ETS_TAG) {
1232 auto curNavbar = AceType::DynamicCast<NavBarNode>(curNode);
1233 CHECK_NULL_VOID(curNavbar);
1234 curNavbar->StartSystemTransitionPop();
1235 } else {
1236 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1237 CHECK_NULL_VOID(curDestination);
1238 curDestination->StartSystemTransitionPop(true);
1239 }
1240 }
1241 }, option.GetOnFinishEvent());
1242 if (newPopAnimation) {
1243 popAnimations_.emplace_back(newPopAnimation);
1244 }
1245 isOnAnimation_ = true;
1246 }
1247
TransitionWithDialogPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1248 void NavigationGroupNode::TransitionWithDialogPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1249 bool isNavBar)
1250 {
1251 CHECK_NULL_VOID(preNode);
1252 std::vector<WeakPtr<FrameNode>> preNavList;
1253 InitPopPreList(preNode, preNavList);
1254 std::vector<WeakPtr<FrameNode>> curNavList;
1255 bool isNavbarNeedAnimation = lastStandardIndex_ == -1 || isNavBar;
1256 InitPopCurList(curNode, curNavList, isNavbarNeedAnimation);
1257
1258 /* create animation finish callback */
1259 CleanPopAnimations();
1260 AnimationFinishCallback callback = [preNavList, weakNavigation = WeakClaim(this)] {
1261 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation end");
1262 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1263 auto navigation = weakNavigation.Upgrade();
1264 CHECK_NULL_VOID(navigation);
1265 navigation->isOnAnimation_ = false;
1266 navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1267 navigation->CleanPopAnimations();
1268 for (auto iter = preNavList.rbegin(); iter != preNavList.rend(); ++iter) {
1269 auto preNode = (*iter).Upgrade();
1270 CHECK_NULL_VOID(preNode);
1271 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1272 CHECK_NULL_VOID(preNavDesNode);
1273 if (preNavDesNode->SystemTransitionPopCallback()) {
1274 auto parent = preNavDesNode->GetParent();
1275 CHECK_NULL_VOID(parent);
1276 parent->RemoveChild(preNavDesNode);
1277 }
1278 navigation->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1279 }
1280 navigation->RemoveDialogDestination();
1281 auto context = PipelineContext::GetCurrentContext();
1282 CHECK_NULL_VOID(context);
1283 context->MarkNeedFlushMouseEvent();
1284 };
1285 CreateAnimationWithDialogPop(callback, preNavList, curNavList);
1286 }
1287
CreateAnimationWithDialogPush(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> prevNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1288 void NavigationGroupNode::CreateAnimationWithDialogPush(const AnimationFinishCallback callback,
1289 const std::vector<WeakPtr<FrameNode>> prevNavList, const std::vector<WeakPtr<FrameNode>> curNavList)
1290 {
1291 // start transition animation
1292 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1293 callback);
1294 auto newPushAnimation = AnimationUtils::StartAnimation(option,
1295 [weakNavigation = WeakClaim(this), prevNavList, curNavList]() {
1296 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1297 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
1298 auto navigation = weakNavigation.Upgrade();
1299 CHECK_NULL_VOID(navigation);
1300
1301 // preNode do EXIT PUSH animation
1302 for (auto iter : prevNavList) {
1303 auto preNode = iter.Upgrade();
1304 CHECK_NULL_VOID(preNode);
1305 if (preNode->GetTag() == V2::NAVBAR_ETS_TAG &&
1306 navigation->GetNavigationMode() == NavigationMode::STACK) {
1307 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
1308 CHECK_NULL_VOID(navBarNode);
1309 navBarNode->StartSystemTransitionPush();
1310 } else {
1311 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1312 CHECK_NULL_VOID(preDestination);
1313 preDestination->StartSystemTransitionPush(false);
1314 }
1315 }
1316 // curNode do ENTER PUSH animation
1317 for (auto iter : curNavList) {
1318 auto curNode = iter.Upgrade();
1319 CHECK_NULL_VOID(curNode);
1320 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1321 if (curDestination) {
1322 curDestination->StartSystemTransitionPush(true);
1323 }
1324 }
1325 }, option.GetOnFinishEvent());
1326 if (newPushAnimation) {
1327 pushAnimations_.emplace_back(newPushAnimation);
1328 }
1329 isOnAnimation_ = true;
1330 }
1331
PreNodeFinishCallback(const RefPtr<FrameNode> & preNode)1332 void NavigationGroupNode::PreNodeFinishCallback(const RefPtr<FrameNode>& preNode)
1333 {
1334 CHECK_NULL_VOID(preNode);
1335 if (preNode->GetTag() == V2::NAVBAR_ETS_TAG) {
1336 auto preNavbar = AceType::DynamicCast<NavBarNode>(preNode);
1337 CHECK_NULL_VOID(preNavbar);
1338 preNavbar->SystemTransitionPushAction(false);
1339 bool needSetInvisible = preNavbar->GetTransitionType() == PageTransitionType::EXIT_PUSH;
1340 SetNeedSetInvisible(needSetInvisible);
1341 if (needSetInvisible && GetNavigationMode() == NavigationMode::STACK) {
1342 auto property = preNavbar->GetLayoutProperty();
1343 CHECK_NULL_VOID(property);
1344 property->UpdateVisibility(VisibleType::INVISIBLE);
1345 preNavbar->SetJSViewActive(false);
1346 NotifyPageHide();
1347 }
1348 return;
1349 }
1350 if (preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1351 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1352 if (preDestination && preDestination->NeedRemoveInPush()) {
1353 hideNodes_.emplace_back(std::make_pair(preDestination, true));
1354 }
1355 preDestination->SystemTransitionPushCallback(false);
1356 }
1357 }
1358
TransitionWithDialogPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1359 void NavigationGroupNode::TransitionWithDialogPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1360 bool isNavBar)
1361 {
1362 if (!preNode || !curNode) {
1363 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "dialog push animation terminated");
1364 return;
1365 }
1366 CleanPushAnimations();
1367
1368 // initialization
1369 bool isNavbarNeedAnimation = preLastStandardIndex_ == -1 || isNavBar;
1370 std::vector<WeakPtr<FrameNode>> prevNavList;
1371 InitPushPreList(preNode, prevNavList, isNavbarNeedAnimation);
1372 std::vector<WeakPtr<FrameNode>> curNavList;
1373 InitPushCurList(curNode, curNavList);
1374 AnimationFinishCallback callback = [weakNavigation = WeakClaim(this), prevNavList, curNavList] {
1375 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1376 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1377 auto navigation = weakNavigation.Upgrade();
1378 CHECK_NULL_VOID(navigation);
1379 for (auto iter : prevNavList) {
1380 auto preNode = iter.Upgrade();
1381 CHECK_NULL_VOID(preNode);
1382 navigation->PreNodeFinishCallback(preNode);
1383 }
1384 for (auto iter : curNavList) {
1385 auto curNode = iter.Upgrade();
1386 CHECK_NULL_VOID(curNode);
1387 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1388 CHECK_NULL_VOID(curNavDestination);
1389 curNavDestination->SystemTransitionPushCallback(true);
1390 }
1391 navigation->RemoveDialogDestination();
1392 navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1393 navigation->isOnAnimation_ = false;
1394 navigation->CleanPushAnimations();
1395 };
1396 CreateAnimationWithDialogPush(callback, prevNavList, curNavList);
1397 }
1398
InitDialogTransition(const RefPtr<NavDestinationGroupNode> & node,bool isTransitionIn)1399 void NavigationGroupNode::InitDialogTransition(const RefPtr<NavDestinationGroupNode>& node, bool isTransitionIn)
1400 {
1401 CHECK_NULL_VOID(node);
1402 auto contentNode = AceType::DynamicCast<FrameNode>(node->GetContentNode());
1403 CHECK_NULL_VOID(contentNode);
1404 auto context = contentNode->GetRenderContext();
1405 CHECK_NULL_VOID(context);
1406 if (isTransitionIn) {
1407 context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
1408 return;
1409 }
1410 context->UpdateTransformTranslate({ 0.0f,
1411 contentNode->GetGeometryNode()->GetFrameSize().Height(), 0.0f });
1412 }
1413
StartDialogtransition(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isTransitionIn)1414 void NavigationGroupNode::StartDialogtransition(const RefPtr<FrameNode>& preNode,
1415 const RefPtr<FrameNode>& curNode, bool isTransitionIn)
1416 {
1417 AnimationOption option;
1418 const RefPtr<InterpolatingSpring> curve =
1419 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
1420 const float defaultAmplitudePx = 0.005f;
1421 curve->UpdateMinimumAmplitudeRatio(defaultAmplitudePx);
1422 option.SetCurve(curve);
1423 option.SetFillMode(FillMode::FORWARDS);
1424 if (isTransitionIn) {
1425 DialogTransitionPushAnimation(preNode, curNode, option);
1426 } else {
1427 DialogTransitionPopAnimation(preNode, curNode, option);
1428 }
1429 }
1430
DialogTransitionPushAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)1431 void NavigationGroupNode::DialogTransitionPushAnimation(const RefPtr<FrameNode>& preNode,
1432 const RefPtr<FrameNode>& curNode, AnimationOption option)
1433 {
1434 CHECK_NULL_VOID(curNode);
1435 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1436 CHECK_NULL_VOID(curNavdestination);
1437 int32_t end = curNavdestination->GetIndex();
1438 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1439 CHECK_NULL_VOID(navigationPattern);
1440 const auto& navDestinationNodesCur = navigationPattern->GetAllNavDestinationNodes();
1441 int32_t start = 0;
1442 if (preNode && preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1443 auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1444 CHECK_NULL_VOID(navdestination);
1445 start = navdestination->GetIndex() + 1;
1446 }
1447 // find the nodes need to do upward ENTER translation
1448 std::vector<WeakPtr<NavDestinationGroupNode>> curNavList;
1449 for (int32_t index = start; index <= end; index++) {
1450 auto navdestination = GetNavDestinationNode(navDestinationNodesCur[index].second);
1451 CHECK_NULL_VOID(navdestination);
1452 auto curNode = AceType::DynamicCast<FrameNode>(navdestination);
1453 CHECK_NULL_VOID(curNode);
1454 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1455 CHECK_NULL_VOID(curNavDestination);
1456 curNavDestination->InitDialogTransition(false);
1457 curNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(curNavDestination));
1458 }
1459 CleanPushAnimations();
1460 option.SetOnFinishEvent([weakNavigation = WeakClaim(this)] {
1461 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1462 auto navigation = weakNavigation.Upgrade();
1463 CHECK_NULL_VOID(navigation);
1464 navigation->CleanPushAnimations();
1465 });
1466 auto newPushAnimation = AnimationUtils::StartAnimation(option,
1467 [curNavList]() {
1468 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
1469 for (auto iter: curNavList) {
1470 auto curNode = iter.Upgrade();
1471 if (curNode) {
1472 curNode->InitDialogTransition(true);
1473 }
1474 }
1475 },
1476 option.GetOnFinishEvent());
1477 if (newPushAnimation) {
1478 pushAnimations_.emplace_back(newPushAnimation);
1479 }
1480 }
1481
FindNodesPoped(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)1482 std::vector<WeakPtr<NavDestinationGroupNode>> NavigationGroupNode::FindNodesPoped(
1483 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
1484 {
1485 std::vector<WeakPtr<NavDestinationGroupNode>> preNavList;
1486 auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1487 CHECK_NULL_RETURN(preNavdestinationNode, preNavList);
1488 auto end = preNavdestinationNode->GetIndex();
1489 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1490 CHECK_NULL_RETURN(navigationPattern, preNavList);
1491 const auto& navDestinationNodesPre = navigationPattern->GetAllNavDestinationNodesPrev();
1492 int32_t start = 0;
1493 if (curNode && curNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1494 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1495 CHECK_NULL_RETURN(curNavdestination, preNavList);
1496 start = curNavdestination->GetIndex() + 1;
1497 }
1498 // find the nodes need to do downward EXIT translation
1499 for (int32_t index = start; index <= end; index++) {
1500 auto node = GetNavDestinationNode(navDestinationNodesPre[index].second.Upgrade());
1501 if (node) {
1502 auto preNode = AceType::DynamicCast<FrameNode>(node);
1503 CHECK_NULL_RETURN(preNode, preNavList);
1504 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1505 CHECK_NULL_RETURN(preNavDesNode, preNavList);
1506 preNavDesNode->InitDialogTransition(true);
1507 preNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(preNavDesNode));
1508 }
1509 }
1510 return preNavList;
1511 }
1512
DialogTransitionPopAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)1513 void NavigationGroupNode::DialogTransitionPopAnimation(const RefPtr<FrameNode>& preNode,
1514 const RefPtr<FrameNode>& curNode, AnimationOption option)
1515 {
1516 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1517 CHECK_NULL_VOID(navigationPattern);
1518 auto preNavList = FindNodesPoped(preNode, curNode);
1519 CleanPopAnimations();
1520 option.SetOnFinishEvent(
1521 [preNavList, weakNavigation = WeakClaim(this)] {
1522 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation end");
1523 for (auto iter: preNavList) {
1524 auto preNode = iter.Upgrade();
1525 CHECK_NULL_VOID(preNode);
1526 auto parent = preNode->GetParent();
1527 CHECK_NULL_VOID(parent);
1528 parent->RemoveChild(preNode);
1529 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1530 }
1531 auto context = PipelineContext::GetCurrentContext();
1532 CHECK_NULL_VOID(context);
1533 context->MarkNeedFlushMouseEvent();
1534 auto navigation = weakNavigation.Upgrade();
1535 CHECK_NULL_VOID(navigation);
1536 navigation->CleanPopAnimations();
1537 });
1538 auto newPopAnimation = AnimationUtils::StartAnimation(
1539 option, [weakNavigation = WeakClaim(this), preNavList]() {
1540 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation start");
1541 auto navigation = weakNavigation.Upgrade();
1542 CHECK_NULL_VOID(navigation);
1543 for (auto iter: preNavList) {
1544 auto preNode = iter.Upgrade();
1545 CHECK_NULL_VOID(preNode);
1546 preNode->InitDialogTransition(false);
1547 }
1548 }, option.GetOnFinishEvent());
1549 if (newPopAnimation) {
1550 popAnimations_.emplace_back(newPopAnimation);
1551 }
1552 }
1553
InitPopPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & preNavList)1554 void NavigationGroupNode::InitPopPreList(const RefPtr<FrameNode>& preNode, std::vector<WeakPtr<FrameNode>>& preNavList)
1555 {
1556 // find all the nodes need to do EXIT_POP
1557 int32_t preStartIndex = preLastStandardIndex_;
1558 if (preStartIndex == -1) {
1559 // eg. clear + push page1
1560 preStartIndex = 0;
1561 }
1562 auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1563 CHECK_NULL_VOID(preNavdestinationNode);
1564 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1565 CHECK_NULL_VOID(navigationPattern);
1566 const auto& preNavDestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
1567
1568 // find the nodes need to do EXIT_POP
1569 for (int32_t index = preStartIndex; index < static_cast<int32_t>(preNavDestinationNodes.size()); index++) {
1570 auto node = GetNavDestinationNode(preNavDestinationNodes[index].second.Upgrade());
1571 CHECK_NULL_VOID(node);
1572 auto preNode = AceType::DynamicCast<FrameNode>(node);
1573 CHECK_NULL_VOID(preNode);
1574 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1575 if (preNavDestination) {
1576 preNavDestination->InitSystemTransitionPop(false);
1577 preNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1578 }
1579 }
1580 }
1581
InitPopCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList,bool isNavbarNeedAnimation)1582 void NavigationGroupNode::InitPopCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList,
1583 bool isNavbarNeedAnimation)
1584 {
1585 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1586 CHECK_NULL_VOID(navigationPattern);
1587 auto curNavdestionNodes = navigationPattern->GetAllNavDestinationNodes();
1588 auto curStartIndex = lastStandardIndex_;
1589
1590 // navBar + D or navBar should be in animation
1591 if (isNavbarNeedAnimation) {
1592 curStartIndex = 0;
1593 }
1594 // if navBar should be in animation, do initialization and visibility should be true
1595 if (isNavbarNeedAnimation && navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
1596 auto preNode = AceType::DynamicCast<FrameNode>(GetNavBarNode());
1597 if (preNode) {
1598 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
1599 CHECK_NULL_VOID(navBarNode);
1600 navBarNode->InitSystemTransitionPop();
1601 curNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1602 SetNeedSetInvisible(false);
1603 }
1604 }
1605 int32_t size = static_cast<int32_t>(curNavdestionNodes.size());
1606 if (size == 0) {
1607 return;
1608 }
1609 // find the nodes need to do ENTER_POP
1610 for (int32_t index = curStartIndex; index < size; index++) {
1611 auto node = GetNavDestinationNode(curNavdestionNodes[index].second);
1612 CHECK_NULL_VOID(node);
1613 auto curNode = AceType::DynamicCast<FrameNode>(node);
1614 if (curNode) {
1615 auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1616 CHECK_NULL_VOID(navdestination);
1617 navdestination->InitSystemTransitionPop(true);
1618 curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
1619 }
1620 }
1621 }
1622
InitPushPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & prevNavList,bool isNavbarNeedAnimation)1623 void NavigationGroupNode::InitPushPreList(const RefPtr<FrameNode>& preNode,
1624 std::vector<WeakPtr<FrameNode>>& prevNavList, bool isNavbarNeedAnimation)
1625 {
1626 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1627 CHECK_NULL_VOID(navigationPattern);
1628 auto stack = navigationPattern->GetNavigationStack();
1629 auto& preNavdestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
1630 auto preStartIndex = preLastStandardIndex_;
1631
1632 // find the pre last standard index, if there is no pre standard or pre node is single navbar
1633 if (isNavbarNeedAnimation) {
1634 preStartIndex = 0;
1635 }
1636 // if pre node is nav bar or one of preNodes is nav bar and only stack with navbar's animation
1637 if (isNavbarNeedAnimation&& navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
1638 auto preNode = AceType::DynamicCast<FrameNode>(GetNavBarNode());
1639 CHECK_NULL_VOID(preNode);
1640 auto preNavbar = AceType::DynamicCast<NavBarNode>(preNode);
1641 if (preNavbar) {
1642 SetNeedSetInvisible(false);
1643 preNavbar->SystemTransitionPushAction(true);
1644 prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1645 }
1646 }
1647 int32_t size = static_cast<int32_t>(preNavdestinationNodes.size());
1648 if (size == 0) {
1649 return;
1650 }
1651 // find the nodes need to do EXIT_PUSH
1652 for (int32_t index = preStartIndex; index < size; index++) {
1653 auto node = GetNavDestinationNode(preNavdestinationNodes[index].second.Upgrade());
1654 CHECK_NULL_VOID(node);
1655 auto preNode = AceType::DynamicCast<FrameNode>(node);
1656 CHECK_NULL_VOID(preNode);
1657 auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1658 if (preNavdestination) {
1659 preNavdestination->InitSystemTransitionPush(false);
1660 prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1661 }
1662 }
1663 }
1664
InitPushCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList)1665 void NavigationGroupNode::InitPushCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList)
1666 {
1667 // find the nodes need to do ENTER_PUSH
1668 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1669 CHECK_NULL_VOID(navigationPattern);
1670 auto curNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1671 CHECK_NULL_VOID(curNavdestinationNode);
1672 auto curEndIndex = curNavdestinationNode->GetIndex();
1673 auto curStartIndex = lastStandardIndex_;
1674 auto stack = navigationPattern->GetNavigationStack();
1675 for (int32_t index = curStartIndex; index <= curEndIndex; index++) {
1676 auto node = GetNavDestinationNode(stack->Get(index));
1677 CHECK_NULL_VOID(node);
1678 auto curNode = AceType::DynamicCast<FrameNode>(node);
1679 CHECK_NULL_VOID(curNode);
1680 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1681 CHECK_NULL_VOID(curNavDestination);
1682 curNavDestination->InitSystemTransitionPush(true);
1683 curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
1684 }
1685 }
1686 } // namespace OHOS::Ace::NG
1687