1 /*
2  * Copyright (c) 2023 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/inner_navigation_controller.h"
17 
18 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20 
21 namespace OHOS {
22 namespace Ace {
23 namespace {
24 constexpr int32_t INVALID_HANDLE = 0;
25 }
InnerNavigationController(const WeakPtr<NG::NavigationPattern> & pattern,int32_t containerId)26 InnerNavigationController::InnerNavigationController(
27     const WeakPtr<NG::NavigationPattern>& pattern, int32_t containerId)
28     : weakNavigationPattern_(pattern), containerId_(containerId) {}
29 
IsNavDestinationInTopStack()30 bool InnerNavigationController::IsNavDestinationInTopStack()
31 {
32     return GetTopHandle() != INVALID_HANDLE;
33 }
34 
GetTopHandle()35 int32_t InnerNavigationController::GetTopHandle()
36 {
37     CHECK_RUN_ON(UI);
38     ContainerScope scope(containerId_);
39     auto navigationPattern = weakNavigationPattern_.Upgrade();
40     CHECK_NULL_RETURN(navigationPattern, INVALID_HANDLE);
41     auto navigationStack = navigationPattern->GetNavigationStack();
42     CHECK_NULL_RETURN(navigationStack, INVALID_HANDLE);
43     auto topNavDestinationNode = navigationStack->GetTopNavPath();
44     if (!topNavDestinationNode.has_value()) {
45         return INVALID_HANDLE;
46     }
47 
48     auto navDestinationNode = AceType::DynamicCast<NG::NavDestinationGroupNode>(
49         NG::NavigationGroupNode::GetNavDestinationNode(topNavDestinationNode->second));
50     CHECK_NULL_RETURN(navDestinationNode, INVALID_HANDLE);
51     return topNavDestinationNode->second->GetId();
52 }
53 
SetInPIPMode(int32_t handle)54 void InnerNavigationController::SetInPIPMode(int32_t handle)
55 {
56     CHECK_RUN_ON(UI);
57     ContainerScope scope(containerId_);
58     auto navigationPattern = weakNavigationPattern_.Upgrade();
59     CHECK_NULL_VOID(navigationPattern);
60     auto navigationStack = navigationPattern->GetNavigationStack();
61     CHECK_NULL_VOID(navigationStack);
62     auto cacheNode = navigationStack->GetFromCacheNode(handle);
63     if (cacheNode.has_value()) {
64         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "The node has in cache");
65         return;
66     }
67 
68     const auto& navDestinationNodes = navigationStack->GetAllNavDestinationNodes();
69     for (size_t i = 0; i != navDestinationNodes.size(); ++i) {
70         const auto& childNode = navDestinationNodes[i];
71         const auto& uiNode = childNode.second;
72         if (uiNode && uiNode->GetId() == handle) {
73             auto navDestination = AceType::DynamicCast<NG::NavDestinationGroupNode>(
74             NG::NavigationGroupNode::GetNavDestinationNode(uiNode));
75             if (navDestination == nullptr) {
76                 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "The node is not navDestination node");
77                 return;
78             }
79 
80             navigationStack->AddCacheNode(childNode.first, uiNode);
81             return;
82         }
83     }
84 }
85 
PopInPIP(bool destroy)86 void InnerNavigationController::PopInPIP(bool destroy)
87 {
88     CHECK_RUN_ON(UI);
89     ContainerScope scope(containerId_);
90     auto navigationPattern = weakNavigationPattern_.Upgrade();
91     CHECK_NULL_VOID(navigationPattern);
92     auto navigationStack = navigationPattern->GetNavigationStack();
93     CHECK_NULL_VOID(navigationStack);
94     auto topNavDestinationNode = navigationStack->GetTopNavPath();
95     if (!topNavDestinationNode.has_value()) {
96         return;
97     }
98 
99     if (destroy && topNavDestinationNode->second) {
100         navigationStack->RemoveCacheNode(topNavDestinationNode->second->GetId());
101     }
102 
103     navigationStack->Pop();
104 }
105 
PushInPIP(int32_t handle)106 void InnerNavigationController::PushInPIP(int32_t handle)
107 {
108     CHECK_RUN_ON(UI);
109     ContainerScope scope(containerId_);
110     auto navigationPattern = weakNavigationPattern_.Upgrade();
111     CHECK_NULL_VOID(navigationPattern);
112     auto navigationStack = navigationPattern->GetNavigationStack();
113     CHECK_NULL_VOID(navigationStack);
114     auto topNavDestinationNode = navigationStack->GetTopNavPath();
115     if (topNavDestinationNode.has_value()) {
116         if (topNavDestinationNode->second && topNavDestinationNode->second->GetId() == handle) {
117             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "The node has in top stack");
118             return;
119         }
120     }
121     auto cacheNode = navigationStack->GetFromCacheNode(handle);
122     if (!cacheNode.has_value()) {
123         return;
124     }
125 
126     navigationStack->ReOrderCache(cacheNode->first, cacheNode->second);
127     auto context = PipelineContext::GetCurrentContext();
128     CHECK_NULL_VOID(context);
129 
130     auto nodePairs = navigationStack->GetAllNavDestinationNodes();
131     bool findPipNode = false;
132     int32_t nativeStackIndex = 0;
133     for (const auto& pair : nodePairs) {
134         if (pair.first == cacheNode->first && pair.second->GetId() == handle) {
135             findPipNode = true;
136             break;
137         }
138         nativeStackIndex++;
139     }
140 
141     if (findPipNode) {
142         int32_t jsIndex = navigationStack->GetJsIndexFromNativeIndex(nativeStackIndex);
143         if (jsIndex < 0) {
144             navigationStack->Push(cacheNode->first);
145         } else {
146             navigationStack->MoveIndexToTop(jsIndex);
147         }
148     } else {
149         navigationStack->Push(cacheNode->first);
150     }
151 }
152 
DeletePIPMode(int32_t handle)153 void InnerNavigationController::DeletePIPMode(int32_t handle)
154 {
155     CHECK_RUN_ON(UI);
156     ContainerScope scope(containerId_);
157     auto navigationPattern = weakNavigationPattern_.Upgrade();
158     CHECK_NULL_VOID(navigationPattern);
159     auto navigationStack = navigationPattern->GetNavigationStack();
160     CHECK_NULL_VOID(navigationStack);
161     auto context = NG::PipelineContext::GetCurrentContext();
162     CHECK_NULL_VOID(context);
163 
164     auto task = [weakStack = AceType::WeakClaim(AceType::RawPtr(navigationStack)), handle]() {
165         auto stack = weakStack.Upgrade();
166         CHECK_NULL_VOID(stack);
167         stack->RemoveCacheNode(handle);
168     };
169     context->AddBuildFinishCallBack(task);
170 }
171 } // namespace Ace
172 } // namespace OHOS
173