• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/perfmonitor/perf_constants.h"
20 #include "base/perfmonitor/perf_monitor.h"
21 
22 #if !defined(ACE_UNITTEST)
23 #include "core/components_ng/base/transparent_node_detector.h"
24 #endif
25 
26 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
27 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
28 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
29 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
30 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
31 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
32 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.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 constexpr int32_t SOFT_DEFAULT_ANIMATION_DURATION = 400;
42 constexpr int32_t SOFT_POP_ANIMATION_OPACITY_DURATION = 100;
43 constexpr int32_t SOFT_PUSH_ANIMATION_OPACITY_DURATION = 150;
44 constexpr int32_t SOFT_ANIMATION_OPACITY_DELAY = 50;
45 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
46 const RefPtr<InterpolatingSpring> springCurve = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f);
47 const RefPtr<CubicCurve> replaceCurve = AceType::MakeRefPtr<CubicCurve>(0.33, 0.0, 0.67, 1.0);
48 
ExitWindow(PipelineContext * context)49 void ExitWindow(PipelineContext* context)
50 {
51     auto container = Container::Current();
52     CHECK_NULL_VOID(container);
53     if (container->IsUIExtensionWindow()) {
54         container->TerminateUIExtension();
55     } else {
56         auto windowManager = context->GetWindowManager();
57         CHECK_NULL_VOID(windowManager);
58         windowManager->WindowPerformBack();
59     }
60 }
61 
UpdateTransitionAnimationId(const RefPtr<FrameNode> & node,int32_t id)62 void UpdateTransitionAnimationId(const RefPtr<FrameNode>& node, int32_t id)
63 {
64     auto navDestinationBaseNode = AceType::DynamicCast<NavDestinationNodeBase>(node);
65     CHECK_NULL_VOID(navDestinationBaseNode);
66     navDestinationBaseNode->UpdateAnimationId(id);
67 }
68 
TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode> & navDestination,NavigationOperation operation,bool isEnter)69 int32_t TriggerNavDestinationTransition(const RefPtr<NavDestinationGroupNode>& navDestination,
70     NavigationOperation operation, bool isEnter)
71 {
72     CHECK_NULL_RETURN(navDestination, INVALID_ANIMATION_ID);
73     return navDestination->DoTransition(operation, isEnter);
74 }
75 } // namespace
76 class InspectorFilter;
77 
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)78 RefPtr<NavigationGroupNode> NavigationGroupNode::GetOrCreateGroupNode(
79     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
80 {
81     auto frameNode = GetFrameNode(tag, nodeId);
82     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavigationGroupNode>(frameNode));
83     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
84     auto navigationGroupNode = AceType::MakeRefPtr<NavigationGroupNode>(tag, nodeId, pattern);
85     navigationGroupNode->InitializePatternAndContext();
86     ElementRegister::GetInstance()->AddUINode(navigationGroupNode);
87     return navigationGroupNode;
88 }
89 
~NavigationGroupNode()90 NavigationGroupNode::~NavigationGroupNode()
91 {
92     auto navigationPattern = GetPattern<NavigationPattern>();
93     const auto& navDestinationNodes = navigationPattern->GetAllNavDestinationNodes();
94     for (auto iter : navDestinationNodes) {
95         auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(iter.second));
96         if (navDestinationNode) {
97             navDestinationNode->GetPattern<NavDestinationPattern>()->SetCustomNode(nullptr);
98         }
99     }
100     auto context = GetContextWithCheck();
101     CHECK_NULL_VOID(context);
102     auto stageManager = context->GetStageManager();
103     CHECK_NULL_VOID(stageManager);
104     RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
105     CHECK_NULL_VOID(pageNode);
106     auto pagePattern = pageNode->GetPattern<PagePattern>();
107     CHECK_NULL_VOID(pagePattern);
108     CHECK_NULL_VOID(pagePattern->GetPageInfo());
109     int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
110     context->RemoveNavigationNode(pageId, GetId());
111     context->DeleteNavigationNode(curId_);
112 }
113 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)114 void NavigationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
115 {
116     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
117     CHECK_NULL_VOID(pattern);
118     auto navBar = AceType::DynamicCast<NavBarNode>(GetNavBarNode());
119     CHECK_NULL_VOID(navBar);
120     auto contentNode = navBar->GetContentNode();
121     if (!contentNode) {
122         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
123         contentNode = FrameNode::GetOrCreateFrameNode(
124             V2::NAVBAR_CONTENT_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
125         navBar->SetContentNode(contentNode);
126         navBar->AddChild(contentNode);
127 
128         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
129             auto navBarContentNode = AceType::DynamicCast<FrameNode>(contentNode);
130             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
131                 .edges = SAFE_AREA_EDGE_ALL };
132             navBarContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
133         }
134     }
135     contentNode->AddChild(child);
136 }
137 
UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode> & remainChild,bool modeChange)138 void NavigationGroupNode::UpdateNavDestinationNodeWithoutMarkDirty(const RefPtr<UINode>& remainChild, bool modeChange)
139 {
140     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
141     CHECK_NULL_VOID(pattern);
142     const auto& navDestinationNodes = pattern->GetAllNavDestinationNodes();
143 
144     auto navigationContentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
145     CHECK_NULL_VOID(navigationContentNode);
146     bool hasChanged = false;
147     int32_t slot = 0;
148     int32_t beforeLastStandardIndex = lastStandardIndex_;
149     auto preLastStandardNode = AceType::DynamicCast<NavDestinationGroupNode>(
150         navigationContentNode->GetChildAtIndex(beforeLastStandardIndex));
151     if (pattern->GetIsPreForceSetList()) {
152         // if page is force set, some node may not on the tree, so we need get page from preNavPathList.
153         auto preNodes = pattern->GetAllNavDestinationNodesPrev();
154         if (beforeLastStandardIndex < static_cast<int32_t>(preNodes.size()) && beforeLastStandardIndex >= 0) {
155             preLastStandardNode = AceType::DynamicCast<NavDestinationGroupNode>(
156                 NavigationGroupNode::GetNavDestinationNode(preNodes[beforeLastStandardIndex].second.Upgrade()));
157         }
158     }
159 
160     //save preLastStandardIndex_ before update and check whether standard page changed
161     preLastStandardIndex_ = lastStandardIndex_;
162     UpdateLastStandardIndex();
163 
164     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "last standard page index is %{public}d", lastStandardIndex_);
165     if (!ReorderNavDestination(navDestinationNodes, navigationContentNode, slot, hasChanged)) {
166         return;
167     }
168 
169     for (uint32_t index = 0; index < navDestinationNodes.size(); index++) {
170         const auto& childNode = navDestinationNodes[index];
171         const auto& uiNode = childNode.second;
172         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
173         hasChanged = (UpdateNavDestinationVisibility(navDestination, remainChild, index,
174             navDestinationNodes.size(), preLastStandardNode) || hasChanged);
175     }
176 
177     auto context = GetContextRefPtr();
178     if (pattern->IsForceSplitSupported(context)) {
179         primaryNodesToBeRemoved_.clear();
180     }
181     RemoveRedundantNavDestination(
182         navigationContentNode, remainChild, static_cast<int32_t>(slot), hasChanged, preLastStandardNode);
183     if (modeChange) {
184         navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
185     } else if (hasChanged) {
186         navigationContentNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
187     }
188 
189     if (pattern->IsForceSplitSupported(context)) {
190         pattern->BackupPrimaryNodes();
191         pattern->RecognizeHomePageIfNeeded();
192         pattern->SwapNavDestinationAndProxyNode(false);
193         pattern->SetPrimaryNodesToBeRemoved(std::move(primaryNodesToBeRemoved_));
194     }
195 }
196 
ReorderNavDestination(const std::vector<std::pair<std::string,RefPtr<UINode>>> & navDestinationNodes,RefPtr<FrameNode> & navigationContentNode,int32_t & slot,bool & hasChanged)197 bool NavigationGroupNode::ReorderNavDestination(
198     const std::vector<std::pair<std::string, RefPtr<UINode>>>& navDestinationNodes,
199     RefPtr<FrameNode>& navigationContentNode, int32_t& slot, bool& hasChanged)
200 {
201     auto context = GetContextRefPtr();
202     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
203     CHECK_NULL_RETURN(pattern, false);
204     auto stack = pattern->GetNavigationStack();
205     for (uint32_t i = 0; i != navDestinationNodes.size(); ++i) {
206         const auto& childNode = navDestinationNodes[i];
207         const auto& uiNode = childNode.second;
208         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
209         if (navDestination == nullptr) {
210             if (stack && (stack->IsFromRecovery(i) || stack->GetIsForceSet(i))) {
211                 continue;
212             }
213             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "get destination node failed");
214             return false;
215         }
216         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
217         CHECK_NULL_RETURN(navDestinationPattern, false);
218         navDestinationPattern->SetName(childNode.first);
219         navDestinationPattern->SetCustomNode(uiNode);
220         navDestinationPattern->SetIndex(static_cast<int32_t>(i));
221         if (i == navDestinationNodes.size() - 1 && stack) {
222             navDestinationPattern->UpdateSerializedParam(stack->GetSerializedParamSafely(static_cast<int32_t>(i)));
223         }
224         SetBackButtonEvent(navDestination);
225         navDestination->SetIndex(i);
226         auto eventHub = navDestination->GetOrCreateEventHub<NavDestinationEventHub>();
227         if (eventHub && !eventHub->GetOnStateChange()) {
228             auto onStateChangeMap = pattern->GetOnStateChangeMap();
229             auto iter = onStateChangeMap.find(uiNode->GetId());
230             if (iter != onStateChangeMap.end()) {
231                 eventHub->SetOnStateChange(iter->second);
232                 pattern->DeleteOnStateChangeItem(iter->first);
233             }
234         }
235         int32_t childIndex = navigationContentNode->GetChildIndex(navDestination);
236         bool needMoveProxyNode = false;
237         RefPtr<NavDestinationGroupNode> proxyNode = nullptr;
238         if (pattern->IsForceSplitSupported(context) && childIndex < 0 &&
239             navDestination->IsShowInPrimaryPartition() && navDestination->GetOrCreateProxyNode()) {
240             proxyNode = navDestination->GetOrCreateProxyNode();
241             childIndex = navigationContentNode->GetChildIndex(proxyNode);
242             needMoveProxyNode = proxyNode != nullptr && childIndex >= 0;
243         }
244         if (childIndex < 0) {
245             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "mountToParent navdestinationId:%{public}d, slot:%{public}d",
246                 navDestination->GetId(), slot);
247             navDestination->MountToParent(navigationContentNode, slot);
248             hasChanged = true;
249         } else if (childIndex != slot) {
250             if (needMoveProxyNode) {
251                 proxyNode->MovePosition(slot);
252             } else {
253                 navDestination->MovePosition(slot);
254             }
255             hasChanged = true;
256         }
257         slot++;
258     }
259     return true;
260 }
261 
RemoveRedundantNavDestination(RefPtr<FrameNode> & navigationContentNode,const RefPtr<UINode> & remainChild,int32_t slot,bool & hasChanged,const RefPtr<NavDestinationGroupNode> & preLastStandardNode)262 void NavigationGroupNode::RemoveRedundantNavDestination(RefPtr<FrameNode>& navigationContentNode,
263     const RefPtr<UINode>& remainChild, int32_t slot, bool& hasChanged,
264     const RefPtr<NavDestinationGroupNode>& preLastStandardNode)
265 {
266     auto pattern = GetPattern<NavigationPattern>();
267     RefPtr<UINode> maxAnimatingDestination = nullptr;
268     RefPtr<UINode> remainDestination = GetNavDestinationNode(remainChild);
269     RefPtr<UINode> curTopDestination = navigationContentNode->GetChildAtIndex(slot - 1);
270     // record remove destination size
271     int32_t removeSize = 0;
272     bool hideNodesFinish = false;
273     // record animating destination size
274     int32_t animatingSize = 0;
275     int32_t remainNodeIndex = pattern->IsCurTopNewInstance() ? slot - 1 : slot;
276     while (slot + removeSize + animatingSize < static_cast<int32_t>(navigationContentNode->GetChildren().size())) {
277         // delete useless nodes that are not at the top
278         int32_t candidateIndex = static_cast<int32_t>(navigationContentNode->GetChildren().size()) - 1 - animatingSize;
279         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
280             navigationContentNode->GetChildAtIndex(candidateIndex));
281         if (!navDestination) {
282             navigationContentNode->RemoveChildAtIndex(candidateIndex);
283             hasChanged = true;
284             continue;
285         }
286         navDestination->SetInCurrentStack(false);
287         auto eventHub = navDestination->GetOrCreateEventHub<NavDestinationEventHub>();
288         if (eventHub) {
289             eventHub->FireChangeEvent(false);
290         }
291         if (navDestination == remainDestination) {
292             if (pattern->IsCurTopNewInstance()) {
293                 // remain the last child for push animation, and this child
294                 // will be remove in push's animation finish callback
295                 navDestination->SetNeedRemoveInPush(true);
296                 remainNodeIndex = slot - 1;
297                 navDestination->MovePosition(remainNodeIndex);
298             } else {
299                 // remain the last child for pop animation
300                 remainNodeIndex = slot;
301                 navDestination->MovePosition(slot);
302             }
303             ++slot;
304             continue;
305         }
306         // The NavDestination in the EXIT animation needs to be cleaned in the animation onfinish callback.
307         if (navDestination->IsOnAnimation()) {
308             if (navDestination->GetTransitionType() == PageTransitionType::EXIT_POP) {
309                 ++animatingSize;
310                 continue;
311             }
312             if (navDestination->NeedRemoveInPush()) {
313                 if (maxAnimatingDestination == nullptr) {
314                     maxAnimatingDestination = navDestination;
315                 }
316                 ++animatingSize;
317                 continue;
318             }
319         }
320         // remove content child
321         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
322         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "remove child: %{public}s", navDestinationPattern->GetName().c_str());
323         if (navDestination->GetIndex() >= preLastStandardIndex_ && !hideNodesFinish) {
324             if (navDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD
325                 && preLastStandardNode != navDestination) {
326                 hideNodesFinish = true;
327                 DealRemoveDestination(navDestination);
328                 hasChanged = true;
329                 continue;
330             }
331             hideNodes_.emplace_back(std::make_pair(navDestination, true));
332             if (navDestination->GetNavDestinationType() == NavDestinationType::PROXY) {
333                 auto primaryNode = navDestination->GetPrimaryNode();
334                 if (primaryNode) {
335                     primaryNodesToBeRemoved_.push_back(primaryNode);
336                 }
337             }
338             navDestination->SetCanReused(false);
339             removeSize++;
340             // move current destination position to navigation stack size + remove navDestination nodes
341             if (remainNodeIndex >= 0) {
342                 navDestination->MovePosition(remainNodeIndex);
343             }
344             continue;
345         }
346         DealRemoveDestination(navDestination);
347         hasChanged = true;
348     }
349     if (pattern->IsCurTopNewInstance()) {
350         ReorderAnimatingDestination(
351             navigationContentNode, maxAnimatingDestination, remainDestination, curTopDestination);
352     }
353 }
354 
ReorderAnimatingDestination(RefPtr<FrameNode> & navigationContentNode,RefPtr<UINode> & maxAnimatingDestination,RefPtr<UINode> & remainDestination,RefPtr<UINode> & curTopDestination)355 void NavigationGroupNode::ReorderAnimatingDestination(RefPtr<FrameNode>& navigationContentNode,
356     RefPtr<UINode>& maxAnimatingDestination, RefPtr<UINode>& remainDestination, RefPtr<UINode>& curTopDestination)
357 {
358     auto maxAnimatingIndex = navigationContentNode->GetChildIndex(maxAnimatingDestination);
359     if (maxAnimatingIndex != -1 && remainDestination) {
360         remainDestination->MovePosition(maxAnimatingIndex + 1);
361     }
362     auto remainIndex = navigationContentNode->GetChildIndex(remainDestination);
363     if (remainIndex != -1 && curTopDestination) {
364         curTopDestination->MovePosition(remainIndex + 1);
365     }
366 }
367 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const368 void NavigationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
369 {
370     FrameNode::ToJsonValue(json, filter);
371     auto navBarOrHomeDestNode = AceType::DynamicCast<NavDestinationNodeBase>(GetNavBarOrHomeDestinationNode());
372     CHECK_NULL_VOID(navBarOrHomeDestNode);
373     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarOrHomeDestNode->GetTitleBarNode());
374     if (titleBarNode) {
375         std::string title = NavigationTitleUtil::GetTitleString(titleBarNode,
376             navBarOrHomeDestNode->GetPrevTitleIsCustomValue(false));
377         std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
378         json->PutExtAttr("title", title.c_str(), filter);
379         json->PutExtAttr("subtitle", subtitle.c_str(), filter);
380     }
381     auto navBarPattern = navBarOrHomeDestNode->GetPattern<NavDestinationPatternBase>();
382     if (navBarPattern) {
383         auto menuOptionsJson = JsonUtil::Create(true);
384         auto moreButtonOptions = navBarPattern->GetMenuOptions();
385         moreButtonOptions.ToJsonValue(menuOptionsJson, filter);
386         json->PutExtAttr("menuOptions", menuOptionsJson, filter);
387     }
388     json->PutExtAttr("menus", navBarOrHomeDestNode->GetBarItemsString(true).c_str(), filter);
389     json->PutExtAttr("toolBar", navBarOrHomeDestNode->GetBarItemsString(false).c_str(), filter);
390     auto property = navBarOrHomeDestNode->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
391     CHECK_NULL_VOID(property);
392     auto navBarLayoutProperty = AceType::DynamicCast<NavBarLayoutProperty>(property);
393     if (navBarLayoutProperty) {
394         json->PutExtAttr("titleMode", navBarLayoutProperty->GetTitleModeString().c_str(), filter);
395     }
396     json->PutExtAttr("hideBackButton", property->GetHideBackButtonValue(false), filter);
397     json->PutExtAttr("hideTitleBar", property->GetHideTitleBarValue(false), filter);
398     json->PutExtAttr("hideToolBar", property->GetHideToolBarValue(false), filter);
399 }
400 
GetNavDestinationNode(RefPtr<UINode> uiNode)401 RefPtr<UINode> NavigationGroupNode::GetNavDestinationNode(RefPtr<UINode> uiNode)
402 {
403     if (!uiNode) {
404         return nullptr;
405     }
406     // create NavDestinationNode from uiNode stored in NavigationStack
407     while (uiNode) {
408         if (uiNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
409             // this is a navDestination node
410             return uiNode;
411         }
412         if (AceType::DynamicCast<UINode>(uiNode)) {
413             // this is an UINode, go deep further for navDestination node
414             auto children = uiNode->GetChildren();
415             uiNode = children.front();
416             continue;
417         }
418     }
419     CHECK_NULL_RETURN(uiNode, nullptr);
420     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "get navDestination node failed: id: %{public}d, %{public}s",
421         uiNode->GetId(), uiNode->GetTag().c_str());
422     return nullptr;
423 }
424 
HandleBackForHomeDestination()425 bool NavigationGroupNode::HandleBackForHomeDestination()
426 {
427     auto pattern = GetPattern<NavigationPattern>();
428     CHECK_NULL_RETURN(pattern, false);
429     do {
430         auto parentNavPattern = pattern->GetParentNavigationPattern();
431         CHECK_NULL_BREAK(parentNavPattern);
432         auto parentNavNode = AceType::DynamicCast<NavigationGroupNode>(parentNavPattern->GetHost());
433         CHECK_NULL_BREAK(parentNavNode);
434         bool isEntry = false;
435         if (parentNavNode->CheckCanHandleBack(isEntry)) {
436             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "parent Navigation handle back for HomeNavDestination");
437             return true;
438         }
439     } while (false);
440     auto context = GetContext();
441     CHECK_NULL_RETURN(context, false);
442     auto frontend = context->GetFrontend();
443     CHECK_NULL_RETURN(frontend, false);
444     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Frontend will handle back for HomeNavDestination");
445     return frontend->OnBackPressed();
446 }
447 
SetBackButtonEvent(const RefPtr<NavDestinationGroupNode> & navDestination)448 void NavigationGroupNode::SetBackButtonEvent(const RefPtr<NavDestinationGroupNode>& navDestination)
449 {
450     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestination->GetTitleBarNode());
451     CHECK_NULL_VOID(titleBarNode);
452     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetCustomBackButton());
453     if (!backButtonNode) {
454         backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
455     }
456     CHECK_NULL_VOID(backButtonNode);
457     auto backButtonEventHub = backButtonNode->GetOrCreateEventHub<EventHub>();
458     CHECK_NULL_VOID(backButtonEventHub);
459     auto onBackButtonEvent = [navDestinationWeak = WeakPtr<NavDestinationGroupNode>(navDestination),
460                                  navigationWeak = WeakClaim(this)](GestureEvent& /*info*/) -> bool {
461         auto navDestination = navDestinationWeak.Upgrade();
462         TAG_LOGD(AceLogTag::ACE_NAVIGATION, "click navigation back button");
463         CHECK_NULL_RETURN(navDestination, false);
464         auto eventHub = navDestination->GetOrCreateEventHub<NavDestinationEventHub>();
465         CHECK_NULL_RETURN(eventHub, false);
466         eventHub->SetState(NavDestinationState::ON_BACKPRESS);
467         auto navdestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
468         UIObserverHandler::GetInstance().NotifyNavigationStateChange(
469             navdestinationPattern, NavDestinationState::ON_BACKPRESS);
470         auto isOverride = eventHub->GetOnBackPressedEvent();
471         auto result = false;
472         if (isOverride) {
473             result = eventHub->FireOnBackPressedEvent();
474         }
475         auto navigation = navigationWeak.Upgrade();
476         CHECK_NULL_RETURN(navigation, false);
477         navigation->CheckIsNeedForceExitWindow(result);
478         if (result) {
479             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation user onBackPress return true");
480             return true;
481         }
482         if (navDestination->IsHomeDestination()) {
483             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "will handle back for HomeNavDestination");
484             return navigation->HandleBackForHomeDestination();
485         }
486         // if set hideNavBar and stack size is one, return false
487         auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(navigation->GetLayoutProperty());
488         CHECK_NULL_RETURN(navigationLayoutProperty, false);
489         auto pattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
490         CHECK_NULL_RETURN(pattern, false);
491         auto stack = pattern->GetNavigationStack();
492         CHECK_NULL_RETURN(stack, false);
493         if (navigationLayoutProperty->GetHideNavBarValue(false) && stack->GetSize() <= 1) {
494             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "set hideNavBar and stack size is no more than one");
495             return false;
496         }
497         auto isLastChild = stack->Size() == 1;
498         result = navigation->HandleBack(navDestination, isLastChild, (bool)isOverride);
499         // when js navigationStack is provided, modifyDone will be called by state manager.
500         auto navigationPattern = navigation->GetPattern<NavigationPattern>();
501         CHECK_NULL_RETURN(navigationPattern, false);
502         if (!navigationPattern->GetNavigationStackProvided()) {
503             navigation->MarkModifyDone();
504             navigation->MarkDirtyNode();
505         }
506 
507         return result;
508     }; // backButton event
509 
510     navDestination->SetNavDestinationBackButtonEvent(onBackButtonEvent);
511     backButtonEventHub->GetOrCreateGestureEventHub()->SetUserOnClick(onBackButtonEvent);
512 }
513 
GetTopDestination()514 RefPtr<FrameNode> NavigationGroupNode::GetTopDestination()
515 {
516     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
517     CHECK_NULL_RETURN(pattern, nullptr);
518     auto navigationStack = pattern->GetNavigationStack();
519     CHECK_NULL_RETURN(navigationStack, nullptr);
520     auto topNavdestination = AceType::DynamicCast<FrameNode>(GetNavDestinationNode(navigationStack->Get()));
521     return topNavdestination;
522 }
523 
CheckCanHandleBack(bool & isEntry)524 bool NavigationGroupNode::CheckCanHandleBack(bool& isEntry)
525 {
526     auto navigation = AceType::WeakClaim(this).Upgrade();
527     CHECK_NULL_RETURN(navigation, false);
528     auto navigationPattern = GetPattern<NavigationPattern>();
529     CHECK_NULL_RETURN(navigationPattern, false);
530 
531     auto navigationStack = navigationPattern->GetNavigationStack();
532     CHECK_NULL_RETURN(navigationStack, false);
533     RefPtr<NavDestinationGroupNode> navDestination = nullptr;
534     do {
535         navDestination = AceType::DynamicCast<NavDestinationGroupNode>(
536             NavigationGroupNode::GetNavDestinationNode(navigationStack->Get()));
537         if (navDestination) {
538             break;
539         }
540         if (navigationStack->Empty()) {
541             navDestination = AceType::DynamicCast<NavDestinationGroupNode>(customHomeDestination_);
542         }
543         if (navDestination) {
544             break;
545         }
546         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find destination node to process back press");
547         return false;
548     } while (false);
549     if (!navigationPattern->IsFinishInteractiveAnimation()) {
550         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't handle back press during interactive animation");
551         return true;
552     }
553     auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
554     if (navDestinationPattern->OverlayOnBackPressed()) {
555         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination's ovelay consume backPressed event: %{public}s",
556             navDestinationPattern->GetName().c_str());
557         return true;
558     }
559     auto navDestinationContext = navDestinationPattern->GetNavDestinationContext();
560     CHECK_NULL_RETURN(navDestinationContext, false);
561     auto navPathInfo = navDestinationContext->GetNavPathInfo();
562     CHECK_NULL_RETURN(navPathInfo, false);
563     auto isPathEntry = navPathInfo->GetIsEntry();
564     if (isPathEntry) {
565         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s is entry navDestination, do not consume backPressed event",
566             navDestinationPattern->GetName().c_str());
567         navPathInfo->SetIsEntry(false);
568         auto index = navDestinationContext->GetIndex();
569         navigationStack->SetIsEntryByIndex(index, false);
570         isEntry = true;
571         return false;
572     }
573     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navDestination consume back button event: %{public}s",
574         navDestinationPattern->GetName().c_str());
575     GestureEvent gestureEvent;
576     return navDestination->GetNavDestinationBackButtonEvent()(gestureEvent);
577 }
578 
CheckIsNeedForceExitWindow(bool result)579 void NavigationGroupNode::CheckIsNeedForceExitWindow(bool result)
580 {
581     auto context = GetContext();
582     CHECK_NULL_VOID(context);
583     if (!context->GetInstallationFree() || !result) {
584         // if is not atommic service and result is false, don't process.
585         return;
586     }
587 
588     auto navigationPattern = GetPattern<NavigationPattern>();
589     CHECK_NULL_VOID(navigationPattern);
590     auto isHasParentNavigation = navigationPattern->GetParentNavigationPattern();
591     auto navigationStack = navigationPattern->GetNavigationStack();
592     CHECK_NULL_VOID(navigationStack);
593     auto overlayManager = context->GetOverlayManager();
594     CHECK_NULL_VOID(overlayManager);
595     auto stageManager = context->GetStageManager();
596     CHECK_NULL_VOID(stageManager);
597     int32_t navigationStackSize = static_cast<int32_t>(navigationStack->GetAllNavDestinationNodes().size());
598     int32_t pageSize =
599         stageManager->GetStageNode() ? static_cast<int32_t>(stageManager->GetStageNode()->GetChildren().size()) : 0;
600     if (navigationStackSize != 1 || isHasParentNavigation || !overlayManager->IsModalEmpty() || pageSize != 1) {
601         return;
602     }
603 
604     /*
605     * when stack size is one, there four situations.
606     * 1.split mode, navbar visible.
607     * 2.split mode, navbar invisible.
608     * 3.stack mode, navbar visible.
609     * 4.stack mode, navbar invisible.
610     * Only the third situation don't need to be intercepted
611     */
612     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
613     CHECK_NULL_VOID(layoutProperty);
614     bool isSplitMode = GetNavigationMode() == NavigationMode::SPLIT;
615     bool isLastNavdesNeedIntercept = isSplitMode || layoutProperty->GetHideNavBar().value_or(false);
616     if (!isLastNavdesNeedIntercept) {
617         return;
618     }
619     ExitWindow(context);
620     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navdestination onbackpress intercepted, exit window.");
621 }
622 
HandleBack(const RefPtr<FrameNode> & node,bool isLastChild,bool isOverride)623 bool NavigationGroupNode::HandleBack(const RefPtr<FrameNode>& node, bool isLastChild, bool isOverride)
624 {
625     auto navigationPattern = GetPattern<NavigationPattern>();
626     if (!isOverride && !isLastChild) {
627         navigationPattern->RemoveNavDestination();
628         return true;
629     }
630     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
631     CHECK_NULL_RETURN(navDestination, false);
632 
633     auto mode = navigationPattern->GetNavigationMode();
634     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
635     if (isLastChild && (mode == NavigationMode::SPLIT ||
636                            (mode == NavigationMode::STACK && layoutProperty->GetHideNavBar().value_or(false)))) {
637         return false;
638     }
639 
640     navigationPattern->RemoveNavDestination();
641     return true;
642 }
643 
FetchNavigationManager()644 RefPtr<NavigationManager> NavigationGroupNode::FetchNavigationManager()
645 {
646     auto context = GetContext();
647     CHECK_NULL_RETURN(context, nullptr);
648     auto navigationManager = context->GetNavigationManager();
649     CHECK_NULL_RETURN(navigationManager, nullptr);
650     return navigationManager;
651 }
652 
ConfigureNavigationWithAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)653 void NavigationGroupNode::ConfigureNavigationWithAnimation(
654     const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
655 {
656     auto navigationManager = FetchNavigationManager();
657     CHECK_NULL_VOID(navigationManager);
658     if (!navigationManager->HasCacheNavigationNodeEnable()) {
659         return;
660     }
661     navigationManager->SetNavNodeInTransition(curNode, preNode);
662     navigationManager->SetIsNavigationOnAnimation(true);
663 }
664 
ResetTransitionAnimationNodeState(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)665 void NavigationGroupNode::ResetTransitionAnimationNodeState(
666     const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
667 {
668     auto navigationManager = FetchNavigationManager();
669     CHECK_NULL_VOID(navigationManager);
670     if (!navigationManager->HasCacheNavigationNodeEnable()) {
671         return;
672     }
673     auto curNavDestContentFrameNode = navigationManager->GetNavDestContentFrameNode(curNode);
674     if (curNavDestContentFrameNode) {
675         navigationManager->UpdateAnimationCachedRenderGroup(curNavDestContentFrameNode, false);
676         navigationManager->SetCurNodeAnimationCached(false);
677         navigationManager->SetCurrentNodeNeverSet(true);
678     }
679     auto preNavDestContentFrameNode = navigationManager->GetNavDestContentFrameNode(preNode);
680     if (preNavDestContentFrameNode) {
681         navigationManager->UpdateAnimationCachedRenderGroup(preNavDestContentFrameNode, false);
682         navigationManager->SetPreNodeAnimationCached(false);
683         navigationManager->SetPreNodeNeverSet(true);
684     }
685     navigationManager->SetNavNodeInTransition(nullptr, nullptr);
686     navigationManager->SetIsNavigationOnAnimation(false);
687 }
688 
SetSplitPlaceholder(const RefPtr<NG::UINode> & splitPlaceholder)689 void NavigationGroupNode::SetSplitPlaceholder(const RefPtr<NG::UINode>& splitPlaceholder)
690 {
691     auto prevsplitPlaceholder = splitPlaceholder_;
692     CHECK_NULL_VOID(placeholderContentNode_);
693     CHECK_NULL_VOID(splitPlaceholder);
694     auto splitPlaceholderFrameNode = AceType::DynamicCast<FrameNode>(splitPlaceholder);
695     CHECK_NULL_VOID(splitPlaceholderFrameNode);
696     auto splitPlaceholderLayoutProperty = splitPlaceholderFrameNode->GetLayoutProperty();
697     CHECK_NULL_VOID(splitPlaceholderLayoutProperty);
698     auto&& opts = splitPlaceholderLayoutProperty->GetSafeAreaExpandOpts();
699     if (opts) {
700         splitPlaceholderLayoutProperty->UpdateSafeAreaExpandOpts(*opts);
701     } else {
702         SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
703             .edges = SAFE_AREA_EDGE_ALL };
704         splitPlaceholderLayoutProperty->UpdateSafeAreaExpandOpts(opts);
705     }
706     auto spllitPlaceHolderFrameNode = AceType::DynamicCast<FrameNode>(splitPlaceholder);
707     CHECK_NULL_VOID(spllitPlaceHolderFrameNode);
708     const auto& eventHub = spllitPlaceHolderFrameNode->GetOrCreateEventHub<EventHub>();
709     CHECK_NULL_VOID(eventHub);
710     eventHub->SetEnabled(false);
711     auto focusHub = spllitPlaceHolderFrameNode->GetOrCreateFocusHub();
712     CHECK_NULL_VOID(focusHub);
713     focusHub->SetFocusable(false);
714     if (!prevsplitPlaceholder) {
715         splitPlaceholder->MountToParent(placeholderContentNode_);
716     } else {
717         if (splitPlaceholder != prevsplitPlaceholder) {
718             placeholderContentNode_->ReplaceChild(prevsplitPlaceholder, splitPlaceholder);
719             placeholderContentNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
720         }
721     }
722     splitPlaceholder_ = splitPlaceholder;
723 }
724 
CreateAnimationWithPop(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBarOrHomeDestination)725 void NavigationGroupNode::CreateAnimationWithPop(const TransitionUnitInfo& preInfo, const TransitionUnitInfo& curInfo,
726     const AnimationFinishCallback finishCallback, bool isNavBarOrHomeDestination)
727 {
728     auto pattern = GetPattern<NavigationPattern>();
729     CHECK_NULL_VOID(pattern);
730     // this function has been override for different device type
731     auto preNode = preInfo.transitionNode;
732     auto curNode = curInfo.transitionNode;
733     auto preUseCustomTransition = preInfo.isUseCustomTransition;
734     auto curUseCustomTransition = curInfo.isUseCustomTransition;
735     CHECK_NULL_VOID(preNode);
736     auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
737     CHECK_NULL_VOID(preNavDestination);
738     if (!preUseCustomTransition) {
739         preNavDestination->SystemTransitionPopStart(false);
740     }
741     if (curNode) {
742         if ((isNavBarOrHomeDestination && !pattern->IsForceSplitSuccess()) ||
743             (!isNavBarOrHomeDestination && !curUseCustomTransition)) {
744             auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
745             CHECK_NULL_VOID(nodeBase);
746             nodeBase->SystemTransitionPopStart(true);
747         }
748     }
749     // start transition animation
750     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
751         finishCallback);
752     pattern->OnStartOneTransitionAnimation();
753     auto newPopAnimation = AnimationUtils::StartAnimation(option, [
754         this, preNode, curNode, isNavBarOrHomeDestination, preUseCustomTransition, curUseCustomTransition, pattern]() {
755             ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition start");
756             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
757             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation pop animation start: animationId: %{public}d",
758                 static_cast<int32_t>(animationId_));
759 
760             // ENTER_POP nodes animation
761             if (curNode) {
762                 if ((isNavBarOrHomeDestination && !pattern->IsForceSplitSuccess()) ||
763                     (!isNavBarOrHomeDestination && !curUseCustomTransition)) {
764                     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
765                     CHECK_NULL_VOID(nodeBase);
766                     nodeBase->SystemTransitionPopEnd(true);
767                 }
768             }
769             // EXIT_POP nodes finish animation
770             auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
771             CHECK_NULL_VOID(preNavDestination);
772             if (!preUseCustomTransition) {
773                 preNavDestination->SystemTransitionPopEnd(false);
774             }
775         }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
776     if (newPopAnimation) {
777         popAnimations_.emplace_back(newPopAnimation);
778     }
779     if (!preUseCustomTransition) {
780         auto titleOpacityAnimation = preNavDestination->TitleOpacityAnimation(false);
781         if (titleOpacityAnimation) {
782             popAnimations_.emplace_back(titleOpacityAnimation);
783         }
784         auto backButtonAnimation = preNavDestination->BackButtonAnimation(false);
785         if (backButtonAnimation) {
786             popAnimations_.emplace_back(backButtonAnimation);
787         }
788     }
789     if (!curUseCustomTransition && (!isNavBarOrHomeDestination || !pattern->IsForceSplitSuccess())) {
790         auto maskAnimation = MaskAnimation(curNode, true);
791         if (maskAnimation) {
792             popAnimations_.emplace_back(maskAnimation);
793         }
794     }
795     ConfigureNavigationWithAnimation(preNode, curNode);
796 }
797 
TransitionWithPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBarOrHomeDestination)798 void NavigationGroupNode::TransitionWithPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
799     bool isNavBarOrHomeDestination)
800 {
801     CHECK_NULL_VOID(preNode);
802     /* create animation finish callback */
803     CleanPopAnimations();
804     // update animation id
805     auto popAnimationId = MakeUniqueAnimationId();
806     UpdateTransitionAnimationId(preNode, popAnimationId);
807     UpdateTransitionAnimationId(curNode, popAnimationId);
808     /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
809     int32_t preAnimationId = TriggerNavDestinationTransition(
810         DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::POP, false);
811     auto preUseCustomTransition = true;
812     if (preAnimationId == INVALID_ANIMATION_ID) {
813         preAnimationId = popAnimationId;
814         preUseCustomTransition = false;
815     }
816     auto curUseCustomTransition = true;
817     int32_t curAnimationId = TriggerNavDestinationTransition(
818         DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::POP, true);
819     if (curAnimationId == INVALID_ANIMATION_ID) {
820         curAnimationId = popAnimationId;
821         curUseCustomTransition = false;
822     }
823     if (preUseCustomTransition && curUseCustomTransition) {
824         return;
825     }
826     std::function<void()> onFinish = [weakPreNode = WeakPtr<FrameNode>(preNode), preUseCustomTransition,
827         weakCurNode = WeakPtr<FrameNode>(curNode), weakNavigation = WeakClaim(this), preAnimationId, curAnimationId] {
828             ACE_SCOPED_TRACE_COMMERCIAL("Navigation page pop transition end");
829             TAG_LOGI(AceLogTag::ACE_NAVIGATION,
830                 "navigation pop animation end, pre node animationId: %{public}d", preAnimationId);
831             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
832             auto navigation = weakNavigation.Upgrade();
833             CHECK_NULL_VOID(navigation);
834             navigation->isOnAnimation_ = false;
835             auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
836             navigation->OnAccessibilityEvent(
837                 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
838             navigation->CleanPopAnimations();
839             auto preNavDesNode = weakPreNode.Upgrade();
840             CHECK_NULL_VOID(preNavDesNode);
841             auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNavDesNode);
842             CHECK_NULL_VOID(preNavdestination);
843             auto curNavDesNode = weakCurNode.Upgrade();
844             navigation->ResetTransitionAnimationNodeState(preNavDesNode, curNavDesNode);
845             if (preNavdestination->IsInDestroying()) {
846                 preNavdestination->SetDestroying(false, false);
847             }
848             if (!preUseCustomTransition && preNavdestination->SystemTransitionPopFinish(preAnimationId)) {
849                 // return true means need to remove the poped navdestination
850                 auto parent = preNavDesNode->GetParent();
851                 CHECK_NULL_VOID(parent);
852                 parent->RemoveChild(preNavDesNode);
853                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
854             }
855             auto context = navigation->GetContextWithCheck();
856             CHECK_NULL_VOID(context);
857             context->MarkNeedFlushMouseEvent();
858             CHECK_NULL_VOID(preNavDesNode);
859             preNavDesNode->AddToOcclusionMap(false);
860         };
861     AnimationFinishCallback callback = [onFinishCb = std::move(onFinish), weakNavigation = WeakClaim(this)]() {
862         auto navigation = weakNavigation.Upgrade();
863         if (onFinishCb) {
864             onFinishCb();
865         }
866         CHECK_NULL_VOID(navigation);
867         auto pattern = navigation->GetPattern<NavigationPattern>();
868         CHECK_NULL_VOID(pattern);
869         pattern->OnFinishOneTransitionAnimation();
870     };
871     TransitionUnitInfo preInfo(preNode, preUseCustomTransition, preAnimationId);
872     TransitionUnitInfo curInfo(curNode, curUseCustomTransition, curAnimationId);
873     if (SystemProperties::IsSoftPageTransition()) {
874         CreateSoftAnimationWithPop(preInfo, curInfo, callback,
875             isNavBarOrHomeDestination && customHomeDestination_ == nullptr);
876     } else {
877         CreateAnimationWithPop(preInfo, curInfo, callback, isNavBarOrHomeDestination);
878     }
879     // remove jschild when pop page animation begin
880     RemoveJsChildImmediately(preNode, preUseCustomTransition, preAnimationId);
881 
882     // clear this flag for navBar / homeNavDestination layout only
883     if (isNavBarOrHomeDestination) {
884         SetNeedSetInvisible(false);
885     }
886     isOnAnimation_ = true;
887     CHECK_NULL_VOID(preNode);
888     preNode->AddToOcclusionMap(true);
889 }
890 
RemoveJsChildImmediately(const RefPtr<FrameNode> & preNode,bool preUseCustomTransition,int32_t preAnimationId)891 void NavigationGroupNode::RemoveJsChildImmediately(const RefPtr<FrameNode>& preNode, bool preUseCustomTransition,
892     int32_t preAnimationId)
893 {
894     if (!CheckEnableCustomNodeDel()) {
895         return;
896     }
897 
898     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
899         return;
900     }
901 
902     auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
903     CHECK_NULL_VOID(preNavdestination);
904 
905     if (preUseCustomTransition || !preNavdestination->CheckTransitionPop(preAnimationId)) {
906         return;
907     }
908 
909     if (preNode->HasSkipNode()) {
910         return;
911     }
912 
913     auto removeJsFun = [weakPreNode = WeakPtr<FrameNode>(preNode)]() {
914         auto preNavDesNode = weakPreNode.Upgrade();
915         CHECK_NULL_VOID(preNavDesNode);
916         preNavDesNode->SetDestroying();
917     };
918     auto taskExecutor = Container::CurrentTaskExecutor();
919     CHECK_NULL_VOID(taskExecutor);
920     taskExecutor->PostDelayedTask(removeJsFun, TaskExecutor::TaskType::UI,
921         RELEASE_JSCHILD_DELAY_TIME, "ArkUIRemoveJsChild");
922 }
923 
CreateAnimationWithPush(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBarOrHomeDestination)924 void NavigationGroupNode::CreateAnimationWithPush(const TransitionUnitInfo& preInfo, const TransitionUnitInfo& curInfo,
925     const AnimationFinishCallback finishCallback, bool isNavBarOrHomeDestination)
926 {
927     auto pattern = GetPattern<NavigationPattern>();
928     CHECK_NULL_VOID(pattern);
929     auto preNode = preInfo.transitionNode;
930     auto curNode = curInfo.transitionNode;
931     auto preUseCustomTransition = preInfo.isUseCustomTransition;
932     auto curUseCustomTransition = curInfo.isUseCustomTransition;
933     // this function has been override for different device type
934     if (preNode) {
935         if ((isNavBarOrHomeDestination && !pattern->IsForceSplitSuccess()) ||
936             (!isNavBarOrHomeDestination && !preUseCustomTransition)) {
937             auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(preNode);
938             CHECK_NULL_VOID(nodeBase);
939             nodeBase->SystemTransitionPushStart(false);
940         }
941     }
942     if (curNode) {
943         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
944         CHECK_NULL_VOID(nodeBase);
945         if (!curUseCustomTransition) {
946             nodeBase->SystemTransitionPushStart(true);
947         }
948     }
949 
950     // start transition animation
951     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
952         finishCallback);
953     NavigationTitleUtil::SetTitleAnimationElapsedTime(option, curNode);
954     pattern->OnStartOneTransitionAnimation();
955     auto newPushAnimation = AnimationUtils::StartAnimation(option, [
956         preNode, curNode, isNavBarOrHomeDestination, preUseCustomTransition, curUseCustomTransition, pattern]() {
957             ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition start");
958             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
959             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation start");
960             if ((isNavBarOrHomeDestination && !pattern->IsForceSplitSuccess()) ||
961                 (preNode && !preUseCustomTransition)) {
962                 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(preNode);
963                 CHECK_NULL_VOID(nodeBase);
964                 nodeBase->SystemTransitionPushEnd(false);
965             }
966             if (curNode && !curUseCustomTransition) {
967                 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
968                 CHECK_NULL_VOID(nodeBase);
969                 nodeBase->SystemTransitionPushEnd(true);
970             }
971     }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
972     if (newPushAnimation) {
973         pushAnimations_.emplace_back(newPushAnimation);
974     }
975     if (!preUseCustomTransition && (!isNavBarOrHomeDestination || !pattern->IsForceSplitSuccess())) {
976         auto maskAnimation = MaskAnimation(preNode, false);
977         if (maskAnimation) {
978             pushAnimations_.emplace_back(maskAnimation);
979         }
980     }
981     if (!curUseCustomTransition) {
982         CHECK_NULL_VOID(curNode);
983         auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
984         CHECK_NULL_VOID(curNavdestination);
985         // title opacity
986         auto titleOpacityAnimation = curNavdestination->TitleOpacityAnimation(true);
987         if (titleOpacityAnimation) {
988             pushAnimations_.emplace_back(titleOpacityAnimation);
989         }
990         // backIcon opacity
991         auto backButtonAnimation = curNavdestination->BackButtonAnimation(true);
992         if (backButtonAnimation) {
993             pushAnimations_.emplace_back(backButtonAnimation);
994         }
995     }
996     if (preNode) {
997         preNode->SetNodeFreeze(true);
998     }
999     ConfigureNavigationWithAnimation(preNode, curNode);
1000 }
1001 
TransitionAnimationIsValid(const RefPtr<FrameNode> & node,bool isNavBarOrHomeDestination,bool isUseNavDestCustomTransition)1002 RefPtr<FrameNode> NavigationGroupNode::TransitionAnimationIsValid(
1003     const RefPtr<FrameNode>& node, bool isNavBarOrHomeDestination, bool isUseNavDestCustomTransition)
1004 {
1005     if (isNavBarOrHomeDestination || isUseNavDestCustomTransition) {
1006         return node;
1007     }
1008     auto destination = AceType::DynamicCast<NavDestinationGroupNode>(node);
1009     if (destination && destination->GetSystemTransitionType() == NavigationSystemTransitionType::NONE) {
1010         return nullptr;
1011     }
1012     return node;
1013 }
1014 
TransitionWithPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBarOrHomeDestination)1015 void NavigationGroupNode::TransitionWithPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1016     bool isNavBarOrHomeDestination)
1017 {
1018     CHECK_NULL_VOID(preNode);
1019     CHECK_NULL_VOID(curNode);
1020 
1021     // Create animation callback
1022     CleanPushAnimations();
1023     auto pushAnimationId = MakeUniqueAnimationId();
1024     UpdateTransitionAnimationId(preNode, pushAnimationId);
1025     UpdateTransitionAnimationId(curNode, pushAnimationId);
1026     /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
1027     int32_t preAnimationId = TriggerNavDestinationTransition(
1028         DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::PUSH, false);
1029     auto preUseCustomTransition = true;
1030     if (preAnimationId == INVALID_ANIMATION_ID) {
1031         preAnimationId = pushAnimationId;
1032         preUseCustomTransition = false;
1033     }
1034     auto curUseCustomTransition = true;
1035     int32_t curAnimationId = TriggerNavDestinationTransition(
1036         DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::PUSH, true);
1037     if (curAnimationId == INVALID_ANIMATION_ID) {
1038         curAnimationId = pushAnimationId;
1039         curUseCustomTransition = false;
1040     }
1041     if (preUseCustomTransition && curUseCustomTransition) {
1042         return;
1043     }
1044     std::function<void()> onFinish = [weakPreNode = WeakPtr<FrameNode>(preNode), preUseCustomTransition,
1045         weakCurNode = WeakPtr<FrameNode>(curNode), curUseCustomTransition, weakNavigation = WeakClaim(this),
1046         isNavBarOrHomeDestination, preAnimationId, curAnimationId] {
1047             ACE_SCOPED_TRACE_COMMERCIAL("Navigation page push transition end");
1048             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1049             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation push animation end");
1050             auto navigation = weakNavigation.Upgrade();
1051             CHECK_NULL_VOID(navigation);
1052             auto pattern = navigation->GetPattern<NavigationPattern>();
1053             CHECK_NULL_VOID(pattern);
1054             auto preNode = weakPreNode.Upgrade();
1055             while (preNode) {
1056                 preNode->SetNodeFreeze(false);
1057                 preNode->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
1058                 if (!navigation->CheckAnimationIdValid(preNode, preAnimationId)) {
1059                     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "pre node is doing another animation, skip handling.");
1060                     break;
1061                 }
1062                 if (isNavBarOrHomeDestination && !pattern->IsForceSplitSuccess()) {
1063                     auto navBarOrHomeDestination = AceType::DynamicCast<NavDestinationNodeBase>(preNode);
1064                     CHECK_NULL_VOID(navBarOrHomeDestination);
1065                     navBarOrHomeDestination->SystemTransitionPushFinish(false, preAnimationId);
1066                     bool needSetInvisible =
1067                         navBarOrHomeDestination->GetTransitionType() == PageTransitionType::EXIT_PUSH;
1068                     navigation->SetNeedSetInvisible(needSetInvisible);
1069                     bool isInvisible = navBarOrHomeDestination->IsNodeInvisible(navigation);
1070                     if (needSetInvisible && isInvisible) {
1071                         preNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1072                         preNode->SetJSViewActive(false);
1073                         navigation->NotifyPageHide();
1074                     }
1075                     navBarOrHomeDestination->GetRenderContext()->SetOpacity(1.0f);
1076                 } else {
1077                     auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1078                     CHECK_NULL_VOID(preDestination);
1079                     if (preUseCustomTransition) {
1080                         // no need handle pre node here. it will be handled in its custom transition callback.
1081                         break;
1082                     }
1083                     if (preDestination->NeedRemoveInPush()) {
1084                         navigation->hideNodes_.emplace_back(std::make_pair(preDestination, true));
1085                         break;
1086                     }
1087                     preDestination->SystemTransitionPushFinish(false, preAnimationId);
1088                     preDestination->GetRenderContext()->SetOpacity(1.0f);
1089                 }
1090                 break;
1091             }
1092             auto curNode = weakCurNode.Upgrade();
1093             if (curNode) {
1094                 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1095                 CHECK_NULL_VOID(curNavDestination);
1096                 if (!curUseCustomTransition) {
1097                     navigation->ResetTransitionAnimationNodeState(preNode, curNode);
1098                     curNavDestination->SystemTransitionPushFinish(true, curAnimationId);
1099                 }
1100             }
1101             navigation->RemoveDialogDestination();
1102             auto id = navigation->GetTopDestination() ? navigation->GetTopDestination()->GetAccessibilityId() : -1;
1103             navigation->OnAccessibilityEvent(
1104                 AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1105             navigation->isOnAnimation_ = false;
1106             navigation->CleanPushAnimations();
1107             pattern->CheckContentNeedMeasure(navigation);
1108             CHECK_NULL_VOID(preNode);
1109             preNode->AddToOcclusionMap(false);
1110         };
1111 
1112     AnimationFinishCallback callback = [onFinishCb = std::move(onFinish), weakNavigation = WeakClaim(this)]() {
1113         auto navigation = weakNavigation.Upgrade();
1114         if (onFinishCb) {
1115             onFinishCb();
1116         }
1117         CHECK_NULL_VOID(navigation);
1118         auto pattern = navigation->GetPattern<NavigationPattern>();
1119         CHECK_NULL_VOID(pattern);
1120         pattern->OnFinishOneTransitionAnimation();
1121     };
1122     auto preNodeNew = TransitionAnimationIsValid(preNode, isNavBarOrHomeDestination, preUseCustomTransition);
1123     auto curNodeNew = TransitionAnimationIsValid(curNode, isNavBarOrHomeDestination, curUseCustomTransition);
1124     if (preNodeNew != nullptr || curNodeNew != nullptr) {
1125         TransitionUnitInfo preInfo(preNodeNew, preUseCustomTransition, preAnimationId);
1126         TransitionUnitInfo curInfo(curNodeNew, curUseCustomTransition, curAnimationId);
1127         if (SystemProperties::IsSoftPageTransition()) {
1128             CreateSoftAnimationWithPush(preInfo, curInfo, callback,
1129                 isNavBarOrHomeDestination && customHomeDestination_ == nullptr);
1130         } else {
1131             CreateAnimationWithPush(preInfo, curInfo, callback, isNavBarOrHomeDestination);
1132         }
1133     }
1134 
1135     isOnAnimation_ = true;
1136     auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1137     CHECK_NULL_VOID(curNavDestination);
1138     auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1139     std::string fromPath = "";
1140     if (AceChecker::IsPerformanceCheckEnabled()) {
1141         if (preNavDestination) {
1142         fromPath = preNavDestination->GetNavDestinationPathInfo();
1143         }
1144         int64_t startTime = GetSysTimestamp();
1145         auto pipeline = AceType::DynamicCast<NG::PipelineContext>(GetContextWithCheck());
1146         CHECK_NULL_VOID(pipeline);
1147         // After completing layout tasks at all nodes on the page, perform performance testing and management
1148         pipeline->AddAfterLayoutTask([weakNav = WeakClaim(this), weakNode = WeakPtr<FrameNode>(curNode), startTime,
1149                                          path = curNavDestination->GetNavDestinationPathInfo(), fromPath,
1150                                          moduleName = curNavDestination->GetNavDestinationModuleName()]() {
1151             auto navigation = weakNav.Upgrade();
1152             CHECK_NULL_VOID(navigation);
1153             auto curNode = weakNode.Upgrade();
1154             int64_t endTime = GetSysTimestamp();
1155             CHECK_NULL_VOID(curNode);
1156             PerformanceCheckNodeMap nodeMap;
1157             curNode->GetPerformanceCheckData(nodeMap);
1158             AceScopedPerformanceCheck::RecordPerformanceCheckData(
1159                 nodeMap, endTime - startTime, path, fromPath, moduleName, true);
1160         });
1161     }
1162 #if !defined(ACE_UNITTEST)
1163     TransparentNodeDetector::GetInstance().PostCheckNodeTransparentTask(curNode,
1164         curNavDestination->GetNavDestinationPathInfo());
1165 #endif
1166     CHECK_NULL_VOID(preNode);
1167     preNode->AddToOcclusionMap(true);
1168 }
1169 
MaskAnimation(const RefPtr<FrameNode> & node,bool isTransitionIn)1170 std::shared_ptr<AnimationUtils::Animation> NavigationGroupNode::MaskAnimation(const RefPtr<FrameNode>& node,
1171     bool isTransitionIn)
1172 {
1173     CHECK_NULL_RETURN(node, nullptr);
1174     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(node);
1175     if (navDestination && navDestination->TransitionContentInValid()) {
1176         return nullptr;
1177     }
1178     AnimationOption maskOption;
1179     maskOption.SetCurve(Curves::FRICTION);
1180     maskOption.SetDuration(MASK_DURATION);
1181     maskOption.SetFillMode(FillMode::FORWARDS);
1182     auto renderContext = node->GetRenderContext();
1183     CHECK_NULL_RETURN(renderContext, nullptr);
1184     if (isTransitionIn) {
1185         renderContext->SetActualForegroundColor(MASK_COLOR);
1186         return AnimationUtils::StartAnimation(
1187             maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
1188                 auto context = weakRender.Upgrade();
1189                 CHECK_NULL_VOID(context);
1190                 context->SetActualForegroundColor(Color::TRANSPARENT);
1191             });
1192     }
1193     renderContext->SetActualForegroundColor(Color::TRANSPARENT);
1194     return AnimationUtils::StartAnimation(
1195         maskOption, [weakRender = WeakPtr<RenderContext>(renderContext)]() {
1196             auto context = weakRender.Upgrade();
1197             CHECK_NULL_VOID(context);
1198             context->SetActualForegroundColor(MASK_COLOR);
1199         }, nullptr /* finishCallback */, nullptr /* repeatCallback */, GetContextRefPtr());
1200 }
1201 
TransitionWithReplace(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBarOrHomeDestination)1202 void NavigationGroupNode::TransitionWithReplace(
1203     const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode, bool isNavBarOrHomeDestination)
1204 {
1205     CHECK_NULL_VOID(preNode);
1206     CHECK_NULL_VOID(curNode);
1207     auto replaceAnimationId = MakeUniqueAnimationId();
1208     UpdateTransitionAnimationId(preNode, replaceAnimationId);
1209     UpdateTransitionAnimationId(curNode, replaceAnimationId);
1210     /* handle NavDestination CustomTransition, animationId of navDestination will be updated accordingly */
1211     int32_t preAnimationId = TriggerNavDestinationTransition(
1212         DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::REPLACE, false);
1213     auto preUseCustomTransition = true;
1214     if (preAnimationId == INVALID_ANIMATION_ID) {
1215         preAnimationId = replaceAnimationId;
1216         preUseCustomTransition = false;
1217     }
1218     int32_t curAnimationId = TriggerNavDestinationTransition(
1219         DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::REPLACE, true);
1220     auto curUseCustomTransition = true;
1221     if (curAnimationId == INVALID_ANIMATION_ID) {
1222         curAnimationId = replaceAnimationId;
1223         curUseCustomTransition = false;
1224     }
1225     if (preUseCustomTransition && curUseCustomTransition) {
1226         return;
1227     }
1228     std::function<void()> onFinish = [weakPreNode = WeakPtr<FrameNode>(preNode),
1229         weakNavigation = WeakClaim(this), isNavBarOrHomeDestination, preAnimationId, curAnimationId,
1230         weakCurNode = WeakPtr<FrameNode>(curNode), preUseCustomTransition]() {
1231         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation replace animation end");
1232         ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition end");
1233         PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1234         auto preNode = weakPreNode.Upgrade();
1235         CHECK_NULL_VOID(preNode);
1236         auto navigationNode = weakNavigation.Upgrade();
1237         CHECK_NULL_VOID(navigationNode);
1238         navigationNode->isOnAnimation_ = false;
1239         auto id = navigationNode->GetTopDestination() ? navigationNode->GetTopDestination()->GetAccessibilityId() : -1;
1240         navigationNode->OnAccessibilityEvent(
1241             AccessibilityEventType::PAGE_CHANGE, id, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_INVALID);
1242         preNode->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
1243         if (!navigationNode->CheckAnimationIdValid(preNode, preAnimationId)) {
1244             return;
1245         }
1246         if (!preUseCustomTransition) {
1247             navigationNode->DealNavigationExit(preNode, isNavBarOrHomeDestination);
1248         }
1249         auto curNode = weakCurNode.Upgrade();
1250         navigationNode->ResetTransitionAnimationNodeState(preNode, curNode);
1251         auto context = navigationNode->GetContextWithCheck();
1252         CHECK_NULL_VOID(context);
1253         context->MarkNeedFlushMouseEvent();
1254     };
1255     AnimationFinishCallback callback = [onFinishCb = std::move(onFinish), weakNavigation = WeakClaim(this)]() {
1256         auto navigation = weakNavigation.Upgrade();
1257         if (onFinishCb) {
1258             onFinishCb();
1259         }
1260         CHECK_NULL_VOID(navigation);
1261         auto pattern = navigation->GetPattern<NavigationPattern>();
1262         CHECK_NULL_VOID(pattern);
1263         pattern->OnFinishOneTransitionAnimation();
1264     };
1265     AnimationOption option;
1266     option.SetCurve(replaceCurve);
1267     option.SetFillMode(FillMode::FORWARDS);
1268     option.SetDuration(DEFAULT_REPLACE_DURATION);
1269     option.SetOnFinishEvent(callback);
1270 
1271     preNode->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(false);
1272     auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1273     if (curNavDestination && curNavDestination->IsNeedContentTransition() && !curUseCustomTransition) {
1274         curNode->GetRenderContext()->UpdateOpacity(0.0f);
1275     }
1276     if (!isNavBarOrHomeDestination) {
1277         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1278         if (navDestination && !curUseCustomTransition) {
1279             navDestination->SetIsOnAnimation(true);
1280         }
1281     }
1282     auto pattern = GetPattern<NavigationPattern>();
1283     CHECK_NULL_VOID(pattern);
1284     pattern->OnStartOneTransitionAnimation();
1285     AnimationUtils::Animate(
1286         option,
1287         [curNode, curUseCustomTransition]() {
1288             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation replace animation start");
1289             ACE_SCOPED_TRACE_COMMERCIAL("Navigation page replace transition start");
1290             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1291             auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1292             if (curNavDestination && curNavDestination->IsNeedContentTransition() && !curUseCustomTransition) {
1293                 curNode->GetRenderContext()->UpdateOpacity(1.0f);
1294             }
1295         },
1296         option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
1297     isOnAnimation_ = true;
1298     ConfigureNavigationWithAnimation(preNode, curNode);
1299 }
1300 
OnInspectorIdUpdate(const std::string & id)1301 void NavigationGroupNode::OnInspectorIdUpdate(const std::string& id)
1302 {
1303     auto context = GetContextWithCheck();
1304     CHECK_NULL_VOID(context);
1305     context->AddOrReplaceNavigationNode(id, WeakClaim(this));
1306     curId_ = id;
1307 }
1308 
DealNavigationExit(const RefPtr<FrameNode> & preNode,bool isNavBarOrHomeDestination,bool isAnimated)1309 void NavigationGroupNode::DealNavigationExit(
1310     const RefPtr<FrameNode>& preNode, bool isNavBarOrHomeDestination, bool isAnimated)
1311 {
1312     CHECK_NULL_VOID(preNode);
1313     if (preNode->GetOrCreateEventHub<EventHub>()) {
1314         preNode->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
1315     }
1316     if (isNavBarOrHomeDestination && isAnimated) {
1317         SetNeedSetInvisible(true);
1318         return;
1319     }
1320     auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1321     CHECK_NULL_VOID(navDestinationNode);
1322     navDestinationNode->SetIsOnAnimation(false);
1323     auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
1324     CHECK_NULL_VOID(navDestinationPattern);
1325     auto navigationPattern = GetPattern<NavigationPattern>();
1326     CHECK_NULL_VOID(navigationPattern);
1327     auto stack = navigationPattern->GetNavigationStack();
1328     bool isInStack = stack->FindIndex(navDestinationPattern->GetName(),
1329         navDestinationPattern->GetCustomNode(), true) != -1;
1330     if (isInStack) {
1331         RemoveDialogDestination(true);
1332         auto preContext = navDestinationNode->GetRenderContext();
1333         CHECK_NULL_VOID(preContext);
1334         preContext->UpdateZIndex(0);
1335         return;
1336     }
1337     if (!isNavBarOrHomeDestination) {
1338         navDestinationNode->CleanContent();
1339         auto parent = AceType::DynamicCast<FrameNode>(preNode->GetParent());
1340         CHECK_NULL_VOID(parent);
1341         parent->RemoveChild(preNode);
1342         RemoveDialogDestination(true);
1343         parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1344     }
1345 }
1346 
NotifyPageHide()1347 void NavigationGroupNode::NotifyPageHide()
1348 {
1349     auto context = GetContextWithCheck();
1350     CHECK_NULL_VOID(context);
1351     auto stageManager = context->GetStageManager();
1352     CHECK_NULL_VOID(stageManager);
1353     auto container = Container::Current();
1354     CHECK_NULL_VOID(container);
1355     auto pageUrlChecker = container->GetPageUrlChecker();
1356     CHECK_NULL_VOID(pageUrlChecker);
1357     RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1358     CHECK_NULL_VOID(pageNode);
1359     auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
1360     CHECK_NULL_VOID(pagePattern);
1361     auto pageInfo = pagePattern->GetPageInfo();
1362     CHECK_NULL_VOID(pageInfo);
1363     pageUrlChecker->NotifyPageHide(pageInfo->GetPageUrl());
1364 }
1365 
UpdateLastStandardIndex()1366 void NavigationGroupNode::UpdateLastStandardIndex()
1367 {
1368     // remove the impact of last standard index
1369     lastStandardIndex_ = -1;
1370     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1371     CHECK_NULL_VOID(navigationPattern);
1372     auto navigationStack = navigationPattern->GetNavigationStack();
1373     CHECK_NULL_VOID(navigationStack);
1374     const auto& navDestinationNodes = navigationStack->GetAllNavDestinationNodes();
1375     if (navDestinationNodes.size() == 0) {
1376         return;
1377     }
1378     for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1; index >= 0; index--) {
1379         const auto& curPath = navDestinationNodes[index];
1380         const auto& uiNode = curPath.second;
1381         if (!uiNode) {
1382             continue;
1383         }
1384         auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(GetNavDestinationNode(uiNode));
1385         if (navDestinationNode && navDestinationNode->GetNavDestinationMode() == NavDestinationMode::STANDARD) {
1386             lastStandardIndex_ = index;
1387             return;
1388         }
1389     }
1390 }
1391 
UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode> & navDestination,const RefPtr<UINode> & remainChild,int32_t index,size_t destinationSize,const RefPtr<UINode> & preLastStandardNode)1392 bool NavigationGroupNode::UpdateNavDestinationVisibility(const RefPtr<NavDestinationGroupNode>& navDestination,
1393     const RefPtr<UINode>& remainChild, int32_t index, size_t destinationSize, const RefPtr<UINode>& preLastStandardNode)
1394 {
1395     auto navigationPattern = GetPattern<NavigationPattern>();
1396     CHECK_NULL_RETURN(navigationPattern, false);
1397     CHECK_NULL_RETURN(navDestination, false);
1398     auto eventHub = navDestination->GetOrCreateEventHub<NavDestinationEventHub>();
1399     CHECK_NULL_RETURN(eventHub, false);
1400     if (index == static_cast<int32_t>(destinationSize) - 1) {
1401         // process shallow builder
1402         navDestination->ProcessShallowBuilder();
1403         navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE, true);
1404         navDestination->SetJSViewActive(true);
1405         navDestination->GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
1406         // for the navDestination at the top, FireChangeEvent
1407         eventHub->FireChangeEvent(true);
1408         bool hasChanged = CheckNeedMeasure(navDestination->GetLayoutProperty()->GetPropertyChangeFlag());
1409         if (!hasChanged && NavigationLayoutAlgorithm::IsAutoHeight(GetLayoutProperty<NavigationLayoutProperty>())) {
1410             hasChanged = true;
1411         }
1412         return hasChanged;
1413     }
1414     if (navigationPattern->IsPrimaryNode(navDestination)) {
1415         return false;
1416     }
1417     if (index < lastStandardIndex_) {
1418         auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1419         if (navDestination->IsOnAnimation()) {
1420             return false;
1421         }
1422         if (!pattern || !pattern->GetIsOnShow()) {
1423             // push more than one standard navDestination, need to set invisible below newTopDestination
1424             auto navDestinationLayoutProperty = navDestination->GetLayoutProperty();
1425             CHECK_NULL_RETURN(navDestinationLayoutProperty, false);
1426             navDestinationLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1427             navDestination->SetJSViewActive(false);
1428             return false;
1429         }
1430         eventHub->FireChangeEvent(false);
1431         if (pattern->GetCustomNode() != remainChild) {
1432             if (navDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG ||
1433                 navDestination == AceType::DynamicCast<NavDestinationGroupNode>(preLastStandardNode)) {
1434                 hideNodes_.insert(hideNodes_.begin(), std::pair(navDestination, false));
1435             } else {
1436                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1437                 auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1438                 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1439                 pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1440             }
1441         }
1442         return false;
1443     }
1444     auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1445     if (navDestination->GetPattern<NavDestinationPattern>()->GetCustomNode() != remainChild) {
1446         // if curNode is visible, need remove in hideNodes_.
1447         hideNodes_.erase(
1448             std::remove_if(hideNodes_.begin(), hideNodes_.end(),
1449                 [navDestination](const auto& pair) { return navDestination == pair.first && !pair.second; }),
1450             hideNodes_.end());
1451         navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
1452         navDestination->SetJSViewActive(true);
1453     }
1454     return false;
1455 }
1456 
GetNavigationMode()1457 NavigationMode NavigationGroupNode::GetNavigationMode()
1458 {
1459     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1460     CHECK_NULL_RETURN(navigationPattern, NavigationMode::AUTO);
1461     return navigationPattern->GetNavigationMode();
1462 }
1463 
OnDetachFromMainTree(bool recursive,PipelineContext * context)1464 void NavigationGroupNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
1465 {
1466     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1467     if (pattern) {
1468         pattern->DetachNavigationStackFromParent();
1469         pattern->RemoveFromDumpManager();
1470     }
1471     GroupNode::OnDetachFromMainTree(recursive, context);
1472     CHECK_NULL_VOID(context);
1473     auto navigationManager = context->GetNavigationManager();
1474     if (navigationManager) {
1475         navigationManager->RemoveNavigation(GetId());
1476     }
1477 }
1478 
FindNavigationParent(const std::string & parentName)1479 bool NavigationGroupNode::FindNavigationParent(const std::string& parentName)
1480 {
1481     auto parent = GetParent();
1482     while (parent) {
1483         if (parent->GetTag() == parentName) {
1484             AddDestinationNode(parent);
1485             return true;
1486         }
1487         parent = parent->GetParent();
1488     }
1489     return parent != nullptr;
1490 }
1491 
AddDestinationNode(const RefPtr<UINode> & parent)1492 void NavigationGroupNode::AddDestinationNode(const RefPtr<UINode>& parent)
1493 {
1494     auto destinationNode = AceType::DynamicCast<NavDestinationGroupNode>(parent);
1495     if (destinationNode) {
1496         parentDestinationNode_ = destinationNode;
1497     }
1498 }
1499 
OnAttachToMainTree(bool recursive)1500 void NavigationGroupNode::OnAttachToMainTree(bool recursive)
1501 {
1502     GroupNode::OnAttachToMainTree(recursive);
1503 
1504     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1505     if (pattern) {
1506         pattern->AttachNavigationStackToParent();
1507         pattern->AddToDumpManager();
1508     }
1509     RefPtr<UINode> parentCustomNode;
1510     bool findParentNode = false;
1511     auto curNode = GetParent();
1512     while (curNode) {
1513         auto curTag = curNode->GetTag();
1514         // check parentCustomNode is nullptr, to avoid parentCustomNode re-assignment
1515         if (!parentCustomNode && curTag == V2::JS_VIEW_ETS_TAG) {
1516             parentCustomNode = curNode;
1517         }
1518         if (!findParentNode) {
1519             findParentNode = CheckNeedUpdateParentNode(curNode);
1520         }
1521         if (parentCustomNode && findParentNode) {
1522             break;
1523         }
1524         curNode = curNode->GetParent();
1525     }
1526     if (parentCustomNode) {
1527         pattern->SetParentCustomNode(parentCustomNode);
1528     } else {
1529         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "parent custom node is nullptr");
1530     }
1531     if (!findParentNode) {
1532         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "current navigation has no parent page");
1533     }
1534     CreateHomeDestinationIfNeeded();
1535     auto pipelineContext = GetContextWithCheck();
1536     CHECK_NULL_VOID(pipelineContext);
1537     bool findNavdestination = FindNavigationParent(V2::NAVDESTINATION_VIEW_ETS_TAG);
1538     auto stageManager = pipelineContext->GetStageManager();
1539     CHECK_NULL_VOID(stageManager);
1540     RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
1541     CHECK_NULL_VOID(pageNode);
1542     auto pagePattern = pageNode->GetPattern<PagePattern>();
1543     CHECK_NULL_VOID(pagePattern);
1544     CHECK_NULL_VOID(pagePattern->GetPageInfo());
1545     int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
1546     if (!findNavdestination) {
1547         pipelineContext->AddNavigationNode(pageId, WeakClaim(this));
1548     }
1549 }
1550 
CheckNeedUpdateParentNode(const RefPtr<UINode> & curNode)1551 bool NavigationGroupNode::CheckNeedUpdateParentNode(const RefPtr<UINode>& curNode)
1552 {
1553     // only the first time need to be assigned
1554     CHECK_NULL_RETURN(curNode, false);
1555     bool isFindParent = false;
1556     auto curTag = curNode->GetTag();
1557     RefPtr<UINode> parentNode;
1558     do {
1559         if (curTag == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1560             auto curParent = curNode->GetParent();
1561             // check whether current destination is redirected throut transition
1562             if (curParent && curParent->GetTag() == V2::NAVIGATION_CONTENT_ETS_TAG) {
1563                 parentNode = curNode;
1564                 isFindParent = true;
1565             }
1566             break;
1567         }
1568         if (curTag == V2::PAGE_ETS_TAG || curTag == V2::MODAL_PAGE_TAG ||
1569             curTag == V2::SHEET_PAGE_TAG) {
1570             // check current navigation is in modal page, sheet page and page,
1571             // dialog and overlay is not need recorded
1572             parentNode = curNode;
1573             isFindParent = true;
1574             break;
1575         }
1576         if (curTag == V2::NAVBAR_ETS_TAG) {
1577             // if navigation is under navBar node. don't need to record relationShip
1578             isFindParent = true;
1579         }
1580     } while (0);
1581     if (!isFindParent || !parentNode) {
1582         return isFindParent;
1583     }
1584     auto pipelineContext = GetContextRefPtr();
1585     CHECK_NULL_RETURN(pipelineContext, true);
1586     auto navigationManager = pipelineContext->GetNavigationManager();
1587     CHECK_NULL_RETURN(navigationManager, true);
1588     // update navigation manager map <parentId, std::vector<navigationId>>
1589     navigationManager->AddNavigation(parentNode->GetId(), DynamicCast<FrameNode>(Claim(this)));
1590     return true;
1591 }
1592 
FireHideNodeChange(NavDestinationLifecycle lifecycle)1593 void NavigationGroupNode::FireHideNodeChange(NavDestinationLifecycle lifecycle)
1594 {
1595     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1596     for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); ++iter) {
1597         auto navDestination = iter->first;
1598         if (!navDestination) {
1599             continue;
1600         }
1601         if (lifecycle == NavDestinationLifecycle::ON_WILL_DISAPPEAR) {
1602             if (iter->second) {
1603                 navigationPattern->NotifyDestinationLifecycle(
1604                     navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1605             }
1606             continue;
1607         }
1608         auto pattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1609         if (!pattern->GetIsOnShow()) {
1610             continue;
1611         }
1612         if (lifecycle == NavDestinationLifecycle::ON_WILL_HIDE) {
1613             navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1614             continue;
1615         }
1616         if (lifecycle == NavDestinationLifecycle::ON_HIDE) {
1617             navigationPattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1618         }
1619     }
1620 }
1621 
RemoveDialogDestination(bool isReplace,bool isTriggerByInteractiveCancel)1622 void NavigationGroupNode::RemoveDialogDestination(bool isReplace, bool isTriggerByInteractiveCancel)
1623 {
1624     for (auto iter = hideNodes_.begin(); iter != hideNodes_.end(); iter++) {
1625         auto navDestination = iter->first;
1626         if (!navDestination) {
1627             continue;
1628         }
1629         if (!iter->second) {
1630             auto type = navDestination->GetTransitionType();
1631             bool isEnterPage = (type == PageTransitionType::ENTER_PUSH || type == PageTransitionType::ENTER_POP);
1632             if (!isTriggerByInteractiveCancel && isEnterPage) {
1633                 // if tigger by interactive animation, The transition type is incorrect, ignore this case.
1634                 continue;
1635             }
1636             // navDestination node don't need to remove, update visibility invisible
1637             navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1638             navDestination->SetJSViewActive(false);
1639             if (!isReplace) {
1640                 continue;
1641             }
1642             auto context = navDestination->GetRenderContext();
1643             if (!context) {
1644                 continue;
1645             }
1646             context->UpdateZIndex(0);
1647             continue;
1648         }
1649         auto parent = navDestination->GetParent();
1650         if (!parent) {
1651             continue;
1652         }
1653         auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestination->GetPattern());
1654         if (!navDestinationPattern) {
1655             continue;
1656         }
1657         navDestination->CleanContent();
1658         parent->RemoveChild(navDestination);
1659         parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1660     }
1661     hideNodes_.clear();
1662 }
1663 
DealRemoveDestination(const RefPtr<NavDestinationGroupNode> & navDestination)1664 void NavigationGroupNode::DealRemoveDestination(const RefPtr<NavDestinationGroupNode>& navDestination)
1665 {
1666     // remove content child
1667     auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
1668     auto pattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1669     if (navDestination->GetNavDestinationType() == NavDestinationType::PROXY) {
1670         contentNode_->RemoveChild(navDestination, true);
1671         auto primaryNode = navDestination->GetPrimaryNode();
1672         CHECK_NULL_VOID(primaryNode);
1673         primaryNodesToBeRemoved_.push_back(primaryNode);
1674         return;
1675     }
1676 
1677     if (navDestinationPattern->GetIsOnShow()) {
1678         pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_HIDE);
1679         pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_HIDE);
1680         navDestinationPattern->SetIsOnShow(false);
1681     }
1682     pattern->NotifyDestinationLifecycle(navDestination, NavDestinationLifecycle::ON_WILL_DISAPPEAR);
1683     navDestination->CleanContent();
1684     contentNode_->RemoveChild(navDestination, true);
1685 }
1686 
CreateAnimationWithDialogPop(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> preNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1687 void NavigationGroupNode::CreateAnimationWithDialogPop(const AnimationFinishCallback callback,
1688     const std::vector<WeakPtr<FrameNode>> preNavList,
1689     const std::vector<WeakPtr<FrameNode>> curNavList)
1690 {
1691     auto navigationPattern = GetPattern<NavigationPattern>();
1692     CHECK_NULL_VOID(navigationPattern);
1693     // start transition animation
1694     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1695         callback);
1696     navigationPattern->OnStartOneTransitionAnimation();
1697     auto newPopAnimation = AnimationUtils::StartAnimation(option, [
1698        weakNavigation = WeakClaim(this), curNavList, preNavList]() {
1699             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1700             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation start");
1701 
1702             // do preNode transition
1703             auto navigation = weakNavigation.Upgrade();
1704             CHECK_NULL_VOID(navigation);
1705             for (auto iter: preNavList) {
1706                 auto preNode = iter.Upgrade();
1707                 CHECK_NULL_VOID(preNode);
1708                 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1709                 if (preNavDesNode) {
1710                     preNavDesNode->SystemTransitionPopEnd(false);
1711                 }
1712             }
1713 
1714             // do currentNode transition
1715             for (auto iter: curNavList) {
1716                 auto curNode = iter.Upgrade();
1717                 CHECK_NULL_VOID(curNode);
1718                 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
1719                 CHECK_NULL_VOID(nodeBase);
1720                 nodeBase->SystemTransitionPopEnd(true);
1721             }
1722         },
1723         option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
1724     if (newPopAnimation) {
1725         popAnimations_.emplace_back(newPopAnimation);
1726     }
1727     isOnAnimation_ = true;
1728 }
1729 
TransitionWithDialogPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1730 void NavigationGroupNode::TransitionWithDialogPop(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1731     bool isNavBar)
1732 {
1733     auto navigationPattern = GetPattern<NavigationPattern>();
1734     CHECK_NULL_VOID(navigationPattern);
1735     CHECK_NULL_VOID(preNode);
1736     std::vector<WeakPtr<FrameNode>> curNavList;
1737     bool isNavbarNeedAnimation = lastStandardIndex_ == -1 || isNavBar;
1738     InitPopCurList(curNode, curNavList, isNavbarNeedAnimation);
1739     std::vector<WeakPtr<FrameNode>> preNavList;
1740     InitPopPreList(preNode, preNavList, curNavList);
1741 
1742     /* create animation finish callback */
1743     CleanPopAnimations();
1744     std::function<void()> onFinish = [preNavList, weakNavigation = WeakClaim(this), weakCurNode = WeakPtr(curNode)] {
1745             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog pop animation end TransitionWithDialogPop");
1746             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1747             auto navigation = weakNavigation.Upgrade();
1748             CHECK_NULL_VOID(navigation);
1749             navigation->isOnAnimation_ = false;
1750             navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1751             navigation->CleanPopAnimations();
1752             for (auto iter = preNavList.rbegin(); iter != preNavList.rend(); ++iter) {
1753                 auto preNode = (*iter).Upgrade();
1754                 if (!preNode) {
1755                     continue;
1756                 }
1757                 auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1758                 CHECK_NULL_VOID(preNavDesNode);
1759                 auto pattern = navigation->GetPattern<NavigationPattern>();
1760                 CHECK_NULL_VOID(pattern);
1761                 bool isIncurStack = pattern->FindInCurStack(preNode);
1762                 if (preNavDesNode->SystemTransitionPopFinish(preNavDesNode->GetAnimationId(), !isIncurStack)) {
1763                     auto parent = preNavDesNode->GetParent();
1764                     CHECK_NULL_VOID(parent);
1765                     if (!isIncurStack) {
1766                         parent->RemoveChild(preNavDesNode);
1767                     }
1768                 }
1769                 navigation->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1770             }
1771             navigation->RemoveDialogDestination();
1772             auto context = navigation->GetContextWithCheck();
1773             CHECK_NULL_VOID(context);
1774             context->MarkNeedFlushMouseEvent();
1775         };
1776     AnimationFinishCallback callback = [onFinishCb = std::move(onFinish), weak = WeakPtr(navigationPattern)]() {
1777         auto pattern = weak.Upgrade();
1778         if (onFinishCb) {
1779             onFinishCb();
1780         }
1781         CHECK_NULL_VOID(pattern);
1782         pattern->OnFinishOneTransitionAnimation();
1783     };
1784     CreateAnimationWithDialogPop(callback, preNavList, curNavList);
1785 }
1786 
CreateAnimationWithDialogPush(const AnimationFinishCallback callback,const std::vector<WeakPtr<FrameNode>> prevNavList,const std::vector<WeakPtr<FrameNode>> curNavList)1787 void NavigationGroupNode::CreateAnimationWithDialogPush(const AnimationFinishCallback callback,
1788     const std::vector<WeakPtr<FrameNode>> prevNavList, const std::vector<WeakPtr<FrameNode>> curNavList)
1789 {
1790     auto navigationPattern = GetPattern<NavigationPattern>();
1791     CHECK_NULL_VOID(navigationPattern);
1792     // start transition animation
1793     AnimationOption option = CreateAnimationOption(springCurve, FillMode::FORWARDS, DEFAULT_ANIMATION_DURATION,
1794         callback);
1795     navigationPattern->OnStartOneTransitionAnimation();
1796     auto newPushAnimation = AnimationUtils::StartAnimation(option,
1797         [weakNavigation = WeakClaim(this), prevNavList, curNavList]() {
1798             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1799             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
1800             auto navigation = weakNavigation.Upgrade();
1801             CHECK_NULL_VOID(navigation);
1802 
1803             // preNode do EXIT PUSH animation
1804             for (auto iter : prevNavList) {
1805                 auto preNode = iter.Upgrade();
1806                 CHECK_NULL_VOID(preNode);
1807                 if (navigation->IsNavBarOrHomeDestination(preNode) &&
1808                     navigation->GetNavigationMode() == NavigationMode::STACK) {
1809                     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(preNode);
1810                     CHECK_NULL_VOID(nodeBase);
1811                     nodeBase->SystemTransitionPushEnd(false);
1812                 } else {
1813                     auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1814                     CHECK_NULL_VOID(preDestination);
1815                     preDestination->SystemTransitionPushEnd(false);
1816                 }
1817             }
1818             // curNode do ENTER PUSH animation
1819             for (auto iter : curNavList) {
1820                 auto curNode = iter.Upgrade();
1821                 CHECK_NULL_VOID(curNode);
1822                 auto curDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1823                 if (curDestination) {
1824                     curDestination->SystemTransitionPushEnd(true);
1825                 }
1826             }
1827         },
1828         option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
1829     if (newPushAnimation) {
1830         pushAnimations_.emplace_back(newPushAnimation);
1831     }
1832     isOnAnimation_ = true;
1833 }
1834 
PreNodeFinishCallback(const RefPtr<FrameNode> & preNode)1835 void NavigationGroupNode::PreNodeFinishCallback(const RefPtr<FrameNode>& preNode)
1836 {
1837     CHECK_NULL_VOID(preNode);
1838     if (IsNavBarOrHomeDestination(preNode)) {
1839         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(preNode);
1840         CHECK_NULL_VOID(nodeBase);
1841         nodeBase->SystemTransitionPushFinish(false);
1842         bool needSetInvisible = nodeBase->GetTransitionType() == PageTransitionType::EXIT_PUSH;
1843         SetNeedSetInvisible(needSetInvisible);
1844         if (needSetInvisible && GetNavigationMode() == NavigationMode::STACK) {
1845             auto property = nodeBase->GetLayoutProperty();
1846             CHECK_NULL_VOID(property);
1847             property->UpdateVisibility(VisibleType::INVISIBLE);
1848             nodeBase->SetJSViewActive(false);
1849             NotifyPageHide();
1850         }
1851         return;
1852     }
1853     if (preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1854         auto preDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1855         if (preDestination && preDestination->NeedRemoveInPush()) {
1856             hideNodes_.emplace_back(std::make_pair(preDestination, true));
1857         }
1858         preDestination->SystemTransitionPushFinish(false, preDestination->GetAnimationId());
1859     }
1860 }
1861 
TransitionWithDialogPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar)1862 void NavigationGroupNode::TransitionWithDialogPush(const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode,
1863     bool isNavBar)
1864 {
1865     if (!preNode || !curNode) {
1866         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "dialog push animation terminated");
1867         return;
1868     }
1869 
1870     auto navigationPattern = GetPattern<NavigationPattern>();
1871     CHECK_NULL_VOID(navigationPattern);
1872     CleanPushAnimations();
1873 
1874     // initialization
1875     bool isNavbarNeedAnimation = preLastStandardIndex_ == -1 || isNavBar;
1876     std::vector<WeakPtr<FrameNode>> curNavList;
1877     InitPushCurList(curNode, curNavList);
1878     std::vector<WeakPtr<FrameNode>> prevNavList;
1879     InitPushPreList(preNode, prevNavList, curNavList, isNavbarNeedAnimation);
1880 
1881     std::function<void()> onFinish =
1882         [weakNavigation = WeakClaim(this), prevNavList, curNavList, weakCurNode = WeakPtr(curNode)] {
1883             PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1884             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1885             auto navigation = weakNavigation.Upgrade();
1886             CHECK_NULL_VOID(navigation);
1887             for (auto iter : prevNavList) {
1888                 auto preNode = iter.Upgrade();
1889                 if (!preNode) {
1890                     continue;
1891                 }
1892                 navigation->PreNodeFinishCallback(preNode);
1893             }
1894             for (auto iter : curNavList) {
1895                 auto curNode = iter.Upgrade();
1896                 if (!curNode) {
1897                     continue;
1898                 }
1899                 auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1900                 CHECK_NULL_VOID(curNavDestination);
1901                 curNavDestination->SystemTransitionPushFinish(true, curNavDestination->GetAnimationId());
1902             }
1903             navigation->RemoveDialogDestination();
1904             navigation->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1905             navigation->isOnAnimation_ = false;
1906             navigation->CleanPushAnimations();
1907         };
1908     AnimationFinishCallback callback = [onFinishCb = std::move(onFinish), weak = WeakPtr(navigationPattern)]() {
1909         auto pattern = weak.Upgrade();
1910         if (onFinishCb) {
1911             onFinishCb();
1912         }
1913         CHECK_NULL_VOID(pattern);
1914         pattern->OnFinishOneTransitionAnimation();
1915     };
1916     if (preNode) {
1917         auto renderContext = preNode->GetRenderContext();
1918         CHECK_NULL_VOID(renderContext);
1919         renderContext->RemoveClipWithRRect();
1920     }
1921     CreateAnimationWithDialogPush(callback, prevNavList, curNavList);
1922 }
1923 
StartDialogtransition(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isTransitionIn)1924 void NavigationGroupNode::StartDialogtransition(const RefPtr<FrameNode>& preNode,
1925     const RefPtr<FrameNode>& curNode, bool isTransitionIn)
1926 {
1927     AnimationOption option;
1928     const RefPtr<InterpolatingSpring> curve =
1929         AceType::MakeRefPtr<InterpolatingSpring>(0.0f, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
1930     const float defaultAmplitudePx = 0.005f;
1931     curve->UpdateMinimumAmplitudeRatio(defaultAmplitudePx);
1932     option.SetCurve(curve);
1933     option.SetFillMode(FillMode::FORWARDS);
1934     if (isTransitionIn) {
1935         DialogTransitionPushAnimation(preNode, curNode, option);
1936         TriggerNavDestinationTransition(
1937             DynamicCast<NavDestinationGroupNode>(preNode), NavigationOperation::PUSH, false);
1938     } else {
1939         DialogTransitionPopAnimation(preNode, curNode, option);
1940         TriggerNavDestinationTransition(
1941             DynamicCast<NavDestinationGroupNode>(curNode), NavigationOperation::POP, true);
1942     }
1943 }
1944 
DialogTransitionPushAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)1945 void NavigationGroupNode::DialogTransitionPushAnimation(const RefPtr<FrameNode>& preNode,
1946     const RefPtr<FrameNode>& curNode, AnimationOption option)
1947 {
1948     CHECK_NULL_VOID(curNode);
1949     auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1950     CHECK_NULL_VOID(curNavdestination);
1951     int32_t end = curNavdestination->GetIndex();
1952     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
1953     CHECK_NULL_VOID(navigationPattern);
1954     const auto& navDestinationNodesCur = navigationPattern->GetAllNavDestinationNodes();
1955     int32_t start = 0;
1956     if (preNode && preNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
1957         auto navdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
1958         CHECK_NULL_VOID(navdestination);
1959         start = navdestination->GetIndex() + 1;
1960         auto renderContext = preNode->GetRenderContext();
1961         CHECK_NULL_VOID(renderContext);
1962         renderContext->RemoveClipWithRRect();
1963     }
1964     // find the nodes need to do upward ENTER translation
1965     std::vector<WeakPtr<NavDestinationGroupNode>> curNavList;
1966     for (int32_t index = start; index <= end; index++) {
1967         auto navdestination = GetNavDestinationNode(navDestinationNodesCur[index].second);
1968         CHECK_NULL_VOID(navdestination);
1969         auto curNode = AceType::DynamicCast<FrameNode>(navdestination);
1970         CHECK_NULL_VOID(curNode);
1971         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1972         CHECK_NULL_VOID(navDestination);
1973         if (TriggerNavDestinationTransition(navDestination, NavigationOperation::PUSH, true) == INVALID_ANIMATION_ID) {
1974             navDestination->InitDialogTransition(false);
1975             curNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(navDestination));
1976         }
1977     }
1978     CleanPushAnimations();
1979     std::function<void()> onFinish = [weakNavigation = WeakClaim(this), weakCurNode = WeakPtr<FrameNode>(curNode),
1980                                       weakPreNode = WeakPtr<FrameNode>(preNode)] {
1981         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation end");
1982         auto navigation = weakNavigation.Upgrade();
1983         CHECK_NULL_VOID(navigation);
1984         auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(weakPreNode.Upgrade());
1985         if (preNavDestination && preNavDestination->NeedRemoveInPush()) {
1986             navigation->hideNodes_.emplace_back(std::make_pair(preNavDestination, true));
1987         }
1988         navigation->RemoveDialogDestination();
1989         navigation->CleanPushAnimations();
1990         auto curNode = weakCurNode.Upgrade();
1991         auto preNode = weakPreNode.Upgrade();
1992         navigation->ResetTransitionAnimationNodeState(preNode, curNode);
1993     };
1994     auto finishWrapper = [onFinishCb = std::move(onFinish), weak = WeakPtr(navigationPattern)]() {
1995         auto pattern = weak.Upgrade();
1996         if (onFinishCb) {
1997             onFinishCb();
1998         }
1999         CHECK_NULL_VOID(pattern);
2000         pattern->OnFinishOneTransitionAnimation();
2001     };
2002     option.SetOnFinishEvent(finishWrapper);
2003     navigationPattern->OnStartOneTransitionAnimation();
2004     auto newPushAnimation = AnimationUtils::StartAnimation(option,
2005         [curNavList]() {
2006             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "navigation dialog push animation start");
2007             for (auto iter: curNavList) {
2008                 auto curNode = iter.Upgrade();
2009                 if (curNode) {
2010                     curNode->InitDialogTransition(true);
2011                 }
2012             }
2013         },
2014         option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
2015     if (newPushAnimation) {
2016         pushAnimations_.emplace_back(newPushAnimation);
2017     }
2018     ConfigureNavigationWithAnimation(preNode, curNode);
2019 }
2020 
FindNodesPoped(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode)2021 std::vector<WeakPtr<NavDestinationGroupNode>> NavigationGroupNode::FindNodesPoped(
2022     const RefPtr<FrameNode>& preNode, const RefPtr<FrameNode>& curNode)
2023 {
2024     std::vector<WeakPtr<NavDestinationGroupNode>> preNavList;
2025     auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2026     CHECK_NULL_RETURN(preNavdestinationNode, preNavList);
2027     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2028     CHECK_NULL_RETURN(navigationPattern, preNavList);
2029     const auto& navDestinationNodesPre = navigationPattern->GetAllNavDestinationNodesPrev();
2030     int32_t start = 0;
2031     if (curNode && curNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
2032         auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2033         CHECK_NULL_RETURN(curNavdestination, preNavList);
2034         start = preLastStandardIndex_ + 1;
2035     }
2036     // find the nodes need to do downward EXIT translation
2037     auto stack = navigationPattern->GetNavigationStack();
2038     int32_t size = static_cast<int32_t>(navDestinationNodesPre.size());
2039     for (int32_t index = start; index < size; index++) {
2040         auto node = GetNavDestinationNode(navDestinationNodesPre[index].second.Upgrade());
2041         if (!node) {
2042             continue;
2043         }
2044         auto preNode = AceType::DynamicCast<FrameNode>(node);
2045         CHECK_NULL_RETURN(preNode, preNavList);
2046         auto preNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2047         CHECK_NULL_RETURN(preNavDesNode, preNavList);
2048         bool isInCurStack = stack->FindIndex(navDestinationNodesPre[index].first,
2049             navDestinationNodesPre[index].second.Upgrade(), true) != -1;
2050         if (!isInCurStack) {
2051             // this node not in current stack should do animation.
2052             if (TriggerNavDestinationTransition(preNavDesNode, NavigationOperation::POP, false)
2053                 == INVALID_ANIMATION_ID) {
2054                 // has no custom transition or system transition, so do default animation.
2055                 preNavDesNode->InitDialogTransition(true);
2056                 preNavList.emplace_back(WeakPtr<NavDestinationGroupNode>(preNavDesNode));
2057             }
2058         } else {
2059             // update visbility when this node is under the last standard page
2060             if (preNavDesNode->GetIndex() < lastStandardIndex_) {
2061                 preNavDesNode->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
2062             }
2063         }
2064     }
2065     return preNavList;
2066 }
2067 
DialogTransitionPopAnimation(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,AnimationOption option)2068 void NavigationGroupNode::DialogTransitionPopAnimation(const RefPtr<FrameNode>& preNode,
2069     const RefPtr<FrameNode>& curNode, AnimationOption option)
2070 {
2071     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2072     CHECK_NULL_VOID(navigationPattern);
2073     auto preNavList = FindNodesPoped(preNode, curNode);
2074     CleanPopAnimations();
2075     std::function<void()> onFinish =
2076         [preNavList, weakNavigation = WeakClaim(this), weakCurNode = WeakPtr<FrameNode>(curNode),
2077          weakPreNode = WeakPtr<FrameNode>(preNode)] {
2078             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "dialog transition pop animation end");
2079             auto navigation = weakNavigation.Upgrade();
2080             CHECK_NULL_VOID(navigation);
2081             auto curNode = weakCurNode.Upgrade();
2082             auto preNode = weakPreNode.Upgrade();
2083             navigation->ResetTransitionAnimationNodeState(preNode, curNode);
2084             for (auto iter: preNavList) {
2085                 auto preNode = iter.Upgrade();
2086                 CHECK_NULL_CONTINUE(preNode);
2087                 auto parent = preNode->GetParent();
2088                 CHECK_NULL_CONTINUE(parent);
2089                 auto pattern = navigation->GetPattern<NavigationPattern>();
2090                 bool isIncurStack = pattern->FindInCurStack(preNode);
2091                 if (!isIncurStack) {
2092                     parent->RemoveChild(preNode);
2093                     parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2094                 }
2095             }
2096             navigation->RemoveDialogDestination();
2097             auto context = navigation->GetContextWithCheck();
2098             CHECK_NULL_VOID(context);
2099             context->MarkNeedFlushMouseEvent();
2100             navigation->CleanPopAnimations();
2101         };
2102     auto finishWrapper = [onFinishCb = std::move(onFinish), weak = WeakPtr(navigationPattern)]() {
2103         auto pattern = weak.Upgrade();
2104         if (onFinishCb) {
2105             onFinishCb();
2106         }
2107         CHECK_NULL_VOID(pattern);
2108         pattern->OnFinishOneTransitionAnimation();
2109     };
2110     option.SetOnFinishEvent(finishWrapper);
2111 
2112     navigationPattern->OnStartOneTransitionAnimation();
2113     auto newPopAnimation = AnimationUtils::StartAnimation(
2114         option, [weakNavigation = WeakClaim(this), preNavList]() {
2115             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "dialog transition pop animation start");
2116             auto navigation = weakNavigation.Upgrade();
2117             CHECK_NULL_VOID(navigation);
2118             for (auto iter: preNavList) {
2119                 auto preNode = iter.Upgrade();
2120                 CHECK_NULL_VOID(preNode);
2121                 preNode->InitDialogTransition(false);
2122             }
2123     }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
2124     if (newPopAnimation) {
2125         popAnimations_.emplace_back(newPopAnimation);
2126     }
2127     ConfigureNavigationWithAnimation(preNode, curNode);
2128 }
2129 
InitPopPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & preNavList,const std::vector<WeakPtr<FrameNode>> & curNavList)2130 void NavigationGroupNode::InitPopPreList(const RefPtr<FrameNode>& preNode, std::vector<WeakPtr<FrameNode>>& preNavList,
2131     const std::vector<WeakPtr<FrameNode>>& curNavList)
2132 {
2133     // find all the nodes need to do EXIT_POP
2134     int32_t preStartIndex = preLastStandardIndex_;
2135     if (preStartIndex == -1) {
2136         // eg. clear + push page1
2137         preStartIndex = 0;
2138     }
2139     auto preNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2140     CHECK_NULL_VOID(preNavdestinationNode);
2141     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2142     CHECK_NULL_VOID(navigationPattern);
2143     const auto& preNavDestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
2144 
2145     // find the nodes need to do EXIT_POP
2146     for (int32_t index = preStartIndex; index < static_cast<int32_t>(preNavDestinationNodes.size()); index++) {
2147         auto node = GetNavDestinationNode(preNavDestinationNodes[index].second.Upgrade());
2148         CHECK_NULL_VOID(node);
2149         auto preNode = AceType::DynamicCast<FrameNode>(node);
2150         CHECK_NULL_VOID(preNode);
2151         // Animation nodes should not be in both the prelist and the curlist, priority of the curlist is higher.
2152         auto targetNode = std::find_if(curNavList.begin(), curNavList.end(), [=](WeakPtr<FrameNode> frameNode) {
2153             auto curListNode = frameNode.Upgrade();
2154             return curListNode == preNode;
2155         });
2156         if (targetNode != curNavList.end()) {
2157             continue;
2158         }
2159         auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2160         if (preNavDestination && TriggerNavDestinationTransition(
2161             preNavDestination, NavigationOperation::POP, false) == INVALID_ANIMATION_ID) {
2162             preNavDestination->SystemTransitionPopStart(false);
2163             preNavList.emplace_back(WeakPtr<FrameNode>(preNode));
2164         }
2165     }
2166 }
2167 
InitPopCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList,bool isNavbarNeedAnimation)2168 void NavigationGroupNode::InitPopCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList,
2169     bool isNavbarNeedAnimation)
2170 {
2171     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2172     CHECK_NULL_VOID(navigationPattern);
2173     auto curNavdestionNodes = navigationPattern->GetAllNavDestinationNodes();
2174     auto curStartIndex = lastStandardIndex_;
2175 
2176     // navBar + D or navBar should be in animation
2177     if (isNavbarNeedAnimation) {
2178         curStartIndex = 0;
2179     }
2180     // if navBar should be in animation, do initialization and visibility should be true
2181     if (isNavbarNeedAnimation && navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
2182         auto preNode = AceType::DynamicCast<NavDestinationNodeBase>(GetNavBarOrHomeDestinationNode());
2183         if (preNode) {
2184             preNode->SystemTransitionPopStart(true);
2185             curNavList.emplace_back(WeakPtr<FrameNode>(preNode));
2186             SetNeedSetInvisible(false);
2187         }
2188     }
2189     int32_t size = static_cast<int32_t>(curNavdestionNodes.size());
2190     if (size == 0) {
2191         return;
2192     }
2193     // find the nodes need to do ENTER_POP
2194     for (int32_t index = curStartIndex; index < size; index++) {
2195         auto node = GetNavDestinationNode(curNavdestionNodes[index].second);
2196         CHECK_NULL_VOID(node);
2197         auto curNode = AceType::DynamicCast<FrameNode>(node);
2198         if (curNode) {
2199             auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2200             if (navDestination && TriggerNavDestinationTransition(
2201                 navDestination, NavigationOperation::POP, true) == INVALID_ANIMATION_ID) {
2202                 navDestination->SystemTransitionPopStart(true);
2203                 curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
2204             }
2205         }
2206     }
2207 }
2208 
InitPushPreList(const RefPtr<FrameNode> & preNode,std::vector<WeakPtr<FrameNode>> & prevNavList,const std::vector<WeakPtr<FrameNode>> & curNavList,bool isNavbarNeedAnimation)2209 void NavigationGroupNode::InitPushPreList(const RefPtr<FrameNode>& preNode,
2210     std::vector<WeakPtr<FrameNode>>& prevNavList, const std::vector<WeakPtr<FrameNode>>& curNavList,
2211     bool isNavbarNeedAnimation)
2212 {
2213     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2214     CHECK_NULL_VOID(navigationPattern);
2215     auto stack = navigationPattern->GetNavigationStack();
2216     auto& preNavdestinationNodes = navigationPattern->GetAllNavDestinationNodesPrev();
2217     auto preStartIndex = preLastStandardIndex_;
2218 
2219     // find the pre last standard index, if there is no pre standard or pre node is single navbar
2220     if (isNavbarNeedAnimation) {
2221         preStartIndex = 0;
2222     }
2223     // if pre node is nav bar or one of preNodes is nav bar and only stack with navbar's animation
2224     if (isNavbarNeedAnimation&& navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
2225         auto preNode = AceType::DynamicCast<NavDestinationNodeBase>(GetNavBarOrHomeDestinationNode());
2226         if (preNode) {
2227             SetNeedSetInvisible(false);
2228             preNode->SystemTransitionPushStart(false);
2229             prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
2230         }
2231     }
2232     int32_t size = static_cast<int32_t>(preNavdestinationNodes.size());
2233     if (size == 0) {
2234         return;
2235     }
2236     // find the nodes need to do EXIT_PUSH
2237     for (int32_t index = preStartIndex; index < size; index++) {
2238         auto node = GetNavDestinationNode(preNavdestinationNodes[index].second.Upgrade());
2239         CHECK_NULL_VOID(node);
2240         auto preNode = AceType::DynamicCast<FrameNode>(node);
2241         CHECK_NULL_VOID(preNode);
2242         // Animation nodes should not be in both the prelist and the curlist, priority of the curlist is higher.
2243         auto targetNode = std::find_if(curNavList.begin(), curNavList.end(), [=](WeakPtr<FrameNode> frameNode) {
2244             auto curListNode = frameNode.Upgrade();
2245             return curListNode == preNode;
2246         });
2247         if (targetNode != curNavList.end()) {
2248             continue;
2249         }
2250         auto preNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2251         if (preNavdestination && TriggerNavDestinationTransition(
2252             preNavdestination, NavigationOperation::PUSH, false) == INVALID_ANIMATION_ID) {
2253             preNavdestination->SystemTransitionPushStart(false);
2254             prevNavList.emplace_back(WeakPtr<FrameNode>(preNode));
2255         }
2256     }
2257 }
2258 
InitPushCurList(const RefPtr<FrameNode> & curNode,std::vector<WeakPtr<FrameNode>> & curNavList)2259 void NavigationGroupNode::InitPushCurList(const RefPtr<FrameNode>& curNode, std::vector<WeakPtr<FrameNode>>& curNavList)
2260 {
2261     // find the nodes need to do ENTER_PUSH
2262     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(GetPattern());
2263     CHECK_NULL_VOID(navigationPattern);
2264     auto curNavdestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2265     CHECK_NULL_VOID(curNavdestinationNode);
2266     auto curEndIndex = curNavdestinationNode->GetIndex();
2267     auto curStartIndex = lastStandardIndex_;
2268     auto stack = navigationPattern->GetNavigationStack();
2269     for (int32_t index = curStartIndex; index <= curEndIndex; index++) {
2270         auto node = GetNavDestinationNode(stack->Get(index));
2271         CHECK_NULL_VOID(node);
2272         auto curNode = AceType::DynamicCast<FrameNode>(node);
2273         CHECK_NULL_VOID(curNode);
2274         auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2275         if (curNavDestination && TriggerNavDestinationTransition(
2276             curNavDestination, NavigationOperation::PUSH, true) == INVALID_ANIMATION_ID) {
2277             curNavDestination->SystemTransitionPushStart(true);
2278             curNavList.emplace_back(WeakPtr<FrameNode>(curNode));
2279         }
2280     }
2281 }
2282 
CreateAnimationOption(const RefPtr<Curve> & curve,FillMode mode,int32_t duration,const NavigationGroupNode::AnimationFinishCallback & callback)2283 AnimationOption NavigationGroupNode::CreateAnimationOption(const RefPtr<Curve>& curve, FillMode mode,
2284     int32_t duration, const NavigationGroupNode::AnimationFinishCallback& callback)
2285 {
2286     AnimationOption option;
2287     option.SetCurve(curve);
2288     option.SetFillMode(mode);
2289     option.SetDuration(duration);
2290     option.SetOnFinishEvent(callback);
2291     return option;
2292 }
2293 
CheckAnimationIdValid(const RefPtr<FrameNode> & curNode,const int32_t animationId)2294 bool NavigationGroupNode::CheckAnimationIdValid(const RefPtr<FrameNode>& curNode, const int32_t animationId)
2295 {
2296     auto navDestinationBaseNode = AceType::DynamicCast<NavDestinationNodeBase>(curNode);
2297     CHECK_NULL_RETURN(navDestinationBaseNode, false);
2298     auto result = navDestinationBaseNode->GetAnimationId() == animationId;
2299     if (!result) {
2300         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "animation id is invalid");
2301     }
2302     return result;
2303 }
2304 
ToDumpString()2305 std::string NavigationGroupNode::ToDumpString()
2306 {
2307     std::string dumpString;
2308     auto navigationPattern = GetPattern<NavigationPattern>();
2309     CHECK_NULL_RETURN(navigationPattern, dumpString);
2310     auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
2311     CHECK_NULL_RETURN(navigationLayoutProperty, dumpString);
2312     NavigationMode usrSetMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
2313     NavigationMode actualMode = navigationPattern->GetNavigationMode();
2314     std::string mode;
2315     switch (usrSetMode) {
2316         case NavigationMode::STACK:
2317             mode = "STACK";
2318             break;
2319         case NavigationMode::SPLIT:
2320             mode = "SPLIT";
2321             break;
2322         case NavigationMode::AUTO:
2323             mode = (actualMode == NavigationMode::STACK) ? "AUTO(STACK)" : "AUTO(SPLIT)";
2324             break;
2325         default:
2326             mode = "INVALID";
2327             break;
2328     }
2329     dumpString.append("|-> Navigation ID: ");
2330     dumpString.append(std::to_string(GetId()));
2331     dumpString.append(", Depth: ");
2332     dumpString.append(std::to_string(GetDepth()));
2333     dumpString.append(", Mode: \"");
2334     dumpString.append(mode);
2335     dumpString.append("\", NavDestinations:");
2336     return dumpString;
2337 }
2338 
ResetSystemAnimationProperties(const RefPtr<FrameNode> & navDestinationNode)2339 void NavigationGroupNode::ResetSystemAnimationProperties(const RefPtr<FrameNode>& navDestinationNode)
2340 {
2341     auto navDestination = DynamicCast<NavDestinationGroupNode>(navDestinationNode);
2342     CHECK_NULL_VOID(navDestination);
2343     auto renderContext = navDestination->GetRenderContext();
2344     CHECK_NULL_VOID(renderContext);
2345     // update navDestination's translateXY
2346     renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
2347     auto titleBarNode = AceType::DynamicCast<FrameNode>(navDestination->GetTitleBarNode());
2348     CHECK_NULL_VOID(titleBarNode);
2349     auto titleBarRenderContext = titleBarNode->GetRenderContext();
2350     CHECK_NULL_VOID(titleBarRenderContext);
2351     // update titleBar's translateXY
2352     titleBarRenderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
2353 }
2354 
StartSoftOpacityAnimationPush(const RefPtr<FrameNode> & curNode)2355 void NavigationGroupNode::StartSoftOpacityAnimationPush(const RefPtr<FrameNode>& curNode)
2356 {
2357     CHECK_NULL_VOID(curNode);
2358     AnimationOption opacityAnimationOption =
2359         CreateAnimationOption(Curves::SMOOTH, FillMode::FORWARDS, SOFT_PUSH_ANIMATION_OPACITY_DURATION, nullptr);
2360     opacityAnimationOption.SetDelay(SOFT_ANIMATION_OPACITY_DELAY);
2361     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2362     CHECK_NULL_VOID(navDestination);
2363     auto titleBarNode = AceType::DynamicCast<FrameNode>(navDestination->GetTitleBarNode());
2364     if (navDestination->IsNeedContentTransition()) {
2365         curNode->GetRenderContext()->OpacityAnimation(opacityAnimationOption, 0.0f, 1.0f);
2366     } else if (titleBarNode && navDestination->IsNeedTitleTransition()) {
2367         titleBarNode->GetRenderContext()->OpacityAnimation(opacityAnimationOption, 0.0f, 1.0f);
2368     }
2369 }
2370 
SoftTransitionAnimationPush(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar,bool preUseCustomTransition,bool curUseCustomTransition,const NavigationGroupNode::AnimationFinishCallback & callback)2371 void NavigationGroupNode::SoftTransitionAnimationPush(const RefPtr<FrameNode>& preNode,
2372     const RefPtr<FrameNode>& curNode, bool isNavBar, bool preUseCustomTransition, bool curUseCustomTransition,
2373     const NavigationGroupNode::AnimationFinishCallback& callback)
2374 {
2375     AnimationOption option = CreateAnimationOption(
2376         Curves::FRICTION, FillMode::FORWARDS, SOFT_DEFAULT_ANIMATION_DURATION, callback);
2377     auto pattern = GetPattern<NavigationPattern>();
2378     CHECK_NULL_VOID(pattern);
2379     pattern->OnStartOneTransitionAnimation();
2380     auto newPushAnimation = AnimationUtils::StartAnimation(option, [
2381         preNode, curNode, isNavBar, preUseCustomTransition, curUseCustomTransition]() {
2382             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
2383             if (isNavBar) {
2384                 auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
2385                 CHECK_NULL_VOID(navBarNode);
2386                 navBarNode->StartSoftTransitionPush();
2387             } else {
2388                 if (preNode && !preUseCustomTransition) {
2389                     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2390                     CHECK_NULL_VOID(navDestination);
2391                     navDestination->StartSoftTransitionPush(false);
2392                 }
2393             }
2394             if (curNode && !curUseCustomTransition) {
2395                 auto curNavdestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2396                 CHECK_NULL_VOID(curNavdestination);
2397                 curNavdestination->StartSoftTransitionPush(true);
2398             }
2399     }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
2400     if (newPushAnimation) {
2401         pushAnimations_.emplace_back(newPushAnimation);
2402     }
2403 }
2404 
CreateSoftAnimationWithPush(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBar)2405 void NavigationGroupNode::CreateSoftAnimationWithPush(const TransitionUnitInfo& preInfo,
2406                                                       const TransitionUnitInfo& curInfo,
2407                                                       const AnimationFinishCallback finishCallback,
2408                                                       bool isNavBar)
2409 {
2410     auto pattern = GetPattern<NavigationPattern>();
2411     CHECK_NULL_VOID(pattern);
2412     auto preNode = preInfo.transitionNode;
2413     auto curNode = curInfo.transitionNode;
2414     auto preUseCustomTransition = preInfo.isUseCustomTransition;
2415     auto curUseCustomTransition = curInfo.isUseCustomTransition;
2416     if (isNavBar) {
2417         auto navBarNode = AceType::DynamicCast<NavBarNode>(preNode);
2418         CHECK_NULL_VOID(navBarNode);
2419         navBarNode->SoftTransitionPushAction(true);
2420     } else {
2421         if (preNode) {
2422             auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2423             CHECK_NULL_VOID(navDestination);
2424             if (!preUseCustomTransition) {
2425                 navDestination->InitSoftTransitionPush(false);
2426             }
2427         }
2428     }
2429     if (curNode) {
2430         auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2431         CHECK_NULL_VOID(curNavDestination);
2432         if (!curUseCustomTransition) {
2433             curNavDestination->InitSoftTransitionPush(true);
2434         }
2435     }
2436     // opacity animation
2437     StartSoftOpacityAnimationPush(curNode);
2438     // translateX animation
2439     SoftTransitionAnimationPush(preNode, curNode, isNavBar,
2440         preUseCustomTransition, curUseCustomTransition, finishCallback);
2441     if (preNode) {
2442         preNode->SetNodeFreeze(true);
2443     }
2444     ConfigureNavigationWithAnimation(preNode, curNode);
2445 }
2446 
StartSoftOpacityAnimationPop(const RefPtr<FrameNode> & preNode)2447 void NavigationGroupNode::StartSoftOpacityAnimationPop(const RefPtr<FrameNode>& preNode)
2448 {
2449     CHECK_NULL_VOID(preNode);
2450     AnimationOption opacityAnimationOption =
2451         CreateAnimationOption(Curves::SMOOTH, FillMode::FORWARDS, SOFT_POP_ANIMATION_OPACITY_DURATION, nullptr);
2452     opacityAnimationOption.SetDelay(SOFT_ANIMATION_OPACITY_DELAY);
2453     auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2454     CHECK_NULL_VOID(navDestination);
2455     auto titleBarNode = AceType::DynamicCast<FrameNode>(navDestination->GetTitleBarNode());
2456     if (navDestination->IsNeedContentTransition()) {
2457         preNode->GetRenderContext()->OpacityAnimation(opacityAnimationOption, 1.0f, 0.0f);
2458     } else if (titleBarNode && navDestination->IsNeedTitleTransition()) {
2459         titleBarNode->GetRenderContext()->OpacityAnimation(opacityAnimationOption, 1.0f, 0.0f);
2460     }
2461 }
2462 
SoftTransitionAnimationPop(const RefPtr<FrameNode> & preNode,const RefPtr<FrameNode> & curNode,bool isNavBar,bool preUseCustomTransition,bool curUseCustomTransition,const NavigationGroupNode::AnimationFinishCallback & callback)2463 void NavigationGroupNode::SoftTransitionAnimationPop(const RefPtr<FrameNode>& preNode,
2464     const RefPtr<FrameNode>& curNode, bool isNavBar, bool preUseCustomTransition, bool curUseCustomTransition,
2465     const NavigationGroupNode::AnimationFinishCallback& callback)
2466 {
2467     AnimationOption option = CreateAnimationOption(
2468         Curves::FRICTION, FillMode::FORWARDS, SOFT_DEFAULT_ANIMATION_DURATION, callback);
2469     auto pattern = GetPattern<NavigationPattern>();
2470     pattern->OnStartOneTransitionAnimation();
2471     auto newPopAnimation = AnimationUtils::StartAnimation(option, [
2472         this, preNode, curNode, isNavBar, preUseCustomTransition, curUseCustomTransition]() {
2473             PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
2474             if (curNode) {
2475                 if (isNavBar) {
2476                     auto curNavBar = AceType::DynamicCast<NavBarNode>(curNode);
2477                     CHECK_NULL_VOID(curNavBar);
2478                     curNavBar->StartSoftTransitionPop();
2479                 } else if (!curUseCustomTransition) {
2480                     auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2481                     CHECK_NULL_VOID(curNavDestination);
2482                     curNavDestination->StartSoftTransitionPop(true);
2483                 }
2484             }
2485             auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2486             CHECK_NULL_VOID(preNavDestination);
2487             if (!preUseCustomTransition) {
2488                 preNavDestination->StartSoftTransitionPop(false);
2489             }
2490     }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
2491     if (newPopAnimation) {
2492         popAnimations_.emplace_back(newPopAnimation);
2493     }
2494 }
2495 
CreateSoftAnimationWithPop(const TransitionUnitInfo & preInfo,const TransitionUnitInfo & curInfo,const AnimationFinishCallback finishCallback,bool isNavBar)2496 void NavigationGroupNode::CreateSoftAnimationWithPop(const TransitionUnitInfo& preInfo,
2497                                                      const TransitionUnitInfo& curInfo,
2498                                                      const AnimationFinishCallback finishCallback,
2499                                                      bool isNavBar)
2500 {
2501     auto pattern = GetPattern<NavigationPattern>();
2502     CHECK_NULL_VOID(pattern);
2503     auto preNode = preInfo.transitionNode;
2504     auto curNode = curInfo.transitionNode;
2505     auto preUseCustomTransition = preInfo.isUseCustomTransition;
2506     auto curUseCustomTransition = curInfo.isUseCustomTransition;
2507     CHECK_NULL_VOID(preNode);
2508     auto preNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(preNode);
2509     CHECK_NULL_VOID(preNavDestination);
2510     if (!preUseCustomTransition) {
2511         preNavDestination->InitSoftTransitionPop(false);
2512     }
2513     if (curNode) {
2514         if (isNavBar) {
2515             auto navBarNode = AceType::DynamicCast<NavBarNode>(curNode);
2516             CHECK_NULL_VOID(navBarNode);
2517             navBarNode->InitSoftTransitionPop();
2518         } else {
2519             auto curNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
2520             CHECK_NULL_VOID(curNavDestination);
2521             if (!curUseCustomTransition) {
2522                 curNavDestination->InitSoftTransitionPop(true);
2523             }
2524         }
2525     }
2526     // opacity animation
2527     StartSoftOpacityAnimationPop(preNode);
2528     // translateX animation
2529     SoftTransitionAnimationPop(preNode, curNode, isNavBar,
2530         preUseCustomTransition, curUseCustomTransition, finishCallback);
2531     ConfigureNavigationWithAnimation(preNode, curNode);
2532 }
2533 
GetNavBarOrHomeDestinationNode() const2534 const RefPtr<UINode>& NavigationGroupNode::GetNavBarOrHomeDestinationNode() const
2535 {
2536     if (useHomeDestination_.has_value() && useHomeDestination_.value()) {
2537         return customHomeDestination_;
2538     } else {
2539         return navBarNode_;
2540     }
2541 }
2542 
IsNavBarOrHomeDestination(const RefPtr<UINode> & node) const2543 bool NavigationGroupNode::IsNavBarOrHomeDestination(const RefPtr<UINode>& node) const
2544 {
2545     CHECK_NULL_RETURN(node, false);
2546     if (node->GetTag() == V2::NAVBAR_ETS_TAG) {
2547         return true;
2548     }
2549     return customHomeDestination_ != nullptr && customHomeDestination_ == node;
2550 }
2551 
CreateHomeDestinationIfNeeded()2552 void NavigationGroupNode::CreateHomeDestinationIfNeeded()
2553 {
2554     if (!useHomeDestination_.has_value() || !useHomeDestination_.value() || customHomeDestination_) {
2555         return;
2556     }
2557     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "will create home NavDestination");
2558     auto pattern = GetPattern<NavigationPattern>();
2559     CHECK_NULL_VOID(pattern);
2560     RefPtr<NavDestinationGroupNode> destNode = nullptr;
2561     if (!pattern->CreateHomeDestination(customHomeNode_, destNode)) {
2562         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "failed to create home NavDestination");
2563         return;
2564     }
2565     CHECK_NULL_VOID(customHomeNode_);
2566     CHECK_NULL_VOID(destNode);
2567     SetBackButtonEvent(destNode);
2568     auto eventHub = destNode->GetOrCreateEventHub<NavDestinationEventHub>();
2569     CHECK_NULL_VOID(eventHub);
2570     eventHub->FireOnWillAppear();
2571     AddChild(destNode, 0);
2572     customHomeDestination_ = destNode;
2573 }
2574 } // namespace OHOS::Ace::NG
2575