• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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/manager/navigation/navigation_manager.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/components_ng/pattern/container_modal/enhance/container_modal_view_enhance.h"
20 #include "core/components_ng/pattern/dialog/dialog_pattern.h"
21 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
22 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
23 
24 namespace OHOS::Ace::NG {
25 constexpr int32_t INDENT_SIZE = 2;
26 constexpr int32_t INVALID_NODE_ID = -1;
27 constexpr char INTENT_PARAM_KEY[] = "ohos.insightIntent.executeParam.param";
28 constexpr char INTENT_NAVIGATION_ID_KEY[] = "ohos.insightIntent.pageParam.navigationId";
29 constexpr char INTENT_NAVDESTINATION_NAME_KEY[] = "ohos.insightIntent.pageParam.navDestinationName";
30 
IsOuterMostNavigation(int32_t nodeId,int32_t depth)31 bool NavigationManager::IsOuterMostNavigation(int32_t nodeId, int32_t depth)
32 {
33     if (dumpMap_.empty()) {
34         return false;
35     }
36     auto outerMostKey = dumpMap_.begin()->first;
37     return outerMostKey == DumpMapKey(nodeId, depth);
38 }
39 
SetForceSplitNavState(bool isTargetForceSplitNav,const RefPtr<FrameNode> & navigationNode)40 void NavigationManager::SetForceSplitNavState(bool isTargetForceSplitNav, const RefPtr<FrameNode>& navigationNode)
41 {
42     auto pattern = navigationNode->GetPattern<NavigationPattern>();
43     CHECK_NULL_VOID(pattern);
44     // Notification target navigation can attempt to force split.
45     pattern->SetIsTargetForceSplitNav(isTargetForceSplitNav);
46     // Record that the force split has been done in navigation manager
47     SetExistForceSplitNav(isTargetForceSplitNav, isTargetForceSplitNav ? navigationNode->GetId() : INVALID_NODE_ID);
48 }
49 
RemoveForceSplitNavStateIfNeed(int32_t nodeId)50 void NavigationManager::RemoveForceSplitNavStateIfNeed(int32_t nodeId)
51 {
52     auto existForceSplitNav = GetExistForceSplitNav();
53     if (existForceSplitNav.first && existForceSplitNav.second == nodeId) {
54         SetExistForceSplitNav(false, INVALID_NODE_ID);
55     }
56 }
57 
IsTargetForceSplitNav(const RefPtr<FrameNode> & navigationNode)58 void NavigationManager::IsTargetForceSplitNav(const RefPtr<FrameNode>& navigationNode)
59 {
60     /**
61      * If it does not support force split,
62      * or if there is already a force split navigation,
63      * return directly.
64      */
65     auto existForceSplitNav = GetExistForceSplitNav();
66     if (!IsForceSplitSupported() || existForceSplitNav.first) {
67         return;
68     }
69 
70     /**
71      * If id and depth are not configured, the target force split navigation is the outermost navigation.
72      * It is necessary to determine whether the current navigation is the outermost navigation.
73      * Current navigation determines whether to force split before dumpMap information is stored,
74      * if the map is empty, the current navigation is the outermost navigation.
75      */
76     if (!TargetIdOrDepthExists()) {
77         bool isOuterMostNavigation = dumpMap_.begin() == dumpMap_.end();
78         SetForceSplitNavState(isOuterMostNavigation, navigationNode);
79         return;
80     }
81 
82     // Prioritize whether the configured id matches the id of the current navigation, when configuring id.
83     auto targetInspectorId = GetTargetNavigationId();
84     if (targetInspectorId.has_value()) {
85         auto currInspectorId = navigationNode->GetInspectorId().value_or("");
86         bool isTargetForceSplitNav = currInspectorId == targetInspectorId.value();
87         SetForceSplitNavState(isTargetForceSplitNav, navigationNode);
88         return;
89     }
90     auto targetNestedDepth = GetTargetNavigationDepth();
91     if (!targetNestedDepth.has_value()) {
92         return;
93     }
94 
95     /**
96      * If the current navigation depth is greater than the maximum depth stored in the dumpMap_,
97      * this means that there are no nodes at the same level in the current navigation node,
98      * and nested depth increased by one.
99      * After get the nested depth of the current navigation,
100      * compare whether it is the target nested depth navigation.
101      */
102     auto currDeepest = dumpMap_.rbegin();
103     auto currNodeDepth = navigationNode->GetDepth();
104     currNestedDepth_ =
105         currDeepest != dumpMap_.rend() && currNodeDepth > currDeepest->first.depth
106         ? ++currNestedDepth_
107         : currNestedDepth_;
108     bool isTargetForceSplitNav = currNestedDepth_ == targetNestedDepth.value();
109     SetForceSplitNavState(isTargetForceSplitNav, navigationNode);
110 }
111 
AddNavigationDumpCallback(const RefPtr<FrameNode> & navigationNode,const DumpCallback & callback)112 void NavigationManager::AddNavigationDumpCallback(const RefPtr<FrameNode>& navigationNode, const DumpCallback& callback)
113 {
114     CHECK_RUN_ON(UI);
115     IsTargetForceSplitNav(navigationNode);
116     dumpMap_.emplace(DumpMapKey(navigationNode->GetId(), navigationNode->GetDepth()), callback);
117 }
118 
RemoveNavigationDumpCallback(int32_t nodeId,int32_t depth)119 void NavigationManager::RemoveNavigationDumpCallback(int32_t nodeId, int32_t depth)
120 {
121     CHECK_RUN_ON(UI);
122     auto it = dumpMap_.find(DumpMapKey(nodeId, depth));
123     if (it != dumpMap_.end()) {
124         dumpMap_.erase(it);
125     }
126     RemoveForceSplitNavStateIfNeed(nodeId);
127 }
128 
OnDumpInfo()129 void NavigationManager::OnDumpInfo()
130 {
131     CHECK_RUN_ON(UI);
132     auto pipeline = PipelineContext::GetCurrentContext();
133     CHECK_NULL_VOID(pipeline);
134     auto rootNode = pipeline->GetRootElement();
135     if (!rootNode) {
136         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navigation dump failed, invalid root node");
137         return;
138     }
139     DumpLog::GetInstance().Print("Navigation number: " + std::to_string(dumpMap_.size()));
140     std::stack<std::pair<RefPtr<UINode>, int32_t>> stack;
141     stack.push({ rootNode, 0 });
142     while (!stack.empty()) {
143         auto [curNode, curDepth] = stack.top();
144         stack.pop();
145         std::string space(INDENT_SIZE * curDepth, ' ');
146         int32_t depth = 0;
147         if (curNode->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
148             auto navigation = AceType::DynamicCast<NavigationGroupNode>(curNode);
149             CHECK_NULL_VOID(navigation);
150             DumpLog::GetInstance().Print(space + navigation->ToDumpString());
151             depth++;
152         } else if (curNode->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
153             auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
154             CHECK_NULL_VOID(navDestination);
155             DumpLog::GetInstance().Print(space + navDestination->ToDumpString());
156             depth++;
157             auto parent = curNode->GetParent();
158             if (!stack.empty() && parent && parent->GetTag() == V2::PRIMARY_CONTENT_NODE_ETS_TAG &&
159                 stack.top().first->GetTag() != V2::NAVDESTINATION_VIEW_ETS_TAG) {
160                 DumpLog::GetInstance().Print("----------------------------------------------------------");
161             }
162         } else if (curNode->GetTag() == V2::NAVBAR_ETS_TAG) {
163             auto navBar = AceType::DynamicCast<NavBarNode>(curNode);
164             CHECK_NULL_VOID(navBar);
165             DumpLog::GetInstance().Print(space + navBar->ToDumpString());
166             DumpLog::GetInstance().Print("----------------------------------------------------------");
167         }
168         const auto& children = curNode->GetChildren();
169         for (auto it = children.rbegin(); it != children.rend(); it++) {
170             if (!(*it)) {
171                 continue;
172             }
173             stack.push({ *it, curDepth + depth });
174         }
175     }
176 }
177 
FireNavigationUpdateCallback()178 void NavigationManager::FireNavigationUpdateCallback()
179 {
180     for (const auto& func : updateCallbacks_) {
181         func();
182     }
183     updateCallbacks_.clear();
184 }
185 
GetNavigationInfo(const RefPtr<AceType> & node)186 std::shared_ptr<NavigationInfo> NavigationManager::GetNavigationInfo(const RefPtr<AceType>& node)
187 {
188     RefPtr<UINode> current = nullptr;
189     auto customNode = AceType::DynamicCast<CustomNode>(node);
190     if (customNode) {
191         current = customNode->GetNavigationNode().Upgrade();
192     }
193 
194     if (!current) {
195         current = AceType::DynamicCast<UINode>(node);
196         while (current) {
197             if (current->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
198                 break;
199             }
200             current = current->GetParent();
201         }
202     }
203 
204     if (!current) {
205         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "find parent navigation node failed");
206         return nullptr;
207     }
208 
209     auto navigation = AceType::DynamicCast<NavigationGroupNode>(current);
210     CHECK_NULL_RETURN(navigation, nullptr);
211     auto pattern = navigation->GetPattern<NavigationPattern>();
212     CHECK_NULL_RETURN(pattern, nullptr);
213     auto stack = pattern->GetNavigationStack();
214     CHECK_NULL_RETURN(stack, nullptr);
215     return std::make_shared<NavigationInfo>(navigation->GetInspectorId().value_or(""), stack, navigation->GetId());
216 }
217 
AddInteractiveAnimation(const std::function<void ()> & addCallback)218 bool NavigationManager::AddInteractiveAnimation(const std::function<void()>& addCallback)
219 {
220     if (!isInteractive_) {
221         return false;
222     }
223     auto navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(
224         FrameNode::GetFrameNode(V2::NAVIGATION_VIEW_ETS_TAG, interactiveAnimationId_));
225     CHECK_NULL_RETURN(navigationGroupNode, false);
226     auto pattern = navigationGroupNode->GetPattern<NavigationPattern>();
227     CHECK_NULL_RETURN(pattern, false);
228     auto proxy = pattern->GetTopNavigationProxy();
229     CHECK_NULL_RETURN(proxy, false);
230     proxy->AddInteractiveAnimation(addCallback);
231     return true;
232 }
233 
CheckNodeNeedCache(const RefPtr<FrameNode> & node)234 bool NavigationManager::CheckNodeNeedCache(const RefPtr<FrameNode>& node)
235 {
236     CHECK_NULL_RETURN(node, false);
237 
238     auto context = node->GetRenderContext();
239     if ((context && context->GetAnimationsCount() != 0) || node->GetTag() == V2::UI_EXTENSION_COMPONENT_ETS_TAG) {
240         return false;
241     }
242     std::stack<RefPtr<FrameNode>> nodeStack;
243     nodeStack.push(node);
244     while (!nodeStack.empty()) {
245         auto curNode = nodeStack.top();
246         nodeStack.pop();
247         std::list<RefPtr<FrameNode>> children;
248         curNode->GenerateOneDepthVisibleFrameWithTransition(children);
249         for (auto& child : children) {
250             if (!child) {
251                 continue;
252             }
253             auto childContext = child->GetRenderContext();
254             if ((childContext && childContext->GetAnimationsCount() != 0) ||
255                 child->GetTag() == V2::UI_EXTENSION_COMPONENT_ETS_TAG) {
256                 return false;
257             }
258             nodeStack.push(child);
259         }
260         auto overlayNode = curNode->GetOverlayNode();
261         if (overlayNode) {
262             auto overlayNodeContext = overlayNode->GetRenderContext();
263             if ((overlayNodeContext && overlayNodeContext->GetAnimationsCount() != 0) ||
264                 overlayNode->GetTag() == V2::UI_EXTENSION_COMPONENT_ETS_TAG) {
265                 return false;
266             }
267             nodeStack.push(overlayNode);
268         }
269     }
270     return true;
271 }
272 
GetNavDestContentFrameNode(const RefPtr<FrameNode> & node)273 RefPtr<FrameNode> NavigationManager::GetNavDestContentFrameNode(const RefPtr<FrameNode>& node)
274 {
275     CHECK_NULL_RETURN(node, nullptr);
276     auto navDestinationNodeBase = AceType::DynamicCast<NavDestinationNodeBase>(node);
277     CHECK_NULL_RETURN(navDestinationNodeBase, nullptr);
278     auto navDestContentFrameNode = AceType::DynamicCast<FrameNode>(navDestinationNodeBase->GetContentNode());
279     CHECK_NULL_RETURN(navDestContentFrameNode, nullptr);
280     return navDestContentFrameNode;
281 }
282 
UpdatePreNavNodeRenderGroupProperty()283 void NavigationManager::UpdatePreNavNodeRenderGroupProperty()
284 {
285     auto preNavNode = preNavNode_.Upgrade();
286     CHECK_NULL_VOID(preNavNode);
287     auto preNavDestContentNode = GetNavDestContentFrameNode(preNavNode);
288     CHECK_NULL_VOID(preNavDestContentNode);
289     auto state = CheckNodeNeedCache(preNavDestContentNode);
290     UpdateAnimationCachedRenderGroup(preNavDestContentNode, state);
291     preNodeAnimationCached_ = state;
292     preNodeNeverSet_ = false;
293     auto preNavPattern = preNavNode->GetPattern<NavDestinationPattern>();
294     auto name = preNavPattern == nullptr ? "NavBar" : preNavPattern->GetName();
295     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "Cache PreNavNode, name=%{public}s, will cache? %{public}s", name.c_str(),
296         state ? "yes" : "no");
297 }
298 
UpdateCurNavNodeRenderGroupProperty()299 void NavigationManager::UpdateCurNavNodeRenderGroupProperty()
300 {
301     auto curNavNode = curNavNode_.Upgrade();
302     CHECK_NULL_VOID(curNavNode);
303     auto curNavDestContentNode = GetNavDestContentFrameNode(curNavNode);
304     CHECK_NULL_VOID(curNavDestContentNode);
305     auto state = CheckNodeNeedCache(curNavDestContentNode);
306     UpdateAnimationCachedRenderGroup(curNavDestContentNode, state);
307     curNodeAnimationCached_ = state;
308     currentNodeNeverSet_ = false;
309     auto curNavPattern = curNavNode->GetPattern<NavDestinationPattern>();
310     auto name = curNavPattern == nullptr ? "NavBar" : curNavPattern->GetName();
311     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "Cache CurNavNode, name=%{public}s, will cache? %{public}s", name.c_str(),
312         state ? "yes" : "no");
313 }
314 
SetForceSplitEnable(bool isForceSplit,const std::string & homePage,bool ignoreOrientation)315 void NavigationManager::SetForceSplitEnable(bool isForceSplit, const std::string& homePage, bool ignoreOrientation)
316 {
317     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "set navigation force split %{public}s, homePage:%{public}s, "
318         "ignoreOrientation:%{public}d", (isForceSplit ? "enable" : "disable"), homePage.c_str(), ignoreOrientation);
319     /**
320      * As long as the application supports force split, regardless of whether it is enabled or not,
321      * the SetForceSplitleEnable interface will be called.
322      */
323     isForceSplitSupported_ = true;
324     if (isForceSplitEnable_ == isForceSplit && homePageName_ == homePage && ignoreOrientation_ == ignoreOrientation) {
325         return;
326     }
327     isForceSplitEnable_ = isForceSplit;
328     homePageName_ = homePage;
329     ignoreOrientation_ = ignoreOrientation;
330 
331     auto listeners = forceSplitListeners_;
332     for (auto& listener : listeners) {
333         if (listener.second) {
334             listener.second();
335         }
336     }
337 }
338 
GetIgnoreOrientation() const339 bool NavigationManager::GetIgnoreOrientation() const
340 {
341     if (SystemProperties::GetForceSplitIgnoreOrientationEnabled()) {
342         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Navigation forceSplit ignore Orientation");
343         return true;
344     }
345     return ignoreOrientation_;
346 }
347 
AddForceSplitListener(int32_t nodeId,std::function<void ()> && listener)348 void NavigationManager::AddForceSplitListener(int32_t nodeId, std::function<void()>&& listener)
349 {
350     forceSplitListeners_[nodeId] = std::move(listener);
351 }
352 
RemoveForceSplitListener(int32_t nodeId)353 void NavigationManager::RemoveForceSplitListener(int32_t nodeId)
354 {
355     auto it = forceSplitListeners_.find(nodeId);
356     if (it != forceSplitListeners_.end()) {
357         forceSplitListeners_.erase(it);
358     }
359 }
360 
ResetCurNavNodeRenderGroupProperty()361 void NavigationManager::ResetCurNavNodeRenderGroupProperty()
362 {
363     auto curNavNode = curNavNode_.Upgrade();
364     CHECK_NULL_VOID(curNavNode);
365     auto curNavDestContentNode = GetNavDestContentFrameNode(curNavNode);
366     CHECK_NULL_VOID(curNavDestContentNode);
367     UpdateAnimationCachedRenderGroup(curNavDestContentNode, false);
368     curNodeAnimationCached_ = false;
369     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "Cancel Cache CurNavNode node(id=%{public}d name=%{public}s)",
370         curNavDestContentNode->GetId(), curNavDestContentNode->GetTag().c_str());
371 }
372 
CacheNavigationNodeAnimation()373 void NavigationManager::CacheNavigationNodeAnimation()
374 {
375     if (!hasCacheNavigationNodeEnable_) {
376         return;
377     }
378     if (!IsNavigationInAnimation()) {
379         return;
380     }
381     auto pipeline = PipelineContext::GetCurrentContext();
382     CHECK_NULL_VOID(pipeline);
383     /**
384      * If the exit page has not been cached before, or if the already cached exit page changes again,
385      * cache the exit page for future use.
386      */
387     if (preNodeNeverSet_ || (isNodeAddAnimation_ && preNodeAnimationCached_)) {
388         UpdatePreNavNodeRenderGroupProperty();
389         isNodeAddAnimation_ = false;
390     }
391     //  Cache the entry page for future use
392     if (currentNodeNeverSet_ && !curNodeAnimationCached_ && !pipeline->GetIsRequestVsync()) {
393         UpdateCurNavNodeRenderGroupProperty();
394     }
395     // If the cached entry page changes again, cancel the previously marked entry page.
396     if (!currentNodeNeverSet_) {
397         ResetCurNavNodeRenderGroupProperty();
398     }
399 }
400 
UpdateAnimationCachedRenderGroup(const RefPtr<FrameNode> & node,bool isSet)401 void NavigationManager::UpdateAnimationCachedRenderGroup(const RefPtr<FrameNode>& node, bool isSet)
402 {
403     auto context = node->GetRenderContext();
404     CHECK_NULL_VOID(context);
405     TAG_LOGD(AceLogTag::ACE_NAVIGATION,
406         "UpdateAnimationCachedRenderGroup node(id=%{public}d name=%{public}s), isSet=%{public}d", node->GetId(),
407         node->GetTag().c_str(), isSet);
408     context->UpdateRenderGroup(isSet, false, false);
409 }
410 
AddRecoverableNavigation(std::string id,RefPtr<AceType> navigationNode)411 bool NavigationManager::AddRecoverableNavigation(std::string id, RefPtr<AceType> navigationNode)
412 {
413     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navigationNode);
414     CHECK_NULL_RETURN(navigation, false);
415     if (!navigation->CanRecovery() || id != navigation->GetCurId()) {
416         return false;
417     }
418     recoverableNavigationMap_[id] = navigationNode;
419     return true;
420 }
421 
GetNavigationJsonInfo()422 std::unique_ptr<JsonValue> NavigationManager::GetNavigationJsonInfo()
423 {
424     auto allNavigationInfo = JsonUtil::CreateArray(true);
425     for (auto iter : recoverableNavigationMap_) {
426         auto node = iter.second.Upgrade();
427         if (!node) {
428             continue;
429         }
430         auto navigation = AceType::DynamicCast<NavigationGroupNode>(node);
431         if (!navigation->CanRecovery()) {
432             continue;
433         }
434         auto navigationPattern = navigation->GetPattern<NavigationPattern>();
435         if (!navigationPattern) {
436             continue;
437         }
438         auto navigationInfo = JsonUtil::Create(true);
439         navigationInfo->Put("id", iter.first.c_str());
440         navigationInfo->Put("stack", navigationPattern->GetNavdestinationJsonArray());
441         allNavigationInfo->Put(navigationInfo);
442     }
443     return allNavigationInfo;
444 }
445 
StorageNavigationRecoveryInfo(std::unique_ptr<JsonValue> navigationRecoveryInfo)446 void NavigationManager::StorageNavigationRecoveryInfo(std::unique_ptr<JsonValue> navigationRecoveryInfo)
447 {
448     auto allNavigationInfo = std::move(navigationRecoveryInfo);
449     if (!allNavigationInfo || !allNavigationInfo->IsArray()) {
450         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "Navigation recovery info invalid, can not restore!");
451         return;
452     }
453     auto arraySize = allNavigationInfo->GetArraySize();
454     for (int32_t i = 0; i < arraySize; ++ i) {
455         auto navigationInfo = allNavigationInfo->GetArrayItem(i);
456         auto navigationId = navigationInfo->GetString("id");
457         auto stackInfo = navigationInfo->GetValue("stack");
458         if (!stackInfo->IsArray()) {
459             continue;
460         }
461         std::vector<NavdestinationRecoveryInfo> navdestinationsInfo;
462         auto stackSize = stackInfo->GetArraySize();
463         for (int32_t j = 0; j < stackSize; ++ j) {
464             auto navdestinationInfo = stackInfo->GetArrayItem(j);
465             auto name = navdestinationInfo->GetString("name");
466             auto param = navdestinationInfo->GetString("param");
467             auto mode = navdestinationInfo->GetInt("mode");
468             navdestinationsInfo.emplace_back(NavdestinationRecoveryInfo(name, param, mode));
469         }
470         navigationRecoveryInfo_[navigationId] = navdestinationsInfo;
471     }
472 }
473 
GetNavigationRecoveryInfo(std::string navigationId)474 const std::vector<NavdestinationRecoveryInfo> NavigationManager::GetNavigationRecoveryInfo(std::string navigationId)
475 {
476     if (navigationRecoveryInfo_.find(navigationId) == navigationRecoveryInfo_.end()) {
477         return {};
478     }
479     auto ret = navigationRecoveryInfo_[navigationId];
480     navigationRecoveryInfo_.erase(navigationId);
481     return ret;
482 }
483 
AddNavigation(int32_t parentNodeId,const RefPtr<FrameNode> & navigationNode)484 void NavigationManager::AddNavigation(int32_t parentNodeId, const RefPtr<FrameNode>& navigationNode)
485 {
486     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navigationNode);
487     CHECK_NULL_VOID(navigation);
488     auto navigationInfo = NavigationInfo(navigation->GetId(), navigation->GetCurId(), navigation);
489     if (navigationMap_.find(parentNodeId) != navigationMap_.end()) {
490         navigationMap_[parentNodeId].push_back(navigationInfo);
491         return;
492     }
493     navigationMap_[parentNodeId] = { navigationInfo };
494 }
495 
RemoveNavigation(int32_t navigationNodeId)496 void NavigationManager::RemoveNavigation(int32_t navigationNodeId)
497 {
498     for (auto navigationIter = navigationMap_.begin(); navigationIter != navigationMap_.end();) {
499         auto& navigationInfos = navigationIter->second;
500         auto it = std::find_if(navigationInfos.begin(), navigationInfos.end(), [navigationNodeId](auto info) {
501             return navigationNodeId == info.nodeId;
502         });
503         if (it == navigationInfos.end()) {
504             navigationIter++;
505             continue;
506         }
507         navigationInfos.erase(it);
508         if (navigationInfos.empty()) {
509             navigationIter = navigationMap_.erase(navigationIter);
510         } else {
511             navigationIter++;
512         }
513     }
514 }
515 
FindNavigationInTargetParent(int32_t targetId)516 std::vector<int32_t> NavigationManager::FindNavigationInTargetParent(int32_t targetId)
517 {
518     auto it = navigationMap_.find(targetId);
519     if (it == navigationMap_.end()) {
520         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "can't find inner navigation");
521         return {};
522     }
523     std::vector<int32_t> navigationIds = {};
524     auto navigationInfos = it->second;
525     for (auto navigationInfo : navigationInfos) {
526         navigationIds.push_back(navigationInfo.nodeId);
527     }
528     return navigationIds;
529 }
530 
FireNavigationLifecycle(const RefPtr<UINode> & node,int32_t lifecycle,int32_t reason)531 void NavigationManager::FireNavigationLifecycle(const RefPtr<UINode>& node, int32_t lifecycle, int32_t reason)
532 {
533     NavDestinationActiveReason activeReason = static_cast<NavDestinationActiveReason>(reason);
534     if (activeReason == NavDestinationActiveReason::TRANSITION) {
535         NavigationPattern::FireNavigationLifecycle(node, static_cast<NavDestinationLifecycle>(lifecycle),
536             activeReason);
537         return;
538     }
539     // fire navdestination lifecycle in outer layer
540     FireLowerLayerLifecycle(nullptr, lifecycle, reason);
541 }
542 
FireOverlayLifecycle(const RefPtr<UINode> & node,int32_t lifecycle,int32_t reason)543 void NavigationManager::FireOverlayLifecycle(const RefPtr<UINode>& node, int32_t lifecycle, int32_t reason)
544 {
545     CHECK_NULL_VOID(node);
546     NavDestinationActiveReason activeReason = static_cast<NavDestinationActiveReason>(reason);
547     auto currentLifecycle = static_cast<NavDestinationLifecycle>(lifecycle);
548     NavigationPattern::FireNavigationLifecycle(node, currentLifecycle, activeReason);
549     NavDestinationLifecycle lowerLifecycle = NavDestinationLifecycle::ON_ACTIVE;
550     if (lifecycle == NavDestinationLifecycle::ON_ACTIVE) {
551         lowerLifecycle = NavDestinationLifecycle::ON_INACTIVE;
552     }
553     if (lifecycle == NavDestinationLifecycle::ON_INACTIVE) {
554         lowerLifecycle = NavDestinationLifecycle::ON_ACTIVE;
555     }
556     FireLowerLayerLifecycle(node, static_cast<int32_t>(lowerLifecycle), reason);
557 }
558 
FireLowerLayerLifecycle(const RefPtr<UINode> & node,int32_t lifecycle,int32_t reason)559 void NavigationManager::FireLowerLayerLifecycle(const RefPtr<UINode>& node, int32_t lifecycle, int32_t reason)
560 {
561     NavDestinationLifecycle lowerLifecycle = static_cast<NavDestinationLifecycle>(lifecycle);
562     NavDestinationActiveReason activeReason = static_cast<NavDestinationActiveReason>(reason);
563     auto pipelineContext = pipeline_.Upgrade();
564     CHECK_NULL_VOID(pipelineContext);
565     auto rootNode = pipelineContext->GetRootElement();
566     CHECK_NULL_VOID(rootNode);
567     RefPtr<UINode> curNode = node;
568     // sheet page node is not attach on root, get parent node sheetWrapper
569     if (node && node->GetTag() == V2::SHEET_PAGE_TAG) {
570         curNode = node->GetParent();
571     }
572     int32_t curNodeIndex = curNode ? rootNode->GetChildIndex(curNode)
573         : static_cast<int32_t>(rootNode->GetChildren().size());
574     // find lower layer node below node
575     for (auto index = curNodeIndex - 1; index >= 0; index--) {
576         auto child = AceType::DynamicCast<FrameNode>(rootNode->GetChildAtIndex(index));
577         if (!child) {
578             continue;
579         }
580         auto tag = child->GetTag();
581         if (tag == V2::SHEET_WRAPPER_TAG) {
582             NavigationPattern::FireNavigationLifecycle(child->GetChildAtIndex(0), lowerLifecycle, activeReason);
583             return;
584         }
585         if (tag == V2::MODAL_PAGE_TAG) {
586             NavigationPattern::FireNavigationLifecycle(child, lowerLifecycle, activeReason);
587             return;
588         }
589         if (IsOverlayValid(child)) {
590             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "overlay has onShow");
591             return;
592         }
593         if (IsCustomDialogValid(child)) {
594             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom dialog onShow");
595             return;
596         }
597     }
598     // fire last page lifecycle
599     auto stageManager = pipelineContext->GetStageManager();
600     CHECK_NULL_VOID(stageManager);
601     auto lastPage = stageManager->GetLastPage();
602     CHECK_NULL_VOID(lastPage);
603     NavigationPattern::FireNavigationLifecycle(lastPage, lowerLifecycle, activeReason);
604 }
605 
FireSubWindowLifecycle(const RefPtr<UINode> & node,int32_t lifecycle,int32_t reason)606 void NavigationManager::FireSubWindowLifecycle(const RefPtr<UINode>& node, int32_t lifecycle, int32_t reason)
607 {
608     auto context = AceType::DynamicCast<NG::PipelineContext>(PipelineContext::GetMainPipelineContext());
609     CHECK_NULL_VOID(context);
610     auto navigationManager = context->GetNavigationManager();
611     CHECK_NULL_VOID(navigationManager);
612     navigationManager->FireLowerLayerLifecycle(node, lifecycle, reason);
613 }
614 
IsOverlayValid(const RefPtr<UINode> & node)615 bool NavigationManager::IsOverlayValid(const RefPtr<UINode>& node)
616 {
617     if (node->GetTag() != V2::OVERLAY_ETS_TAG) {
618         return false;
619     }
620     auto overlays = node->GetChildren();
621     // check overlay is visible, if overlay is visible, don't need fire active lifecycle
622     for (auto index = 0; index < static_cast<int32_t>(overlays.size()); index++) {
623         auto overlay = AceType::DynamicCast<FrameNode>(node->GetChildAtIndex(index));
624         if (!overlay) {
625             continue;
626         }
627         auto layoutProperty = overlay->GetLayoutProperty();
628         if (layoutProperty && layoutProperty->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE) {
629             return true;
630         }
631     }
632     return false;
633 }
634 
IsCustomDialogValid(const RefPtr<UINode> & node)635 bool NavigationManager::IsCustomDialogValid(const RefPtr<UINode>& node)
636 {
637     auto frameNode = AceType::DynamicCast<FrameNode>(node);
638     CHECK_NULL_RETURN(frameNode, false);
639     // if lower layer is dialog, don't need to trigger lifecycle
640     auto pattern = frameNode->GetPattern();
641     if (!InstanceOf<DialogPattern>(pattern)) {
642         return false;
643     }
644     auto dialogPattern = AceType::DynamicCast<DialogPattern>(pattern);
645     if (!dialogPattern) {
646         return false;
647     }
648     auto dialogProperty = dialogPattern->GetDialogProperties();
649     // if dialog is custom dialog, don't need to trigger active lifecycle, it triggers when dialog closed
650     return dialogProperty.isUserCreatedDialog;
651 }
652 
AddBeforeOrientationChangeTask(const std::function<void ()> && task)653 void NavigationManager::AddBeforeOrientationChangeTask(const std::function<void()>&& task)
654 {
655     beforeOrientationChangeTasks_.emplace_back(std::move(task));
656 }
657 
ClearBeforeOrientationChangeTask()658 void NavigationManager::ClearBeforeOrientationChangeTask()
659 {
660     beforeOrientationChangeTasks_.clear();
661 }
662 
OnOrientationChanged()663 void NavigationManager::OnOrientationChanged()
664 {
665     auto tasks = std::move(beforeOrientationChangeTasks_);
666     for (auto& task : tasks) {
667         if (task) {
668             task();
669         }
670     }
671 }
672 
SetNavigationIntentInfo(const std::string & intentInfoSerialized,bool isColdStart)673 void NavigationManager::SetNavigationIntentInfo(const std::string& intentInfoSerialized, bool isColdStart)
674 {
675     if (intentInfoSerialized.empty()) {
676         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "error, serialized intent info is empty!");
677         return;
678     }
679     navigationIntentInfo_ = ParseNavigationIntentInfo(intentInfoSerialized);
680     navigationIntentInfo_.value().isColdStart = isColdStart;
681 }
682 
ParseNavigationIntentInfo(const std::string & intentInfoSerialized)683 NavigationIntentInfo NavigationManager::ParseNavigationIntentInfo(const std::string& intentInfoSerialized)
684 {
685     NavigationIntentInfo intentInfo;
686     auto intentJson = JsonUtil::ParseJsonString(intentInfoSerialized);
687     if (!intentJson || !intentJson->IsObject()) {
688         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "error, intent info is an invalid json object!");
689         return intentInfo;
690     }
691     intentInfo.param = intentJson->GetObject(INTENT_PARAM_KEY)->ToString();
692     intentInfo.navigationInspectorId = intentJson->GetString(INTENT_NAVIGATION_ID_KEY, "");
693     intentInfo.navDestinationName = intentJson->GetString(INTENT_NAVDESTINATION_NAME_KEY, "");
694     return intentInfo;
695 }
696 
FireNavigationIntentActively(int32_t pageId,bool needTransition)697 bool NavigationManager::FireNavigationIntentActively(int32_t pageId, bool needTransition)
698 {
699     if (navigationMap_.find(pageId) == navigationMap_.end()) {
700         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "error, no navigation in current page(id: %{public}d)", pageId);
701         return false;
702     }
703     if (!navigationIntentInfo_.has_value()) {
704         TAG_LOGE(AceLogTag::ACE_NAVIGATION, "error, navigation intent info is empty!");
705         return false;
706     }
707     auto navigationInfos = navigationMap_[pageId];
708     // find target navigation
709     for (auto navigationInfo : navigationInfos) {
710         if (navigationInfo.navigationId == navigationIntentInfo_.value().navigationInspectorId) {
711             auto navigationNode = navigationInfo.navigationNode.Upgrade();
712             if (!navigationNode) {
713                 return false;
714             }
715             auto pattern = navigationNode->GetPattern<NavigationPattern>();
716             if (!pattern) {
717                 return false;
718             }
719             return pattern->HandleIntent(needTransition);
720         }
721     }
722     TAG_LOGE(AceLogTag::ACE_NAVIGATION,
723         "error, specified navigation(id: %{public}s) doesn't exist in current page(id: %{public}d)",
724         navigationIntentInfo_.value().navigationInspectorId.c_str(), pageId);
725     return false;
726 }
727 
GetTopNavDestinationInfo(int32_t pageId,bool onlyFullScreen,bool needParam)728 std::string NavigationManager::GetTopNavDestinationInfo(int32_t pageId, bool onlyFullScreen, bool needParam)
729 {
730     if (navigationMap_.find(pageId) == navigationMap_.end()) {
731         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "no navigation in current page(id: %{public}d)", pageId);
732         return "{}";
733     }
734     auto navigationInfos = navigationMap_[pageId];
735     for (int32_t index = static_cast<int32_t>(navigationInfos.size()) -1; index >= 0; index--) {
736         auto navigationInfo = navigationInfos[index];
737         auto navigationNode = navigationInfo.navigationNode.Upgrade();
738         if (!navigationNode) {
739             continue;
740         }
741         auto pattern = navigationNode->GetPattern<NavigationPattern>();
742         if (!pattern) {
743             continue;
744         }
745         if (onlyFullScreen && !pattern->IsFullPageNavigation()) {
746             continue;
747         }
748         return pattern->GetTopNavdestinationJson(needParam)->ToString();
749     }
750     TAG_LOGW(AceLogTag::ACE_NAVIGATION, "no valid navigation in current page(id: %{public}d)", pageId);
751     return "{}";
752 }
753 
RestoreNavDestinationInfo(const std::string & navDestinationInfo,bool isColdStart)754 void NavigationManager::RestoreNavDestinationInfo(const std::string& navDestinationInfo, bool isColdStart)
755 {
756     auto navDestinationJson = JsonUtil::ParseJsonString(navDestinationInfo);
757     if (!navDestinationJson || !navDestinationJson->IsObject()) {
758         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "restore navdestination info is an invalid json object!");
759         return;
760     }
761     auto name = navDestinationJson->GetString("name");
762     auto param = navDestinationJson->GetString("param");
763     auto mode = navDestinationJson->GetInt("mode");
764     if (isColdStart) {
765         // for cold start case
766         auto navigationId = navDestinationJson->GetString("navigationId", "");
767         if (navigationId.empty()) {
768             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "will restore %{public}s without navigationId, "
769                 "it may lead to error in multi-navigation case!", name.c_str());
770         }
771         navigationRecoveryInfo_[navigationId] = { NavdestinationRecoveryInfo(name, param, mode) };
772         return;
773     }
774     // for hot start case
775     if (navigationMap_.empty()) {
776         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "restore navdestination failed cause  is an invagitlid json object!");
777         return;
778     }
779     auto navigationNode = GetNavigationByInspectorId(navDestinationJson->GetString("navigationId", ""));
780     CHECK_NULL_VOID(navigationNode);
781     auto pattern = navigationNode->GetPattern<NavigationPattern>();
782     CHECK_NULL_VOID(pattern);
783     auto navigationStack = pattern->GetNavigationStack();
784     CHECK_NULL_VOID(navigationStack);
785     navigationStack->CallPushDestinationInner(NavdestinationRecoveryInfo(name, param, mode));
786 }
787 
GetNavigationByInspectorId(const std::string & id) const788 RefPtr<FrameNode> NavigationManager::GetNavigationByInspectorId(const std::string& id) const
789 {
790     for (auto iter : navigationMap_) {
791         auto allNavigations = iter.second;
792         for (int32_t index = static_cast<int32_t>(allNavigations.size()) - 1; index >= 0; index--) {
793             auto navigationInfo = allNavigations[index];
794             if (navigationInfo.navigationId == id && navigationInfo.navigationNode.Upgrade()) {
795                 return navigationInfo.navigationNode.Upgrade();
796             }
797         }
798     }
799     return nullptr;
800 }
801 } // namespace OHOS::Ace::NG
802