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