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 "interfaces/inner_api/ui_session/ui_session_manager.h"
19 #include "base/log/ace_checker.h"
20 #include "base/perfmonitor/perf_constants.h"
21 #include "base/perfmonitor/perf_monitor.h"
22
23 #if !defined(ACE_UNITTEST)
24 #include "core/components_ng/base/transparent_node_detector.h"
25 #endif
26
27 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
28 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
29 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
30 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
31 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
32 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
33
34 namespace OHOS::Ace::NG {
35 namespace {
36 constexpr int32_t MASK_DURATION = 350;
37 constexpr int32_t DEFAULT_ANIMATION_DURATION = 450;
38 constexpr int32_t DEFAULT_REPLACE_DURATION = 150;
39 constexpr int32_t INVALID_ANIMATION_ID = -1;
40 constexpr int32_t RELEASE_JSCHILD_DELAY_TIME = 50;
41 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
42 const RefPtr<InterpolatingSpring> springCurve = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f);
43 const RefPtr<CubicCurve> replaceCurve = AceType::MakeRefPtr<CubicCurve>(0.33, 0.0, 0.67, 1.0);
44
ExitWindow(PipelineContext * context)45 void ExitWindow(PipelineContext* context)
46 {
47 auto container = Container::Current();
48 CHECK_NULL_VOID(container);
49 if (container->IsUIExtensionWindow()) {
50 container->TerminateUIExtension();
51 } else {
52 auto windowManager = context->GetWindowManager();
53 CHECK_NULL_VOID(windowManager);
54 windowManager->WindowPerformBack();
55 }
56 }
57
UpdateTransitionAnimationId(const RefPtr<FrameNode> & node,int32_t id)58 void UpdateTransitionAnimationId(const RefPtr<FrameNode>& node, int32_t id)
59 {
60 auto navDestinationBaseNode = AceType::DynamicCast<NavDestinationNodeBase>(node);
61 CHECK_NULL_VOID(navDestinationBaseNode);
62 navDestinationBaseNode->UpdateAnimationId(id);
63 }
64
TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode> & navDestination,NavigationOperation operation,bool isEnter)65 int32_t TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode>& navDestination,
66 NavigationOperation operation, bool isEnter)
67 {
68 CHECK_NULL_RETURN(navDestination, INVALID_ANIMATION_ID);
69 return navDestination->DoTransition(operation, isEnter);
70 }
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 = GetContextWithCheck();
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 if (pattern->GetIsPreForceSetList()) {
148 // if page is force set, some node may not on the tree, so we need get page from preNavPathList.
149 auto preNodes = pattern->GetAllNavDestinationNodesPrev();
150 if (beforeLastStandardIndex < preNodes.size() && beforeLastStandardIndex >= 0) {
151 preLastStandardNode = AceType::DynamicCast<NavDestinationGroupNode>(
152 NavigationGroupNode::GetNavDestinationNode(preNodes[beforeLastStandardIndex].second.Upgrade()));
153 }
154 }
155
156 //save preLastStandardIndex_ before update and check whether standard page changed
157 preLastStandardIndex_ = lastStandardIndex_;
158 UpdateLastStandardIndex();
159
160 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "last standard page index is %{public}d", lastStandardIndex_);
161 if (!ReorderNavDestination(navDestinationNodes, navigationContentNode, slot, hasChanged)) {
162 return;
163 }
164
165 for (uint32_t index = 0; index < navDestinationNodes.size(); index++) {
166 const auto& childNode = navDestinationNodes[index];
167 const auto& uiNode = childNode.second;
168 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
169 hasChanged = (UpdateNavDestinationVisibility(navDestination, remainChild, index,
170 navDestinationNodes.size(), preLastStandardNode) || hasChanged);
171 }
172
173 RemoveRedundantNavDestination(
174 navigationContentNode, remainChild, static_cast<int32_t>(slot), hasChanged, preLastStandardNode);
175 if (modeChange) {
176 navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
177 } else if (hasChanged) {
178 navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
179 }
180 }
181
ReorderNavDestination(const std::vector<std::pair<std::string,RefPtr<UINode>>> & navDestinationNodes,RefPtr<FrameNode> & navigationContentNode,int32_t & slot,bool & hasChanged)182 bool NavigationGroupNode::ReorderNavDestination(
183 const std::vector<std::pair<std::string, RefPtr<UINode>>>& navDestinationNodes,
184 RefPtr<FrameNode>& navigationContentNode, int32_t& slot, bool& hasChanged)
185 {
186 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
187 CHECK_NULL_RETURN(pattern, false);
188 for (uint32_t i = 0; i != navDestinationNodes.size(); ++i) {
189 const auto& childNode = navDestinationNodes[i];
190 const auto& uiNode = childNode.second;
191 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
192 if (navDestination == nullptr) {
193 if (pattern->GetNavigationStack()->IsFromRecovery(i) || pattern->GetNavigationStack()->GetIsForceSet(i)) {
194 continue;
195 }
196 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "get destination node failed");
197 return false;
198 }
199 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
200 CHECK_NULL_RETURN(navDestinationPattern, false);
201 navDestinationPattern->SetName(childNode.first);
202 navDestinationPattern->SetCustomNode(uiNode);
203 navDestinationPattern->SetIndex(static_cast<int32_t>(i));
204 SetBackButtonEvent(navDestination);
205 navDestination->SetIndex(i);
206 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
207 if (eventHub && !eventHub->GetOnStateChange()) {
208 auto onStateChangeMap = pattern->GetOnStateChangeMap();
209 auto iter = onStateChangeMap.find(uiNode->GetId());
210 if (iter != onStateChangeMap.end()) {
211 eventHub->SetOnStateChange(iter->second);
212 pattern->DeleteOnStateChangeItem(iter->first);
213 }
214 }
215 int32_t childIndex = navigationContentNode->GetChildIndex(navDestination);
216 if (childIndex < 0) {
217 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "mountToParent navdestinationId:%{public}d, slot:%{public}d",
218 navDestination->GetId(), slot);
219 navDestination->MountToParent(navigationContentNode, slot);
220 hasChanged = true;
221 } else if (childIndex != slot) {
222 navDestination->MovePosition(slot);
223 hasChanged = true;
224 }
225 slot++;
226 }
227 return true;
228 }
229
RemoveRedundantNavDestination(RefPtr<FrameNode> & navigationContentNode,const RefPtr<UINode> & remainChild,int32_t slot,bool & hasChanged,const RefPtr<NavDestinationGroupNode> & preLastStandardNode)230 void NavigationGroupNode::RemoveRedundantNavDestination(RefPtr<FrameNode>& navigationContentNode,
231 const RefPtr<UINode>& remainChild, int32_t slot, bool& hasChanged,
232 const RefPtr<NavDestinationGroupNode>& preLastStandardNode)
233 {
234 auto pattern = GetPattern<NavigationPattern>();
235 RefPtr<UINode> maxAnimatingDestination = nullptr;
236 RefPtr<UINode> remainDestination = GetNavDestinationNode(remainChild);
237 RefPtr<UINode> curTopDestination = navigationContentNode->GetChildAtIndex(slot - 1);
238 // record remove destination size
239 int32_t removeSize = 0;
240 bool hideNodesFinish = false;
241 // record animating destination size
242 int32_t animatingSize = 0;
243 int32_t remainNodeIndex = pattern->IsCurTopNewInstance() ? slot - 1 : slot;
244 while (slot + removeSize + animatingSize < static_cast<int32_t>(navigationContentNode->GetChildren().size())) {
245 // delete useless nodes that are not at the top
246 int32_t candidateIndex = static_cast<int32_t>(navigationContentNode->GetChildren().size()) - 1 - animatingSize;
247 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
248 navigationContentNode->GetChildAtIndex(candidateIndex));
249 if (!navDestination) {
250 navigationContentNode->RemoveChildAtIndex(candidateIndex);
251 hasChanged = true;
252 continue;
253 }
254 navDestination->SetInCurrentStack(false);
255 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
256 if (eventHub) {
257 eventHub->FireChangeEvent(false);
258 }
259 if (navDestination == remainDestination) {
260 if (pattern->IsCurTopNewInstance()) {
261 // remain the last child for push animation, and this child
262 // will be remove in push's animation finish callback
263 navDestination->SetNeedRemoveInPush(true);
264 remainNodeIndex = slot - 1;
265 navDestination->MovePosition(remainNodeIndex);
266 } else {
267 // remain the last child for pop animation
268 remainNodeIndex = slot;
269 navDestination->MovePosition(slot);
270 }
271 ++slot;
272 continue;
273 }
274 // The NavDestination in the EXIT animation needs to be cleaned in the animation onfinish callback.
275 if (navDestination->IsOnAnimation()) {
276 if (navDestination->GetTransitionType() == PageTransitionType::EXIT_POP) {
277 ++animatingSize;
278 continue;
279 }
280 if (navDestination->NeedRemoveInPush()) {
281 if (maxAnimatingDestination == nullptr) {
282 maxAnimatingDestination = navDestination;
283 }
284 ++animatingSize;
285 continue;
286 }
287 }
288 // remove content child
289 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
290 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "remove child: %{public}s", navDestinationPattern->GetName().c_str());
291 if (navDestination->GetIndex() >= preLastStandardIndex_ && !hideNodesFinish) {
292 if (navDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD
293 && preLastStandardNode != navDestination) {
294 hideNodesFinish = true;
295 DealRemoveDestination(navDestination);
296 hasChanged = true;
297 continue;
298 }
299 hideNodes_.emplace_back(std::make_pair(navDestination, true));
300 navDestination->SetCanReused(false);
301 removeSize++;
302 // move current destination position to navigation stack size + remove navDestination nodes
303 if (remainNodeIndex >= 0) {
304 navDestination->MovePosition(remainNodeIndex);
305 }
306 continue;
307 }
308 DealRemoveDestination(navDestination);
309 hasChanged = true;
310 }
311 if (pattern->IsCurTopNewInstance()) {
312 ReorderAnimatingDestination(
313 navigationContentNode, maxAnimatingDestination, remainDestination, curTopDestination);
314 }
315 }
316
ReorderAnimatingDestination(RefPtr<FrameNode> & navigationContentNode,RefPtr<UINode> & maxAnimatingDestination,RefPtr<UINode> & remainDestination,RefPtr<UINode> & curTopDestination)317 void NavigationGroupNode::ReorderAnimatingDestination(RefPtr<FrameNode>& navigationContentNode,
318 RefPtr<UINode>& maxAnimatingDestination, RefPtr<UINode>& remainDestination, RefPtr<UINode>& curTopDestination)
319 {
320 auto maxAnimatingIndex = navigationContentNode->GetChildIndex(maxAnimatingDestination);
321 if (maxAnimatingIndex != -1 && remainDestination) {
322 remainDestination->MovePosition(maxAnimatingIndex + 1);
323 }
324 auto remainIndex = navigationContentNode->GetChildIndex(remainDestination);
325 if (remainIndex != -1 && curTopDestination) {
326 curTopDestination->MovePosition(remainIndex + 1);
327 }
328 }
329
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const330 void NavigationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
331 {
332 FrameNode::ToJsonValue(json, filter);
333 auto navBarNode = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
334 CHECK_NULL_VOID(navBarNode);
335 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
336 if (titleBarNode) {
337 std::string title = NavigationTitleUtil::GetTitleString(titleBarNode,
338 navBarNode->GetPrevTitleIsCustomValue(false));
339 std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
340 json->PutExtAttr("title", title.c_str(), filter);
341 json->PutExtAttr("subtitle", subtitle.c_str(), filter);
342 }
343 json->PutExtAttr("menus", navBarNode->GetBarItemsString(true).c_str(), filter);
344 json->PutExtAttr("toolBar", navBarNode->GetBarItemsString(false).c_str(), filter);
345 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
346 CHECK_NULL_VOID(navBarLayoutProperty);
347 json->PutExtAttr("titleMode", navBarLayoutProperty->GetTitleModeString().c_str(), filter);
348 json->PutExtAttr("hideBackButton", navBarLayoutProperty->GetHideBackButtonValue(false), filter);
349 json->PutExtAttr("hideTitleBar", navBarLayoutProperty->GetHideTitleBarValue(false), filter);
350 json->PutExtAttr("hideToolBar", navBarLayoutProperty->GetHideToolBarValue(false), filter);
351 }
352
GetNavDestinationNode(RefPtr<UINode> uiNode)353 RefPtr<UINode> NavigationGroupNode::GetNavDestinationNode(RefPtr<UINode> uiNode)
354 {
355 if (!uiNode) {
356 return nullptr;
357 }
358 // create NavDestinationNode from uiNode stored in NavigationStack
359 while (uiNode) {
360 if (uiNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
361 // this is a navDestination node
362 return uiNode;
363 }
364 if (AceType::DynamicCast<UINode>(uiNode)) {
365 // this is an UINode, go deep further for navDestination node
366 auto children = uiNode->GetChildren();
367 uiNode = children.front();
368 continue;
369 }
370 }
371 CHECK_NULL_RETURN(uiNode, nullptr);
372 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get navDestination node failed: id: %{public}d, %{public}s",
373 uiNode->GetId(), uiNode->GetTag().c_str());
374 return nullptr;
375 }
376
SetBackButtonEvent(const RefPtr<NavDestinationGroupNode> & navDestination)377 void NavigationGroupNode::SetBackButtonEvent(const RefPtr<NavDestinationGroupNode>& navDestination)
378 {
379 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
380 CHECK_NULL_VOID(titleBarNode);
381 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetCustomBackButton());
382 if (!backButtonNode) {
383 backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
384 }
385 CHECK_NULL_VOID(backButtonNode);
386 auto backButtonEventHub = backButtonNode->GetEventHub<EventHub>();
387 CHECK_NULL_VOID(backButtonEventHub);
388 auto onBackButtonEvent = [navDestinationWeak = WeakPtr<NavDestinationGroupNode>(navDestination),
389 navigationWeak = WeakClaim(this)](GestureEvent& /*info*/) -> bool {
390 auto navDestination = navDestinationWeak.Upgrade();
391 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "click navigation back button");
392 CHECK_NULL_RETURN(navDestination, false);
393 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
394 CHECK_NULL_RETURN(eventHub, false);
395 eventHub->SetState(NavDestinationState::ON_BACKPRESS);
396 auto navdestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
397 UIObserverHandler::GetInstance().NotifyNavigationStateChange(
398 navdestinationPattern, NavDestinationState::ON_BACKPRESS);
399 auto isOverride = eventHub->GetOnBackPressedEvent();
400 auto result = false;
401 if (isOverride) {
402 result = eventHub->FireOnBackPressedEvent();
403 }
404 auto navigation = navigationWeak.Upgrade();
405 CHECK_NULL_RETURN(navigation, false);
406 navigation->CheckIsNeedForceExitWindow(result);
407 if (result) {
408 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation user onBackPress return true");
409 return true;
410 }
411 // if set hideNavBar and stack size is one, return false
412 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(navigation->GetLayoutProperty());
413 CHECK_NULL_RETURN(navigationLayoutProperty, false);
414 auto pattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
415 CHECK_NULL_RETURN(pattern, false);
416 auto stack = pattern->GetNavigationStack();
417 CHECK_NULL_RETURN(stack, false);
418 if (navigationLayoutProperty->GetHideNavBarValue(false) && stack->GetSize() <= 1) {
419 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "set hideNavBar and stack size is no more than one");
420 return false;
421 }
422 auto isLastChild = stack->Size() == 1;
423 if (isOverride) {
424 result = navigation->HandleBack(navDestination, isLastChild, true);
425 } else {
426 result = navigation->HandleBack(navDestination, isLastChild, false);
427 }
428 // when js navigationStack is provided, modifyDone will be called by state manager.
429 auto navigationPattern = navigation->GetPattern<NavigationPattern>();
430 CHECK_NULL_RETURN(navigationPattern, false);
431 if (!navigationPattern->GetNavigationStackProvided()) {
432 navigation->MarkModifyDone();
433 navigation->MarkDirtyNode();
434 }
435
436 return result;
437 }; // backButton event
438
439 navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
440 backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
441 }
442
GetTopDestination()443 RefPtr<FrameNode> NavigationGroupNode::GetTopDestination()
444 {
445 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
446 CHECK_NULL_RETURN(pattern, nullptr);
447 auto navigationStack = pattern->GetNavigationStack();
448 CHECK_NULL_RETURN(navigationStack, nullptr);
449 auto topNavdestination = AceType::DynamicCast<FrameNode>(GetNavDestinationNode(navigationStack->Get()));
450 return topNavdestination;
451 }
452
CheckCanHandleBack(bool & isEntry)453 bool NavigationGroupNode::CheckCanHandleBack(bool& isEntry)
454 {
455 auto navigation = AceType::WeakClaim(this).Upgrade();
456 CHECK_NULL_RETURN(navigation, false);
457 auto navigationPattern = GetPattern<NavigationPattern>();
458 CHECK_NULL_RETURN(navigationPattern, false);
459
460 auto navigationStack = navigationPattern->GetNavigationStack();
461 CHECK_NULL_RETURN(navigationStack, false);
462 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
463 NavigationGroupNode::GetNavDestinationNode(navigationStack->Get()));
464 if (!navDestination) {
465 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find destination node to process back press");
466 return false;
467 }
468 if (!navigationPattern->IsFinishInteractiveAnimation()) {
469 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't handle back press during interactive animation");
470 return true;
471 }
472 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
473 if (navDestinationPattern->OverlayOnBackPressed()) {
474 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination's ovelay consume backPressed event: %{public}s",
475 navDestinationPattern->GetName().c_str());
476 return true;
477 }
478 auto navDestinationContext = navDestinationPattern->GetNavDestinationContext();
479 CHECK_NULL_RETURN(navDestinationContext, false);
480 auto navPathInfo = navDestinationContext->GetNavPathInfo();
481 CHECK_NULL_RETURN(navPathInfo, false);
482 auto isPathEntry = navPathInfo->GetIsEntry();
483 if (isPathEntry) {
484 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s is entry navDestination, do not consume backPressed event",
485 navDestinationPattern->GetName().c_str());
486 navPathInfo->SetIsEntry(false);
487 auto index = navDestinationContext->GetIndex();
488 navigationStack->SetIsEntryByIndex(index, false);
489 isEntry = true;
490 return false;
491 }
492 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination consume back button event: %{public}s",
493 navDestinationPattern->GetName().c_str());
494 GestureEvent gestureEvent;
495 return navDestination->GetNavDestinationBackButtonEvent()(gestureEvent);
496 }
497
CheckIsNeedForceExitWindow(bool result)498 void NavigationGroupNode::CheckIsNeedForceExitWindow(bool result)
499 {
500 auto context = GetContext();
501 CHECK_NULL_VOID(context);
502 if (!context->GetInstallationFree() || !result) {
503 // if is not atommic service and result is false, don't process.
504 return;
505 }
506
507 auto navigationPattern = GetPattern<NavigationPattern>();
508 CHECK_NULL_VOID(navigationPattern);
509 auto isHasParentNavigation = navigationPattern->GetParentNavigationPattern();
510 auto navigationStack = navigationPattern->GetNavigationStack();
511 CHECK_NULL_VOID(navigationStack);
512 auto overlayManager = context->GetOverlayManager();
513 CHECK_NULL_VOID(overlayManager);
514 auto stageManager = context->GetStageManager();
515 CHECK_NULL_VOID(stageManager);
516 int32_t pageSize =
517 stageManager->GetStageNode() ? static_cast<int32_t>(stageManager->GetStageNode()->GetChildren().size()) : 0;
518 if (navigationStack->GetSize() != 1 || isHasParentNavigation || !overlayManager->IsModalEmpty() || pageSize != 1) {
519 return;
520 }
521
522 /*
523 * when stack size is one, there four situations.
524 * 1.split mode, navbar visible.
525 * 2.split mode, navbar invisible.
526 * 3.stack mode, navbar visible.
527 * 4.stack mode, navbar invisible.
528 * Only the third situation don't need to be intercepted
529 */
530 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
531 CHECK_NULL_VOID(layoutProperty);
532 bool isSplitMode = GetNavigationMode() == NavigationMode::SPLIT;
533 bool isLastNavdesNeedIntercept = isSplitMode || layoutProperty->GetHideNavBar().value_or(false);
534 if (!isLastNavdesNeedIntercept) {
535 return;
536 }
537 ExitWindow(context);
538 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navdestination onbackpress intercepted, exit window.");
539 }
540
HandleBack(const RefPtr<FrameNode> & node,bool isLastChild,bool isOverride)541 bool NavigationGroupNode::HandleBack(const RefPtr<FrameNode>& node, bool isLastChild, bool isOverride)
542 {
543 auto navigationPattern = GetPattern<NavigationPattern>();
544 if (!isOverride && !isLastChild) {
545 navigationPattern->RemoveNavDestination();
546 return true;
547 }
548 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
549 CHECK_NULL_RETURN(navDestination, false);
550
551 auto mode = navigationPattern->GetNavigationMode();
552 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
553 if (isLastChild && (mode == NavigationMode::SPLIT ||
554 (mode == NavigationMode::STACK && layoutProperty->GetHideNavBar().value_or(false)))) {
555 return false;
556 }
557
558 navigationPattern->RemoveNavDestination();
559 return true;
560 }
561
FetchNavigationManager()562 RefPtr<NavigationManager> NavigationGroupNode::FetchNavigationManager()
563 {
564 auto context = GetContext();
565 CHECK_NULL_RETURN(context, nullptr);
566 auto navigationManager = context->GetNavigationManager();
567 CHECK_NULL_RETURN(navigationManager, nullptr);
568 return navigationManager;
569 }
570
ConfigureNavigationWithAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)571 void NavigationGroupNode::ConfigureNavigationWithAnimation(
572 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
573 {
574 auto navigationManager = FetchNavigationManager();
575 CHECK_NULL_VOID(navigationManager);
576 if (!navigationManager->HasCacheNavigationNodeEnable()) {
577 return;
578 }
579 navigationManager->SetNavNodeInTransition(curNode, preNode);
580 navigationManager->SetIsNavigationOnAnimation(true);
581 }
582
ResetTransitionAnimationNodeState(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)583 void NavigationGroupNode::ResetTransitionAnimationNodeState(
584 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
585 {
586 auto navigationManager = FetchNavigationManager();
587 CHECK_NULL_VOID(navigationManager);
588 if (!navigationManager->HasCacheNavigationNodeEnable()) {
589 return;
590 }
591 auto curNavDestContentFrameNode = navigationManager->GetNavDestContentFrameNode(curNode);
592 if (curNavDestContentFrameNode) {
593 navigationManager->UpdateAnimationCachedRenderGroup(curNavDestContentFrameNode, false);
594 navigationManager->SetCurNodeAnimationCached(false);
595 navigationManager->SetCurrentNodeNeverSet(true);
596 }
597 auto preNavDestContentFrameNode = navigationManager->GetNavDestContentFrameNode(preNode);
598 if (preNavDestContentFrameNode) {
599 navigationManager->UpdateAnimationCachedRenderGroup(preNavDestContentFrameNode, false);
600 navigationManager->SetPreNodeAnimationCached(false);
601 navigationManager->SetPreNodeNeverSet(true);
602 }
603 navigationManager->SetNavNodeInTransition(nullptr, nullptr);
604 navigationManager->SetIsNavigationOnAnimation(false);
605 }
606
CreateAnimationWithPop(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBar)607 void NavigationGroupNode::CreateAnimationWithPop(const TransitionUnitInfo& preInfo, const TransitionUnitInfo& curInfo,
608 const AnimationFinishCallback finishCallback, bool isNavBar)
609 {
610 // this function has been override for different device type
611 auto preNode = preInfo.transitionNode;
612 auto curNode = curInfo.transitionNode;
613 auto preUseCustomTransition = preInfo.isUseCustomTransition;
614 auto curUseCustomTransition = curInfo.isUseCustomTransition;
615 CHECK_NULL_VOID(preNode);
616 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
617 CHECK_NULL_VOID(preNavDestination);
618 if (!preUseCustomTransition) {
619 preNavDestination->InitSystemTransitionPop(false);
620 }
621 if (curNode) {
622 if (isNavBar) {
623 auto navbarNode = AceType::DynamicCast<NavBarNode>(curNode);
624 CHECK_NULL_VOID(navbarNode);
625 navbarNode->InitSystemTransitionPop();
626 } else {
627 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
628 CHECK_NULL_VOID(curNavDestination);
629 if (!curUseCustomTransition) {
630 curNavDestination->InitSystemTransitionPop(true);
631 }
632 }
633 }
634 // start transition animation
635 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
636 finishCallback);
637 auto newPopAnimation = AnimationUtils::StartAnimation(option, [
638 this, preNode, curNode, isNavBar, preUseCustomTransition, curUseCustomTransition]() {
639 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition start");
640 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
641 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation start: animationId: %{public}d",
642 static_cast<int32_t>(animationId_));
643
644 // ENTER_POP nodes animation
645 if (curNode) {
646 if (isNavBar) {
647 auto curNavBar = AceType::DynamicCast<NavBarNode>(curNode);
648 CHECK_NULL_VOID(curNavBar);
649 curNavBar->StartSystemTransitionPop();
650 } else if (!curUseCustomTransition) {
651 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
652 CHECK_NULL_VOID(curNavDestination);
653 curNavDestination->StartSystemTransitionPop(true);
654 }
655 }
656 // EXIT_POP nodes finish animation
657 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
658 CHECK_NULL_VOID(preNavDestination);
659 if (!preUseCustomTransition) {
660 preNavDestination->StartSystemTransitionPop(false);
661 }
662 }, option.GetOnFinishEvent());
663 if (newPopAnimation) {
664 popAnimations_.emplace_back(newPopAnimation);
665 }
666 if (!preUseCustomTransition) {
667 auto titleOpacityAnimation = preNavDestination->TitleOpacityAnimation(false);
668 if (titleOpacityAnimation) {
669 popAnimations_.emplace_back(titleOpacityAnimation);
670 }
671 auto backButtonAnimation = preNavDestination->BackButtonAnimation(false);
672 if (backButtonAnimation) {
673 popAnimations_.emplace_back(backButtonAnimation);
674 }
675 }
676 if (!curUseCustomTransition) {
677 auto maskAnimation = MaskAnimation(curNode, true);
678 if (maskAnimation) {
679 popAnimations_.emplace_back(maskAnimation);
680 }
681 }
682 ConfigureNavigationWithAnimation(preNode, curNode);
683 }
684
TransitionWithPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)685 void NavigationGroupNode::TransitionWithPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
686 bool isNavBar)
687 {
688 CHECK_NULL_VOID(preNode);
689 /* create animation finish callback */
690 CleanPopAnimations();
691 // update animation id
692 auto popAnimationId = MakeUniqueAnimationId();
693 UpdateTransitionAnimationId(preNode, popAnimationId);
694 UpdateTransitionAnimationId(curNode, popAnimationId);
695 /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
696 int32_t preAnimationId = TriggerNavDestinationTransition(
697 DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::POP, false);
698 auto preUseCustomTransition = true;
699 if (preAnimationId == INVALID_ANIMATION_ID) {
700 preAnimationId = popAnimationId;
701 preUseCustomTransition = false;
702 }
703 auto curUseCustomTransition = true;
704 int32_t curAnimationId = TriggerNavDestinationTransition(
705 DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::POP, true);
706 if (curAnimationId == INVALID_ANIMATION_ID) {
707 curAnimationId = popAnimationId;
708 curUseCustomTransition = false;
709 }
710 if (preUseCustomTransition && curUseCustomTransition) {
711 return;
712 }
713 AnimationFinishCallback callback = [weakPreNode = WeakPtr<FrameNode>(preNode), preUseCustomTransition,
714 weakCurNode = WeakPtr<FrameNode>(curNode), weakNavigation = WeakClaim(this), preAnimationId] {
715 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition end");
716 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
717 "navigation pop animation end, pre node animationId: %{public}d", preAnimationId);
718 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
719 auto navigation = weakNavigation.Upgrade();
720 CHECK_NULL_VOID(navigation);
721 navigation->isOnAnimation_ = false;
722 auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
723 navigation->OnAccessibilityEvent(
724 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
725 navigation->CleanPopAnimations();
726 auto preNavDesNode = weakPreNode.Upgrade();
727 CHECK_NULL_VOID(preNavDesNode);
728 auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNavDesNode);
729 CHECK_NULL_VOID(preNavdestination);
730 auto curNavDesNode = weakCurNode.Upgrade();
731 navigation->ResetTransitionAnimationNodeState(preNavDesNode, curNavDesNode);
732 if (preNavdestination->IsInDestroying()) {
733 preNavdestination->SetDestroying(false, false);
734 }
735 if (!preUseCustomTransition && preNavdestination->SystemTransitionPopCallback(preAnimationId)) {
736 // return true means need to remove the poped navdestination
737 auto parent = preNavDesNode->GetParent();
738 CHECK_NULL_VOID(parent);
739 parent->RemoveChild(preNavDesNode);
740 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
741 }
742 auto context = navigation->GetContextWithCheck();
743 CHECK_NULL_VOID(context);
744 context->MarkNeedFlushMouseEvent();
745 };
746 TransitionUnitInfo preInfo(preNode, preUseCustomTransition, preAnimationId);
747 TransitionUnitInfo curInfo(curNode, curUseCustomTransition, curAnimationId);
748 CreateAnimationWithPop(preInfo, curInfo, callback, isNavBar);
749 // remove jschild when pop page animation begin
750 RemoveJsChildImmediately(preNode, preUseCustomTransition, preAnimationId);
751
752 // clear this flag for navBar layout only
753 if (isNavBar) {
754 SetNeedSetInvisible(false);
755 }
756 isOnAnimation_ = true;
757 UiSessionManager::GetInstance()->OnRouterChange(navigationPathInfo_, "navigationPopPage");
758 }
759
RemoveJsChildImmediately(const RefPtr<FrameNode> & preNode,bool preUseCustomTransition,int32_t preAnimationId)760 void NavigationGroupNode::RemoveJsChildImmediately(const RefPtr<FrameNode>& preNode, bool preUseCustomTransition,
761 int32_t preAnimationId)
762 {
763 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
764 return;
765 }
766
767 auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
768 CHECK_NULL_VOID(preNavdestination);
769
770 if (preUseCustomTransition || !preNavdestination->CheckTransitionPop(preAnimationId)) {
771 return;
772 }
773
774 if (preNode->HasSkipNode()) {
775 return;
776 }
777
778 auto removeJsFun = [weakPreNode = WeakPtr<FrameNode>(preNode)]() {
779 auto preNavDesNode = weakPreNode.Upgrade();
780 CHECK_NULL_VOID(preNavDesNode);
781 preNavDesNode->SetDestroying();
782 };
783 auto taskExecutor = Container::CurrentTaskExecutor();
784 CHECK_NULL_VOID(taskExecutor);
785 taskExecutor->PostDelayedTask(removeJsFun, TaskExecutor::TaskType::UI,
786 RELEASE_JSCHILD_DELAY_TIME, "ArkUIRemoveJsChild");
787 }
788
CreateAnimationWithPush(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBar)789 void NavigationGroupNode::CreateAnimationWithPush(const TransitionUnitInfo& preInfo, const TransitionUnitInfo& curInfo,
790 const AnimationFinishCallback finishCallback, bool isNavBar)
791 {
792 auto preNode = preInfo.transitionNode;
793 auto curNode = curInfo.transitionNode;
794 auto preUseCustomTransition = preInfo.isUseCustomTransition;
795 auto curUseCustomTransition = curInfo.isUseCustomTransition;
796 // this function has been override for different device type
797 if (isNavBar) {
798 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
799 CHECK_NULL_VOID(navBarNode);
800 navBarNode->SystemTransitionPushAction(true);
801 } else {
802 if (preNode) {
803 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
804 CHECK_NULL_VOID(navDestination);
805 if (!preUseCustomTransition) {
806 navDestination->InitSystemTransitionPush(false);
807 }
808 }
809 }
810 if (curNode) {
811 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
812 CHECK_NULL_VOID(curNavDestination);
813 if (!curUseCustomTransition) {
814 curNavDestination->InitSystemTransitionPush(true);
815 }
816 }
817
818 // start transition animation
819 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
820 finishCallback);
821 auto newPushAnimation = AnimationUtils::StartAnimation(option, [
822 preNode, curNode, isNavBar, preUseCustomTransition, curUseCustomTransition]() {
823 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition start");
824 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
825 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation start");
826 if (isNavBar) {
827 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
828 CHECK_NULL_VOID(navBarNode);
829 navBarNode->StartSystemTransitionPush();
830 } else {
831 if (preNode && !preUseCustomTransition) {
832 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
833 CHECK_NULL_VOID(navDestination);
834 navDestination->StartSystemTransitionPush(false);
835 }
836 }
837 // curNode
838 if (curNode && !curUseCustomTransition) {
839 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
840 CHECK_NULL_VOID(curNavdestination);
841 curNavdestination->StartSystemTransitionPush(true);
842 }
843 }, option.GetOnFinishEvent());
844 if (newPushAnimation) {
845 pushAnimations_.emplace_back(newPushAnimation);
846 }
847 if (!preUseCustomTransition) {
848 auto maskAnimation = MaskAnimation(preNode, false);
849 if (maskAnimation) {
850 pushAnimations_.emplace_back(maskAnimation);
851 }
852 }
853 if (!curUseCustomTransition) {
854 CHECK_NULL_VOID(curNode);
855 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
856 CHECK_NULL_VOID(curNavdestination);
857 // title opacity
858 auto titleOpacityAnimation = curNavdestination->TitleOpacityAnimation(true);
859 if (titleOpacityAnimation) {
860 pushAnimations_.emplace_back(titleOpacityAnimation);
861 }
862 // backIcon opacity
863 auto backButtonAnimation = curNavdestination->BackButtonAnimation(true);
864 if (backButtonAnimation) {
865 pushAnimations_.emplace_back(backButtonAnimation);
866 }
867 }
868 ConfigureNavigationWithAnimation(preNode, curNode);
869 }
870
TransitionAnimationIsValid(const RefPtr<FrameNode> & node,bool isNavBar,bool isUseNavDestCustomTransition)871 RefPtr<FrameNode> NavigationGroupNode::TransitionAnimationIsValid(
872 const RefPtr<FrameNode>& node, bool isNavBar, bool isUseNavDestCustomTransition)
873 {
874 if (isNavBar || isUseNavDestCustomTransition) {
875 return node;
876 }
877 auto destination = AceType::DynamicCast<NavDestinationGroupNode>(node);
878 if (destination && destination->GetSystemTransitionType() == NavigationSystemTransitionType::NONE) {
879 return nullptr;
880 }
881 return node;
882 }
883
TransitionWithPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)884 void NavigationGroupNode::TransitionWithPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
885 bool isNavBar)
886 {
887 CHECK_NULL_VOID(preNode);
888 CHECK_NULL_VOID(curNode);
889
890 // Create animation callback
891 CleanPushAnimations();
892 auto pushAnimationId = MakeUniqueAnimationId();
893 UpdateTransitionAnimationId(preNode, pushAnimationId);
894 UpdateTransitionAnimationId(curNode, pushAnimationId);
895 /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
896 int32_t preAnimationId = TriggerNavDestinationTransition(
897 DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::PUSH, false);
898 auto preUseCustomTransition = true;
899 if (preAnimationId == INVALID_ANIMATION_ID) {
900 preAnimationId = pushAnimationId;
901 preUseCustomTransition = false;
902 }
903 auto curUseCustomTransition = true;
904 int32_t curAnimationId = TriggerNavDestinationTransition(
905 DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::PUSH, true);
906 if (curAnimationId == INVALID_ANIMATION_ID) {
907 curAnimationId = pushAnimationId;
908 curUseCustomTransition = false;
909 }
910 if (preUseCustomTransition && curUseCustomTransition) {
911 return;
912 }
913 AnimationFinishCallback callback = [weakPreNode = WeakPtr<FrameNode>(preNode), preUseCustomTransition,
914 weakCurNode = WeakPtr<FrameNode>(curNode), curUseCustomTransition, weakNavigation = WeakClaim(this),
915 isNavBar, preAnimationId, curAnimationId] {
916 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition end");
917 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
918 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation end");
919 auto navigation = weakNavigation.Upgrade();
920 CHECK_NULL_VOID(navigation);
921 auto preNode = weakPreNode.Upgrade();
922 while (preNode) {
923 auto renderContext = preNode->GetRenderContext();
924 if (renderContext) {
925 renderContext->SetActualForegroundColor(Color::TRANSPARENT);
926 }
927 if (!navigation->CheckAnimationIdValid(preNode, preAnimationId)) {
928 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "pre node is doing another animation, skip handling.");
929 break;
930 }
931 if (isNavBar) {
932 auto navbar = AceType::DynamicCast<NavBarNode>(preNode);
933 CHECK_NULL_VOID(navbar);
934 navbar->SystemTransitionPushAction(false);
935 bool needSetInvisible = navbar->GetTransitionType() == PageTransitionType::EXIT_PUSH;
936 navigation->SetNeedSetInvisible(needSetInvisible);
937 bool isInvisible = navbar->IsNodeInvisible(navigation);
938 if (needSetInvisible && isInvisible) {
939 preNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
940 preNode->SetJSViewActive(false);
941 navigation->NotifyPageHide();
942 }
943 navbar->GetRenderContext()->SetOpacity(1.0f);
944 } else {
945 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
946 CHECK_NULL_VOID(preDestination);
947 if (preUseCustomTransition) {
948 // no need handle pre node here. it will be handled in its custom transition callback.
949 break;
950 }
951 if (preDestination->NeedRemoveInPush()) {
952 navigation->hideNodes_.emplace_back(std::make_pair(preDestination, true));
953 break;
954 }
955 preDestination->SystemTransitionPushCallback(false, preAnimationId);
956 preDestination->GetRenderContext()->SetOpacity(1.0f);
957 }
958 break;
959 }
960 auto curNode = weakCurNode.Upgrade();
961 if (curNode) {
962 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
963 CHECK_NULL_VOID(curNavDestination);
964 if (!curUseCustomTransition) {
965 navigation->ResetTransitionAnimationNodeState(preNode, curNode);
966 curNavDestination->SystemTransitionPushCallback(true, curAnimationId);
967 }
968 }
969 navigation->RemoveDialogDestination();
970 auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
971 navigation->OnAccessibilityEvent(
972 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
973 navigation->isOnAnimation_ = false;
974 navigation->CleanPushAnimations();
975 auto pattern = navigation->GetPattern<NavigationPattern>();
976 pattern->CheckContentNeedMeasure(navigation);
977 };
978
979 auto preNodeNew = TransitionAnimationIsValid(preNode, isNavBar, preUseCustomTransition);
980 auto curNodeNew = TransitionAnimationIsValid(curNode, isNavBar, curUseCustomTransition);
981 if (preNodeNew != nullptr || curNodeNew != nullptr) {
982 TransitionUnitInfo preInfo(preNodeNew, preUseCustomTransition, preAnimationId);
983 TransitionUnitInfo curInfo(curNodeNew, curUseCustomTransition, curAnimationId);
984 CreateAnimationWithPush(preInfo, curInfo, callback, isNavBar);
985 }
986
987 isOnAnimation_ = true;
988 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
989 CHECK_NULL_VOID(curNavDestination);
990 if (AceChecker::IsPerformanceCheckEnabled()) {
991 int64_t startTime = GetSysTimestamp();
992 auto pipeline = AceType::DynamicCast<NG::PipelineContext>(GetContextWithCheck());
993 CHECK_NULL_VOID(pipeline);
994 // After completing layout tasks at all nodes on the page, perform performance testing and management
995 pipeline->AddAfterLayoutTask([weakNav = WeakClaim(this), weakNode = WeakPtr<FrameNode>(curNode), startTime,
996 path = curNavDestination->GetNavDestinationPathInfo()]() {
997 auto navigation = weakNav.Upgrade();
998 CHECK_NULL_VOID(navigation);
999 auto curNode = weakNode.Upgrade();
1000 int64_t endTime = GetSysTimestamp();
1001 CHECK_NULL_VOID(curNode);
1002 PerformanceCheckNodeMap nodeMap;
1003 curNode->GetPerformanceCheckData(nodeMap);
1004 AceScopedPerformanceCheck::RecordPerformanceCheckData(nodeMap, endTime - startTime, path);
1005 });
1006 }
1007 UiSessionManager::GetInstance()->OnRouterChange(navigationPathInfo_, "navigationPushPage");
1008 #if !defined(ACE_UNITTEST)
1009 TransparentNodeDetector::GetInstance().PostCheckNodeTransparentTask(curNode,
1010 curNavDestination->GetNavDestinationPathInfo());
1011 #endif
1012 }
1013
MaskAnimation(const RefPtr<FrameNode> & node,bool isTransitionIn)1014 std::shared_ptr<AnimationUtils::Animation> NavigationGroupNode::MaskAnimation(const RefPtr<FrameNode>& node,
1015 bool isTransitionIn)
1016 {
1017 CHECK_NULL_RETURN(node, nullptr);
1018 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
1019 if (navDestination && navDestination->TransitionContentInValid()) {
1020 return nullptr;
1021 }
1022 AnimationOption maskOption;
1023 maskOption.SetCurve(Curves::FRICTION);
1024 maskOption.SetDuration(MASK_DURATION);
1025 maskOption.SetFillMode(FillMode::FORWARDS);
1026 auto renderContext = node->GetRenderContext();
1027 CHECK_NULL_RETURN(renderContext, nullptr);
1028 if (isTransitionIn) {
1029 renderContext->SetActualForegroundColor(MASK_COLOR);
1030 return AnimationUtils::StartAnimation(
1031 maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
1032 auto context = weakRender.Upgrade();
1033 CHECK_NULL_VOID(context);
1034 context->SetActualForegroundColor(Color::TRANSPARENT);
1035 });
1036 }
1037 renderContext->SetActualForegroundColor(Color::TRANSPARENT);
1038 return AnimationUtils::StartAnimation(
1039 maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
1040 auto context = weakRender.Upgrade();
1041 CHECK_NULL_VOID(context);
1042 context->SetActualForegroundColor(MASK_COLOR);
1043 });
1044 }
1045
TransitionWithReplace(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1046 void NavigationGroupNode::TransitionWithReplace(
1047 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode, bool isNavBar)
1048 {
1049 CHECK_NULL_VOID(preNode);
1050 CHECK_NULL_VOID(curNode);
1051 auto replaceAnimationId = MakeUniqueAnimationId();
1052 UpdateTransitionAnimationId(preNode, replaceAnimationId);
1053 /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
1054 int32_t preAnimationId = TriggerNavDestinationTransition(
1055 DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::REPLACE, false);
1056 auto preUseCustomTransition = true;
1057 if (preAnimationId == INVALID_ANIMATION_ID) {
1058 preAnimationId = replaceAnimationId;
1059 preUseCustomTransition = false;
1060 }
1061 auto curUseCustomTransition = TriggerNavDestinationTransition(
1062 DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::REPLACE, true) != INVALID_ANIMATION_ID;
1063 if (preUseCustomTransition && curUseCustomTransition) {
1064 return;
1065 }
1066 AnimationOption option;
1067 option.SetCurve(replaceCurve);
1068 option.SetFillMode(FillMode::FORWARDS);
1069 option.SetDuration(DEFAULT_REPLACE_DURATION);
1070 option.SetOnFinishEvent([weakPreNode = WeakPtr<FrameNode>(preNode), weakNavigation = WeakClaim(this), isNavBar,
1071 preAnimationId, weakCurNode = WeakPtr<FrameNode>(curNode), preUseCustomTransition]() {
1072 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation replace animation end");
1073 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition end");
1074 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1075 auto preNode = weakPreNode.Upgrade();
1076 CHECK_NULL_VOID(preNode);
1077 auto navigationNode = weakNavigation.Upgrade();
1078 CHECK_NULL_VOID(navigationNode);
1079 navigationNode->isOnAnimation_ = false;
1080 auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1081 navigationNode->OnAccessibilityEvent(
1082 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1083 preNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
1084 if (!navigationNode->CheckAnimationIdValid(preNode, preAnimationId)) {
1085 return;
1086 }
1087 if (!preUseCustomTransition) {
1088 navigationNode->DealNavigationExit(preNode, isNavBar);
1089 }
1090 auto curNode = weakCurNode.Upgrade();
1091 navigationNode->ResetTransitionAnimationNodeState(preNode, curNode);
1092 auto context = navigationNode->GetContextWithCheck();
1093 CHECK_NULL_VOID(context);
1094 context->MarkNeedFlushMouseEvent();
1095 });
1096 preNode->GetEventHub<EventHub>()->SetEnabledInternal(false);
1097 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1098 if (curNavDestination && curNavDestination->IsNeedContentTransition() && !curUseCustomTransition) {
1099 curNode->GetRenderContext()->UpdateOpacity(0.0f);
1100 }
1101 if (!isNavBar) {
1102 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1103 if (navDestination && !curUseCustomTransition) {
1104 navDestination->SetIsOnAnimation(true);
1105 }
1106 }
1107 AnimationUtils::Animate(
1108 option,
1109 [curNode, curUseCustomTransition]() {
1110 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation replace animation start");
1111 ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition start");
1112 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1113 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1114 if (curNavDestination && curNavDestination->IsNeedContentTransition() && !curUseCustomTransition) {
1115 curNode->GetRenderContext()->UpdateOpacity(1.0f);
1116 }
1117 },
1118 option.GetOnFinishEvent());
1119 isOnAnimation_ = true;
1120 ConfigureNavigationWithAnimation(preNode, curNode);
1121 }
1122
OnInspectorIdUpdate(const std::string & id)1123 void NavigationGroupNode::OnInspectorIdUpdate(const std::string& id)
1124 {
1125 auto context = GetContextWithCheck();
1126 CHECK_NULL_VOID(context);
1127 context->AddOrReplaceNavigationNode(id, WeakClaim(this));
1128 curId_ = id;
1129 }
1130
DealNavigationExit(const RefPtr<FrameNode> & preNode,bool isNavBar,bool isAnimated)1131 void NavigationGroupNode::DealNavigationExit(const RefPtr<FrameNode>& preNode, bool isNavBar, bool isAnimated)
1132 {
1133 CHECK_NULL_VOID(preNode);
1134 if (preNode->GetEventHub<EventHub>()) {
1135 preNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
1136 }
1137 if (isNavBar && isAnimated) {
1138 SetNeedSetInvisible(true);
1139 return;
1140 }
1141 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1142 CHECK_NULL_VOID(navDestinationNode);
1143 navDestinationNode->SetIsOnAnimation(false);
1144 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
1145 CHECK_NULL_VOID(navDestinationPattern);
1146 auto navigationPattern = GetPattern<NavigationPattern>();
1147 CHECK_NULL_VOID(navigationPattern);
1148 auto stack = navigationPattern->GetNavigationStack();
1149 bool isInStack = stack->FindIndex(navDestinationPattern->GetName(),
1150 navDestinationPattern->GetCustomNode(), true) != -1;
1151 if (isInStack) {
1152 RemoveDialogDestination(true);
1153 auto preContext = navDestinationNode->GetRenderContext();
1154 CHECK_NULL_VOID(preContext);
1155 preContext->UpdateZIndex(0);
1156 return;
1157 }
1158 navDestinationNode->CleanContent();
1159 auto parent = AceType::DynamicCast<FrameNode>(preNode->GetParent());
1160 CHECK_NULL_VOID(parent);
1161 parent->RemoveChild(preNode);
1162 RemoveDialogDestination(true);
1163 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1164 }
1165
NotifyPageHide()1166 void NavigationGroupNode::NotifyPageHide()
1167 {
1168 auto context = GetContextWithCheck();
1169 CHECK_NULL_VOID(context);
1170 auto stageManager = context->GetStageManager();
1171 CHECK_NULL_VOID(stageManager);
1172 auto container = Container::Current();
1173 CHECK_NULL_VOID(container);
1174 auto pageUrlChecker = container->GetPageUrlChecker();
1175 CHECK_NULL_VOID(pageUrlChecker);
1176 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1177 CHECK_NULL_VOID(pageNode);
1178 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1179 CHECK_NULL_VOID(pagePattern);
1180 auto pageInfo = pagePattern->GetPageInfo();
1181 CHECK_NULL_VOID(pageInfo);
1182 pageUrlChecker->NotifyPageHide(pageInfo->GetPageUrl());
1183 }
1184
UpdateLastStandardIndex()1185 void NavigationGroupNode::UpdateLastStandardIndex()
1186 {
1187 // remove the impact of last standard index
1188 lastStandardIndex_ = -1;
1189 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1190 CHECK_NULL_VOID(navigationPattern);
1191 auto navigationStack = navigationPattern->GetNavigationStack();
1192 CHECK_NULL_VOID(navigationStack);
1193 const auto& navDestinationNodes = navigationStack->GetAllNavDestinationNodes();
1194 if (navDestinationNodes.size() == 0) {
1195 return;
1196 }
1197 for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1; index >= 0; index--) {
1198 const auto& curPath = navDestinationNodes[index];
1199 const auto& uiNode = curPath.second;
1200 if (!uiNode) {
1201 continue;
1202 }
1203 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
1204 if (navDestinationNode && navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
1205 lastStandardIndex_ = index;
1206 return;
1207 }
1208 }
1209 }
1210
UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode> & navDestination,const RefPtr<UINode> & remainChild,int32_t index,size_t destinationSize,const RefPtr<UINode> & preLastStandardNode)1211 bool NavigationGroupNode::UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode>& navDestination,
1212 const RefPtr<UINode>& remainChild, int32_t index, size_t destinationSize, const RefPtr<UINode>& preLastStandardNode)
1213 {
1214 CHECK_NULL_RETURN(navDestination, false);
1215 auto eventHub = navDestination->GetEventHub<NavDestinationEventHub>();
1216 CHECK_NULL_RETURN(eventHub, false);
1217 if (index == static_cast<int32_t>(destinationSize) - 1) {
1218 // process shallow builder
1219 navDestination->ProcessShallowBuilder();
1220 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE, true);
1221 navDestination->SetJSViewActive(true);
1222 navDestination->GetEventHub<EventHub>()->SetEnabledInternal(true);
1223 // for the navDestination at the top, FireChangeEvent
1224 eventHub->FireChangeEvent(true);
1225 bool hasChanged = CheckNeedMeasure(navDestination->GetLayoutProperty()->GetPropertyChangeFlag());
1226 if (!hasChanged && NavigationLayoutAlgorithm::IsAutoHeight(GetLayoutProperty<NavigationLayoutProperty>())) {
1227 hasChanged = true;
1228 }
1229 return hasChanged;
1230 }
1231 if (index < lastStandardIndex_) {
1232 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1233 if (navDestination->IsOnAnimation()) {
1234 return false;
1235 }
1236 if (!pattern || !pattern->GetIsOnShow()) {
1237 // push more than one standard navDestination, need to set invisible below newTopDestination
1238 auto navDestinationLayoutProperty = navDestination->GetLayoutProperty();
1239 CHECK_NULL_RETURN(navDestinationLayoutProperty, false);
1240 navDestinationLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1241 navDestination->SetJSViewActive(false);
1242 return false;
1243 }
1244 eventHub->FireChangeEvent(false);
1245 if (pattern->GetCustomNode() != remainChild) {
1246 if (navDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG ||
1247 navDestination == AceType::DynamicCast<NavDestinationGroupNode>(preLastStandardNode)) {
1248 hideNodes_.insert(hideNodes_.begin(), std::pair(navDestination, false));
1249 } else {
1250 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1251 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1252 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1253 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1254 }
1255 }
1256 return false;
1257 }
1258 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1259 if (navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode() != remainChild &&
1260 !navDestination->IsOnAnimation()) {
1261 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
1262 navDestination->SetJSViewActive(true);
1263 }
1264 return false;
1265 }
1266
GetNavigationMode()1267 NavigationMode NavigationGroupNode::GetNavigationMode()
1268 {
1269 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1270 CHECK_NULL_RETURN(navigationPattern, NavigationMode::AUTO);
1271 return navigationPattern->GetNavigationMode();
1272 }
1273
OnDetachFromMainTree(bool recursive,PipelineContext * context)1274 void NavigationGroupNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
1275 {
1276 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1277 if (pattern) {
1278 pattern->DetachNavigationStackFromParent();
1279 pattern->RemoveFromDumpManager();
1280 }
1281 GroupNode::OnDetachFromMainTree(recursive, context);
1282 CHECK_NULL_VOID(context);
1283 auto navigationManager = context->GetNavigationManager();
1284 if (navigationManager) {
1285 navigationManager->RemoveNavigation(GetId());
1286 }
1287 }
1288
FindNavigationParent(const std::string & parentName)1289 bool NavigationGroupNode::FindNavigationParent(const std::string& parentName)
1290 {
1291 auto parent = GetParent();
1292 while (parent) {
1293 if (parent->GetTag() == parentName) {
1294 AddDestinationNode(parent);
1295 return true;
1296 }
1297 parent = parent->GetParent();
1298 }
1299 return parent != nullptr;
1300 }
1301
AddDestinationNode(const RefPtr<UINode> & parent)1302 void NavigationGroupNode::AddDestinationNode(const RefPtr<UINode>& parent)
1303 {
1304 auto destinationNode = AceType::DynamicCast<NavDestinationGroupNode>(parent);
1305 if (destinationNode) {
1306 parentDestinationNode_ = destinationNode;
1307 }
1308 }
1309
OnAttachToMainTree(bool recursive)1310 void NavigationGroupNode::OnAttachToMainTree(bool recursive)
1311 {
1312 GroupNode::OnAttachToMainTree(recursive);
1313
1314 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1315 if (pattern) {
1316 pattern->AttachNavigationStackToParent();
1317 pattern->AddToDumpManager();
1318 }
1319 RefPtr<UINode> parentCustomNode;
1320 bool findParentNode = false;
1321 auto curNode = GetParent();
1322 while (curNode) {
1323 auto curTag = curNode->GetTag();
1324 // check parentCustomNode is nullptr, to avoid parentCustomNode re-assignment
1325 if (!parentCustomNode && curTag == V2::JS_VIEW_ETS_TAG) {
1326 parentCustomNode = curNode;
1327 }
1328 if (!findParentNode) {
1329 findParentNode = CheckNeedUpdateParentNode(curNode);
1330 }
1331 if (parentCustomNode && findParentNode) {
1332 break;
1333 }
1334 curNode = curNode->GetParent();
1335 }
1336 if (parentCustomNode) {
1337 pattern->SetParentCustomNode(parentCustomNode);
1338 } else {
1339 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "parent custom node is nullptr");
1340 }
1341 if (!findParentNode) {
1342 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "current navigation has no parent page");
1343 }
1344 auto pipelineContext = GetContextWithCheck();
1345 CHECK_NULL_VOID(pipelineContext);
1346 bool findNavdestination = FindNavigationParent(V2::NAVDESTINATION_VIEW_ETS_TAG);
1347 auto stageManager = pipelineContext->GetStageManager();
1348 CHECK_NULL_VOID(stageManager);
1349 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1350 CHECK_NULL_VOID(pageNode);
1351 auto pagePattern = pageNode->GetPattern<PagePattern>();
1352 CHECK_NULL_VOID(pagePattern);
1353 CHECK_NULL_VOID(pagePattern->GetPageInfo());
1354 int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
1355 if (!findNavdestination) {
1356 pipelineContext->AddNavigationNode(pageId, WeakClaim(this));
1357 }
1358 }
1359
CheckNeedUpdateParentNode(const RefPtr<UINode> & curNode)1360 bool NavigationGroupNode::CheckNeedUpdateParentNode(const RefPtr<UINode>& curNode)
1361 {
1362 // only the first time need to be assigned
1363 CHECK_NULL_RETURN(curNode, false);
1364 bool isFindParent = false;
1365 auto curTag = curNode->GetTag();
1366 RefPtr<UINode> parentNode;
1367 do {
1368 if (curTag == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1369 auto curParent = curNode->GetParent();
1370 // check whether current destination is redirected throut transition
1371 if (curParent && curParent->GetTag() == V2::NAVIGATION_CONTENT_ETS_TAG) {
1372 parentNode = curNode;
1373 isFindParent = true;
1374 }
1375 break;
1376 }
1377 if (curTag == V2::PAGE_ETS_TAG || curTag == V2::MODAL_PAGE_TAG ||
1378 curTag == V2::SHEET_PAGE_TAG) {
1379 // check current navigation is in modal page, sheet page and page,
1380 // dialog and overlay is not need recorded
1381 parentNode = curNode;
1382 isFindParent = true;
1383 break;
1384 }
1385 if (curTag == V2::NAVBAR_ETS_TAG) {
1386 // if navigation is under navBar node. don't need to record relationShip
1387 isFindParent = true;
1388 }
1389 } while (0);
1390 if (!isFindParent || !parentNode) {
1391 return isFindParent;
1392 }
1393 auto pipelineContext = GetContextRefPtr();
1394 CHECK_NULL_RETURN(pipelineContext, true);
1395 auto navigationManager = pipelineContext->GetNavigationManager();
1396 CHECK_NULL_RETURN(navigationManager, true);
1397 // update navigation manager map <parentId, std::vector<navigationId>>
1398 navigationManager->AddNavigation(parentNode->GetId(), GetId());
1399 return true;
1400 }
1401
FireHideNodeChange(NavDestinationLifecycle lifecycle)1402 void NavigationGroupNode::FireHideNodeChange(NavDestinationLifecycle lifecycle)
1403 {
1404 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1405 for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); ++iter) {
1406 auto navDestination = iter->first;
1407 if (!navDestination) {
1408 continue;
1409 }
1410 if (lifecycle == NavDestinationLifecycle::ON_WILL_DISAPPEAR) {
1411 if (iter->second) {
1412 navigationPattern->NotifyDestinationLifecycle(
1413 navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1414 }
1415 continue;
1416 }
1417 auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1418 if (!pattern->GetIsOnShow()) {
1419 continue;
1420 }
1421 if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE) {
1422 navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1423 continue;
1424 }
1425 if (lifecycle == NavDestinationLifecycle::ON_HIDE) {
1426 navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1427 }
1428 }
1429 }
1430
RemoveDialogDestination(bool isReplace,bool isTriggerByInteractiveCancel)1431 void NavigationGroupNode::RemoveDialogDestination(bool isReplace, bool isTriggerByInteractiveCancel)
1432 {
1433 for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); iter++) {
1434 auto navDestination = iter->first;
1435 if (!navDestination) {
1436 continue;
1437 }
1438 if (!iter->second) {
1439 auto type = navDestination->GetTransitionType();
1440 bool isEnterPage = (type == PageTransitionType::ENTER_PUSH || type == PageTransitionType::ENTER_POP);
1441 if (!isTriggerByInteractiveCancel && isEnterPage) {
1442 // if tigger by interactive animation, The transition type is incorrect, ignore this case.
1443 continue;
1444 }
1445 // navDestination node don't need to remove, update visibility invisible
1446 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1447 navDestination->SetJSViewActive(false);
1448 if (!isReplace) {
1449 continue;
1450 }
1451 auto context = navDestination->GetRenderContext();
1452 if (!context) {
1453 continue;
1454 }
1455 context->UpdateZIndex(0);
1456 continue;
1457 }
1458 auto parent = navDestination->GetParent();
1459 if (!parent) {
1460 continue;
1461 }
1462 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1463 if (!navDestinationPattern) {
1464 continue;
1465 }
1466 navDestination->CleanContent();
1467 parent->RemoveChild(navDestination);
1468 }
1469 hideNodes_.clear();
1470 }
1471
DealRemoveDestination(const RefPtr<NavDestinationGroupNode> & navDestination)1472 void NavigationGroupNode::DealRemoveDestination(const RefPtr<NavDestinationGroupNode>& navDestination)
1473 {
1474 // remove content child
1475 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
1476 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1477 if (navDestinationPattern->GetIsOnShow()) {
1478 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1479 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1480 navDestinationPattern->SetIsOnShow(false);
1481 }
1482 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1483 navDestination->CleanContent();
1484 contentNode_->RemoveChild(navDestination, true);
1485 }
1486
CreateAnimationWithDialogPop(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> preNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1487 void NavigationGroupNode::CreateAnimationWithDialogPop(const AnimationFinishCallback callback,
1488 const std::vector<WeakPtr<FrameNode>> preNavList,
1489 const std::vector<WeakPtr<FrameNode>> curNavList)
1490 {
1491 // start transition animation
1492 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1493 callback);
1494 auto newPopAnimation = AnimationUtils::StartAnimation(option, [
1495 weakNavigation = WeakClaim(this), curNavList, preNavList]() {
1496 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1497 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation start");
1498
1499 // do preNode transition
1500 auto navigation = weakNavigation.Upgrade();
1501 CHECK_NULL_VOID(navigation);
1502 for (auto iter: preNavList) {
1503 auto preNode = iter.Upgrade();
1504 CHECK_NULL_VOID(preNode);
1505 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1506 if (preNavDesNode) {
1507 preNavDesNode->StartSystemTransitionPop(false);
1508 }
1509 }
1510
1511 // do currentNode transition
1512 for (auto iter: curNavList) {
1513 auto curNode = iter.Upgrade();
1514 CHECK_NULL_VOID(curNode);
1515 if (curNode->GetTag() == V2::NAVBAR_ETS_TAG) {
1516 auto curNavbar = AceType::DynamicCast<NavBarNode>(curNode);
1517 CHECK_NULL_VOID(curNavbar);
1518 curNavbar->StartSystemTransitionPop();
1519 } else {
1520 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1521 CHECK_NULL_VOID(curDestination);
1522 curDestination->StartSystemTransitionPop(true);
1523 }
1524 }
1525 }, option.GetOnFinishEvent());
1526 if (newPopAnimation) {
1527 popAnimations_.emplace_back(newPopAnimation);
1528 }
1529 isOnAnimation_ = true;
1530 }
1531
TransitionWithDialogPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1532 void NavigationGroupNode::TransitionWithDialogPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1533 bool isNavBar)
1534 {
1535 CHECK_NULL_VOID(preNode);
1536 std::vector<WeakPtr<FrameNode>> preNavList;
1537 InitPopPreList(preNode, preNavList);
1538 std::vector<WeakPtr<FrameNode>> curNavList;
1539 bool isNavbarNeedAnimation = lastStandardIndex_ == -1 || isNavBar;
1540 InitPopCurList(curNode, curNavList, isNavbarNeedAnimation);
1541
1542 /* create animation finish callback */
1543 CleanPopAnimations();
1544 AnimationFinishCallback callback = [preNavList, weakNavigation = WeakClaim(this)] {
1545 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation end TransitionWithDialogPop");
1546 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1547 auto navigation = weakNavigation.Upgrade();
1548 CHECK_NULL_VOID(navigation);
1549 navigation->isOnAnimation_ = false;
1550 navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1551 navigation->CleanPopAnimations();
1552 for (auto iter = preNavList.rbegin(); iter != preNavList.rend(); ++iter) {
1553 auto preNode = (*iter).Upgrade();
1554 if (!preNode) {
1555 continue;
1556 }
1557 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1558 CHECK_NULL_VOID(preNavDesNode);
1559 auto pattern = navigation->GetPattern<NavigationPattern>();
1560 CHECK_NULL_VOID(pattern);
1561 bool isIncurStack = pattern->FindInCurStack(preNode);
1562 if (preNavDesNode->SystemTransitionPopCallback(preNavDesNode->GetAnimationId(), !isIncurStack)) {
1563 auto parent = preNavDesNode->GetParent();
1564 CHECK_NULL_VOID(parent);
1565 if (!isIncurStack) {
1566 parent->RemoveChild(preNavDesNode);
1567 }
1568 }
1569 navigation->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1570 }
1571 navigation->RemoveDialogDestination();
1572 auto context = navigation->GetContextWithCheck();
1573 CHECK_NULL_VOID(context);
1574 context->MarkNeedFlushMouseEvent();
1575 };
1576 CreateAnimationWithDialogPop(callback, preNavList, curNavList);
1577 }
1578
CreateAnimationWithDialogPush(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> prevNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1579 void NavigationGroupNode::CreateAnimationWithDialogPush(const AnimationFinishCallback callback,
1580 const std::vector<WeakPtr<FrameNode>> prevNavList, const std::vector<WeakPtr<FrameNode>> curNavList)
1581 {
1582 // start transition animation
1583 AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1584 callback);
1585 auto newPushAnimation = AnimationUtils::StartAnimation(option,
1586 [weakNavigation = WeakClaim(this), prevNavList, curNavList]() {
1587 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1588 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
1589 auto navigation = weakNavigation.Upgrade();
1590 CHECK_NULL_VOID(navigation);
1591
1592 // preNode do EXIT PUSH animation
1593 for (auto iter : prevNavList) {
1594 auto preNode = iter.Upgrade();
1595 CHECK_NULL_VOID(preNode);
1596 if (preNode->GetTag() == V2::NAVBAR_ETS_TAG &&
1597 navigation->GetNavigationMode() == NavigationMode::STACK) {
1598 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
1599 CHECK_NULL_VOID(navBarNode);
1600 navBarNode->StartSystemTransitionPush();
1601 } else {
1602 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1603 CHECK_NULL_VOID(preDestination);
1604 preDestination->StartSystemTransitionPush(false);
1605 }
1606 }
1607 // curNode do ENTER PUSH animation
1608 for (auto iter : curNavList) {
1609 auto curNode = iter.Upgrade();
1610 CHECK_NULL_VOID(curNode);
1611 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1612 if (curDestination) {
1613 curDestination->StartSystemTransitionPush(true);
1614 }
1615 }
1616 }, option.GetOnFinishEvent());
1617 if (newPushAnimation) {
1618 pushAnimations_.emplace_back(newPushAnimation);
1619 }
1620 isOnAnimation_ = true;
1621 }
1622
PreNodeFinishCallback(const RefPtr<FrameNode> & preNode)1623 void NavigationGroupNode::PreNodeFinishCallback(const RefPtr<FrameNode>& preNode)
1624 {
1625 CHECK_NULL_VOID(preNode);
1626 if (preNode->GetTag() == V2::NAVBAR_ETS_TAG) {
1627 auto preNavbar = AceType::DynamicCast<NavBarNode>(preNode);
1628 CHECK_NULL_VOID(preNavbar);
1629 preNavbar->SystemTransitionPushAction(false);
1630 bool needSetInvisible = preNavbar->GetTransitionType() == PageTransitionType::EXIT_PUSH;
1631 SetNeedSetInvisible(needSetInvisible);
1632 if (needSetInvisible && GetNavigationMode() == NavigationMode::STACK) {
1633 auto property = preNavbar->GetLayoutProperty();
1634 CHECK_NULL_VOID(property);
1635 property->UpdateVisibility(VisibleType::INVISIBLE);
1636 preNavbar->SetJSViewActive(false);
1637 NotifyPageHide();
1638 }
1639 return;
1640 }
1641 if (preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1642 auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1643 if (preDestination && preDestination->NeedRemoveInPush()) {
1644 hideNodes_.emplace_back(std::make_pair(preDestination, true));
1645 }
1646 preDestination->SystemTransitionPushCallback(false, preDestination->GetAnimationId());
1647 }
1648 }
1649
TransitionWithDialogPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1650 void NavigationGroupNode::TransitionWithDialogPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1651 bool isNavBar)
1652 {
1653 if (!preNode || !curNode) {
1654 TAG_LOGE(AceLogTag::ACE_NAVIGATION, "dialog push animation terminated");
1655 return;
1656 }
1657 CleanPushAnimations();
1658
1659 // initialization
1660 bool isNavbarNeedAnimation = preLastStandardIndex_ == -1 || isNavBar;
1661 std::vector<WeakPtr<FrameNode>> prevNavList;
1662 InitPushPreList(preNode, prevNavList, isNavbarNeedAnimation);
1663 std::vector<WeakPtr<FrameNode>> curNavList;
1664 InitPushCurList(curNode, curNavList);
1665 AnimationFinishCallback callback = [weakNavigation = WeakClaim(this), prevNavList, curNavList] {
1666 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1667 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1668 auto navigation = weakNavigation.Upgrade();
1669 CHECK_NULL_VOID(navigation);
1670 for (auto iter : prevNavList) {
1671 auto preNode = iter.Upgrade();
1672 if (!preNode) {
1673 continue;
1674 }
1675 navigation->PreNodeFinishCallback(preNode);
1676 }
1677 for (auto iter : curNavList) {
1678 auto curNode = iter.Upgrade();
1679 if (!curNode) {
1680 continue;
1681 }
1682 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1683 CHECK_NULL_VOID(curNavDestination);
1684 curNavDestination->SystemTransitionPushCallback(true, curNavDestination->GetAnimationId());
1685 }
1686 navigation->RemoveDialogDestination();
1687 navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1688 navigation->isOnAnimation_ = false;
1689 navigation->CleanPushAnimations();
1690 };
1691 if (preNode) {
1692 auto renderContext = preNode->GetRenderContext();
1693 CHECK_NULL_VOID(renderContext);
1694 renderContext->RemoveClipWithRRect();
1695 }
1696 CreateAnimationWithDialogPush(callback, prevNavList, curNavList);
1697 }
1698
StartDialogtransition(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isTransitionIn)1699 void NavigationGroupNode::StartDialogtransition(const RefPtr<FrameNode>& preNode,
1700 const RefPtr<FrameNode>& curNode, bool isTransitionIn)
1701 {
1702 AnimationOption option;
1703 const RefPtr<InterpolatingSpring> curve =
1704 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
1705 const float defaultAmplitudePx = 0.005f;
1706 curve->UpdateMinimumAmplitudeRatio(defaultAmplitudePx);
1707 option.SetCurve(curve);
1708 option.SetFillMode(FillMode::FORWARDS);
1709 if (isTransitionIn) {
1710 DialogTransitionPushAnimation(preNode, curNode, option);
1711 TriggerNavDestinationTransition(
1712 DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::PUSH, false);
1713 } else {
1714 DialogTransitionPopAnimation(preNode, curNode, option);
1715 TriggerNavDestinationTransition(
1716 DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::POP, true);
1717 }
1718 }
1719
DialogTransitionPushAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)1720 void NavigationGroupNode::DialogTransitionPushAnimation(const RefPtr<FrameNode>& preNode,
1721 const RefPtr<FrameNode>& curNode, AnimationOption option)
1722 {
1723 CHECK_NULL_VOID(curNode);
1724 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1725 CHECK_NULL_VOID(curNavdestination);
1726 int32_t end = curNavdestination->GetIndex();
1727 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1728 CHECK_NULL_VOID(navigationPattern);
1729 const auto& navDestinationNodesCur = navigationPattern->GetAllNavDestinationNodes();
1730 int32_t start = 0;
1731 if (preNode && preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1732 auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1733 CHECK_NULL_VOID(navdestination);
1734 start = navdestination->GetIndex() + 1;
1735 auto renderContext = preNode->GetRenderContext();
1736 CHECK_NULL_VOID(renderContext);
1737 renderContext->RemoveClipWithRRect();
1738 }
1739 // find the nodes need to do upward ENTER translation
1740 std::vector<WeakPtr<NavDestinationGroupNode>> curNavList;
1741 for (int32_t index = start; index <= end; index++) {
1742 auto navdestination = GetNavDestinationNode(navDestinationNodesCur[index].second);
1743 CHECK_NULL_VOID(navdestination);
1744 auto curNode = AceType::DynamicCast<FrameNode>(navdestination);
1745 CHECK_NULL_VOID(curNode);
1746 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1747 CHECK_NULL_VOID(navDestination);
1748 if (TriggerNavDestinationTransition(navDestination, NavigationOperation::PUSH, true) == INVALID_ANIMATION_ID) {
1749 navDestination->InitDialogTransition(false);
1750 curNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(navDestination));
1751 }
1752 }
1753 CleanPushAnimations();
1754 option.SetOnFinishEvent([weakNavigation = WeakClaim(this), weakCurNode = WeakPtr<FrameNode>(curNode),
1755 weakPreNode = WeakPtr<FrameNode>(preNode)] {
1756 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1757 auto navigation = weakNavigation.Upgrade();
1758 CHECK_NULL_VOID(navigation);
1759 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(weakPreNode.Upgrade());
1760 if (preNavDestination && preNavDestination->NeedRemoveInPush()) {
1761 navigation->hideNodes_.emplace_back(std::make_pair(preNavDestination, true));
1762 }
1763 navigation->RemoveDialogDestination();
1764 navigation->CleanPushAnimations();
1765 auto curNode = weakCurNode.Upgrade();
1766 auto preNode = weakPreNode.Upgrade();
1767 navigation->ResetTransitionAnimationNodeState(preNode, curNode);
1768 });
1769 auto newPushAnimation = AnimationUtils::StartAnimation(option,
1770 [curNavList]() {
1771 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
1772 for (auto iter: curNavList) {
1773 auto curNode = iter.Upgrade();
1774 if (curNode) {
1775 curNode->InitDialogTransition(true);
1776 }
1777 }
1778 },
1779 option.GetOnFinishEvent());
1780 if (newPushAnimation) {
1781 pushAnimations_.emplace_back(newPushAnimation);
1782 }
1783 ConfigureNavigationWithAnimation(preNode, curNode);
1784 }
1785
FindNodesPoped(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)1786 std::vector<WeakPtr<NavDestinationGroupNode>> NavigationGroupNode::FindNodesPoped(
1787 const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
1788 {
1789 std::vector<WeakPtr<NavDestinationGroupNode>> preNavList;
1790 auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1791 CHECK_NULL_RETURN(preNavdestinationNode, preNavList);
1792 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1793 CHECK_NULL_RETURN(navigationPattern, preNavList);
1794 const auto& navDestinationNodesPre = navigationPattern->GetAllNavDestinationNodesPrev();
1795 int32_t start = 0;
1796 if (curNode && curNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1797 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1798 CHECK_NULL_RETURN(curNavdestination, preNavList);
1799 start = preLastStandardIndex_ + 1;
1800 }
1801 // find the nodes need to do downward EXIT translation
1802 auto stack = navigationPattern->GetNavigationStack();
1803 int32_t size = static_cast<int32_t>(navDestinationNodesPre.size());
1804 for (int32_t index = start; index < size; index++) {
1805 auto node = GetNavDestinationNode(navDestinationNodesPre[index].second.Upgrade());
1806 if (!node) {
1807 continue;
1808 }
1809 auto preNode = AceType::DynamicCast<FrameNode>(node);
1810 CHECK_NULL_RETURN(preNode, preNavList);
1811 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1812 CHECK_NULL_RETURN(preNavDesNode, preNavList);
1813 bool isInCurStack = stack->FindIndex(navDestinationNodesPre[index].first,
1814 navDestinationNodesPre[index].second.Upgrade(), true) != -1;
1815 if (!isInCurStack) {
1816 // this node not in current stack should do animation.
1817 if (TriggerNavDestinationTransition(preNavDesNode, NavigationOperation::POP, false)
1818 == INVALID_ANIMATION_ID) {
1819 // has no custom transition or system transition, so do default animation.
1820 preNavDesNode->InitDialogTransition(true);
1821 preNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(preNavDesNode));
1822 }
1823 } else {
1824 // update visbility when this node is under the last standard page
1825 if (preNavDesNode->GetIndex() < lastStandardIndex_) {
1826 preNavDesNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1827 }
1828 }
1829 }
1830 return preNavList;
1831 }
1832
DialogTransitionPopAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)1833 void NavigationGroupNode::DialogTransitionPopAnimation(const RefPtr<FrameNode>& preNode,
1834 const RefPtr<FrameNode>& curNode, AnimationOption option)
1835 {
1836 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1837 CHECK_NULL_VOID(navigationPattern);
1838 auto preNavList = FindNodesPoped(preNode, curNode);
1839 CleanPopAnimations();
1840 option.SetOnFinishEvent(
1841 [preNavList, weakNavigation = WeakClaim(this), weakCurNode = WeakPtr<FrameNode>(curNode),
1842 weakPreNode = WeakPtr<FrameNode>(preNode)] {
1843 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "dialog transition pop animation end");
1844 auto navigation = weakNavigation.Upgrade();
1845 CHECK_NULL_VOID(navigation);
1846 auto curNode = weakCurNode.Upgrade();
1847 auto preNode = weakPreNode.Upgrade();
1848 navigation->ResetTransitionAnimationNodeState(preNode, curNode);
1849 for (auto iter: preNavList) {
1850 auto preNode = iter.Upgrade();
1851 CHECK_NULL_VOID(preNode);
1852 auto parent = preNode->GetParent();
1853 CHECK_NULL_VOID(parent);
1854
1855 auto pattern = navigation->GetPattern<NavigationPattern>();
1856 bool isIncurStack = pattern->FindInCurStack(preNode);
1857 if (!isIncurStack) {
1858 parent->RemoveChild(preNode);
1859 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1860 }
1861 }
1862 navigation->RemoveDialogDestination();
1863 auto context = navigation->GetContextWithCheck();
1864 CHECK_NULL_VOID(context);
1865 context->MarkNeedFlushMouseEvent();
1866 navigation->CleanPopAnimations();
1867 });
1868 auto newPopAnimation = AnimationUtils::StartAnimation(
1869 option, [weakNavigation = WeakClaim(this), preNavList]() {
1870 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "dialog transition pop animation start");
1871 auto navigation = weakNavigation.Upgrade();
1872 CHECK_NULL_VOID(navigation);
1873 for (auto iter: preNavList) {
1874 auto preNode = iter.Upgrade();
1875 CHECK_NULL_VOID(preNode);
1876 preNode->InitDialogTransition(false);
1877 }
1878 }, option.GetOnFinishEvent());
1879 if (newPopAnimation) {
1880 popAnimations_.emplace_back(newPopAnimation);
1881 }
1882 ConfigureNavigationWithAnimation(preNode, curNode);
1883 }
1884
InitPopPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & preNavList)1885 void NavigationGroupNode::InitPopPreList(const RefPtr<FrameNode>& preNode, std::vector<WeakPtr<FrameNode>>& preNavList)
1886 {
1887 // find all the nodes need to do EXIT_POP
1888 int32_t preStartIndex = preLastStandardIndex_;
1889 if (preStartIndex == -1) {
1890 // eg. clear + push page1
1891 preStartIndex = 0;
1892 }
1893 auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1894 CHECK_NULL_VOID(preNavdestinationNode);
1895 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1896 CHECK_NULL_VOID(navigationPattern);
1897 const auto& preNavDestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
1898
1899 // find the nodes need to do EXIT_POP
1900 for (int32_t index = preStartIndex; index < static_cast<int32_t>(preNavDestinationNodes.size()); index++) {
1901 auto node = GetNavDestinationNode(preNavDestinationNodes[index].second.Upgrade());
1902 CHECK_NULL_VOID(node);
1903 auto preNode = AceType::DynamicCast<FrameNode>(node);
1904 CHECK_NULL_VOID(preNode);
1905 auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1906 if (preNavDestination && TriggerNavDestinationTransition(
1907 preNavDestination, NavigationOperation::POP, false) == INVALID_ANIMATION_ID) {
1908 preNavDestination->InitSystemTransitionPop(false);
1909 preNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1910 }
1911 }
1912 }
1913
InitPopCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList,bool isNavbarNeedAnimation)1914 void NavigationGroupNode::InitPopCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList,
1915 bool isNavbarNeedAnimation)
1916 {
1917 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1918 CHECK_NULL_VOID(navigationPattern);
1919 auto curNavdestionNodes = navigationPattern->GetAllNavDestinationNodes();
1920 auto curStartIndex = lastStandardIndex_;
1921
1922 // navBar + D or navBar should be in animation
1923 if (isNavbarNeedAnimation) {
1924 curStartIndex = 0;
1925 }
1926 // if navBar should be in animation, do initialization and visibility should be true
1927 if (isNavbarNeedAnimation && navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
1928 auto preNode = AceType::DynamicCast<FrameNode>(GetNavBarNode());
1929 if (preNode) {
1930 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
1931 CHECK_NULL_VOID(navBarNode);
1932 navBarNode->InitSystemTransitionPop();
1933 curNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1934 SetNeedSetInvisible(false);
1935 }
1936 }
1937 int32_t size = static_cast<int32_t>(curNavdestionNodes.size());
1938 if (size == 0) {
1939 return;
1940 }
1941 // find the nodes need to do ENTER_POP
1942 for (int32_t index = curStartIndex; index < size; index++) {
1943 auto node = GetNavDestinationNode(curNavdestionNodes[index].second);
1944 CHECK_NULL_VOID(node);
1945 auto curNode = AceType::DynamicCast<FrameNode>(node);
1946 if (curNode) {
1947 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1948 if (navDestination && TriggerNavDestinationTransition(
1949 navDestination, NavigationOperation::POP, true) == INVALID_ANIMATION_ID) {
1950 navDestination->InitSystemTransitionPop(true);
1951 curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
1952 }
1953 }
1954 }
1955 }
1956
InitPushPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & prevNavList,bool isNavbarNeedAnimation)1957 void NavigationGroupNode::InitPushPreList(const RefPtr<FrameNode>& preNode,
1958 std::vector<WeakPtr<FrameNode>>& prevNavList, bool isNavbarNeedAnimation)
1959 {
1960 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1961 CHECK_NULL_VOID(navigationPattern);
1962 auto stack = navigationPattern->GetNavigationStack();
1963 auto& preNavdestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
1964 auto preStartIndex = preLastStandardIndex_;
1965
1966 // find the pre last standard index, if there is no pre standard or pre node is single navbar
1967 if (isNavbarNeedAnimation) {
1968 preStartIndex = 0;
1969 }
1970 // if pre node is nav bar or one of preNodes is nav bar and only stack with navbar's animation
1971 if (isNavbarNeedAnimation&& navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
1972 auto preNode = AceType::DynamicCast<FrameNode>(GetNavBarNode());
1973 CHECK_NULL_VOID(preNode);
1974 auto preNavbar = AceType::DynamicCast<NavBarNode>(preNode);
1975 if (preNavbar) {
1976 SetNeedSetInvisible(false);
1977 preNavbar->SystemTransitionPushAction(true);
1978 prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1979 }
1980 }
1981 int32_t size = static_cast<int32_t>(preNavdestinationNodes.size());
1982 if (size == 0) {
1983 return;
1984 }
1985 // find the nodes need to do EXIT_PUSH
1986 for (int32_t index = preStartIndex; index < size; index++) {
1987 auto node = GetNavDestinationNode(preNavdestinationNodes[index].second.Upgrade());
1988 CHECK_NULL_VOID(node);
1989 auto preNode = AceType::DynamicCast<FrameNode>(node);
1990 CHECK_NULL_VOID(preNode);
1991 auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1992 if (preNavdestination && TriggerNavDestinationTransition(
1993 preNavdestination, NavigationOperation::PUSH, false) == INVALID_ANIMATION_ID) {
1994 preNavdestination->InitSystemTransitionPush(false);
1995 prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
1996 }
1997 }
1998 }
1999
InitPushCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList)2000 void NavigationGroupNode::InitPushCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList)
2001 {
2002 // find the nodes need to do ENTER_PUSH
2003 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2004 CHECK_NULL_VOID(navigationPattern);
2005 auto curNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2006 CHECK_NULL_VOID(curNavdestinationNode);
2007 auto curEndIndex = curNavdestinationNode->GetIndex();
2008 auto curStartIndex = lastStandardIndex_;
2009 auto stack = navigationPattern->GetNavigationStack();
2010 for (int32_t index = curStartIndex; index <= curEndIndex; index++) {
2011 auto node = GetNavDestinationNode(stack->Get(index));
2012 CHECK_NULL_VOID(node);
2013 auto curNode = AceType::DynamicCast<FrameNode>(node);
2014 CHECK_NULL_VOID(curNode);
2015 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2016 if (curNavDestination && TriggerNavDestinationTransition(
2017 curNavDestination, NavigationOperation::PUSH, true) == INVALID_ANIMATION_ID) {
2018 curNavDestination->InitSystemTransitionPush(true);
2019 curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
2020 }
2021 }
2022 }
2023
CreateAnimationOption(const RefPtr<Curve> & curve,FillMode mode,int32_t duration,const NavigationGroupNode::AnimationFinishCallback & callback)2024 AnimationOption NavigationGroupNode::CreateAnimationOption(const RefPtr<Curve>& curve, FillMode mode,
2025 int32_t duration, const NavigationGroupNode::AnimationFinishCallback& callback)
2026 {
2027 AnimationOption option;
2028 option.SetCurve(curve);
2029 option.SetFillMode(mode);
2030 option.SetDuration(duration);
2031 option.SetOnFinishEvent(callback);
2032 return option;
2033 }
2034
CheckAnimationIdValid(const RefPtr<FrameNode> & curNode,const int32_t animationId)2035 bool NavigationGroupNode::CheckAnimationIdValid(const RefPtr<FrameNode>& curNode, const int32_t animationId)
2036 {
2037 auto navDestinationBaseNode = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
2038 CHECK_NULL_RETURN(navDestinationBaseNode, false);
2039 auto result = navDestinationBaseNode->GetAnimationId() == animationId;
2040 if (!result) {
2041 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "animation id is invalid");
2042 }
2043 return result;
2044 }
2045
ToDumpString()2046 std::string NavigationGroupNode::ToDumpString()
2047 {
2048 std::string dumpString;
2049 auto navigationPattern = GetPattern<NavigationPattern>();
2050 CHECK_NULL_RETURN(navigationPattern, dumpString);
2051 auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
2052 CHECK_NULL_RETURN(navigationLayoutProperty, dumpString);
2053 NavigationMode usrSetMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
2054 NavigationMode actualMode = navigationPattern->GetNavigationMode();
2055 std::string mode;
2056 switch (usrSetMode) {
2057 case NavigationMode::STACK:
2058 mode = "STACK";
2059 break;
2060 case NavigationMode::SPLIT:
2061 mode = "SPLIT";
2062 break;
2063 case NavigationMode::AUTO:
2064 mode = (actualMode == NavigationMode::STACK) ? "AUTO(STACK)" : "AUTO(SPLIT)";
2065 break;
2066 default:
2067 mode = "INVALID";
2068 break;
2069 }
2070 dumpString.append("|-> Navigation ID: ");
2071 dumpString.append(std::to_string(GetId()));
2072 dumpString.append(", Depth: ");
2073 dumpString.append(std::to_string(GetDepth()));
2074 dumpString.append(", Mode: \"");
2075 dumpString.append(mode);
2076 dumpString.append("\", NavDestinations:");
2077 return dumpString;
2078 }
2079
ResetSystemAnimationProperties(const RefPtr<FrameNode> & navDestinationNode)2080 void NavigationGroupNode::ResetSystemAnimationProperties(const RefPtr<FrameNode>& navDestinationNode)
2081 {
2082 auto navDestination = DynamicCast<NavDestinationGroupNode>(navDestinationNode);
2083 CHECK_NULL_VOID(navDestination);
2084 auto renderContext = navDestination->GetRenderContext();
2085 CHECK_NULL_VOID(renderContext);
2086 // update navDestination's translateXY
2087 renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
2088 auto titleBarNode = AceType::DynamicCast<FrameNode>(navDestination->GetTitleBarNode());
2089 CHECK_NULL_VOID(titleBarNode);
2090 auto titleBarRenderContext = titleBarNode->GetRenderContext();
2091 CHECK_NULL_VOID(titleBarRenderContext);
2092 // update titleBar's translateXY
2093 titleBarRenderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
2094 }
2095 } // namespace OHOS::Ace::NG
2096