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