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/pattern/overlay/sheet_manager.h"
17
18 #include "base/error/error_code.h"
19 #include "core/common/container.h"
20 #include "core/components_ng/base/frame_node.h"
21 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
22 #include "core/components_ng/pattern/stage/page_pattern.h"
23 #ifdef WINDOW_SCENE_SUPPORTED
24 #include "core/components_ng/pattern/window_scene/scene/system_window_scene.h"
25 #endif
26 #include "core/pipeline_ng/pipeline_context.h"
27
28 namespace OHOS::Ace::NG {
29 namespace {
GetTagFromRootNodeType(RootNodeType rootNodeType)30 std::string GetTagFromRootNodeType(RootNodeType rootNodeType)
31 {
32 switch (rootNodeType) {
33 case RootNodeType::PAGE_ETS_TAG:
34 return V2::PAGE_ETS_TAG;
35 case RootNodeType::NAVDESTINATION_VIEW_ETS_TAG:
36 return V2::NAVDESTINATION_VIEW_ETS_TAG;
37 case RootNodeType::WINDOW_SCENE_ETS_TAG:
38 return V2::WINDOW_SCENE_ETS_TAG;
39 default:
40 return V2::PAGE_ETS_TAG;
41 }
42 }
43
44 #ifdef WINDOW_SCENE_SUPPORTED
FindTargetNodeOverlay(RefPtr<UINode> & parent,const RefPtr<FrameNode> & targetNode,bool isShow)45 RefPtr<OverlayManager> FindTargetNodeOverlay(RefPtr<UINode>& parent,
46 const RefPtr<FrameNode>& targetNode, bool isShow)
47 {
48 auto node = AceType::DynamicCast<FrameNode>(parent);
49 CHECK_NULL_RETURN(node, nullptr);
50 auto pattern = node->GetPattern<SystemWindowScene>();
51 CHECK_NULL_RETURN(pattern, nullptr);
52 pattern->CreateOverlayManager(isShow, targetNode);
53 auto overlay = pattern->GetOverlayManager();
54 CHECK_NULL_RETURN(overlay, nullptr);
55 targetNode->SetRootNodeId(node->GetId());
56 targetNode->SetRootNodeType(RootNodeType::WINDOW_SCENE_ETS_TAG);
57 return overlay;
58 }
59 #endif
60
GetOverlayAndTargetNode(int32_t targetId,const SheetStyle & sheetStyle,int32_t sheetContentNodeId,RefPtr<OverlayManager> & overlayManager,RefPtr<FrameNode> & targetNode)61 int32_t GetOverlayAndTargetNode(int32_t targetId, const SheetStyle& sheetStyle, int32_t sheetContentNodeId,
62 RefPtr<OverlayManager>& overlayManager, RefPtr<FrameNode>& targetNode)
63 {
64 bool showInPage = sheetStyle.showInPage.value_or(false);
65 if (targetId < 0) {
66 return ERROR_CODE_NO_ERROR;
67 }
68 targetNode = ElementRegister::GetInstance()->GetSpecificItemById<FrameNode>(targetId);
69 if (targetNode == nullptr) {
70 TAG_LOGE(AceLogTag::ACE_SHEET, "TargetId does not exist.");
71 return ERROR_CODE_TARGET_ID_NOT_EXIST;
72 }
73 if (showInPage) {
74 if (!targetNode->IsOnMainTree()) {
75 TAG_LOGE(AceLogTag::ACE_SHEET, "TargetNode does not on main tree.");
76 return ERROR_CODE_TARGET_NOT_ON_MAIN_TREE;
77 }
78 overlayManager = SheetManager::FindPageNodeOverlay(targetNode, true, true);
79 CHECK_NULL_RETURN(overlayManager, ERROR_CODE_TARGET_NOT_PAGE_CHILD);
80 }
81 // delete Sheet when target node destroy
82 auto destructor =
83 [id = targetNode->GetId(), rootNodeId = targetNode->GetRootNodeId(),
84 rootNodeType = targetNode->GetRootNodeType(), showInPage = sheetStyle.showInPage.value_or(false),
85 instanceId = sheetStyle.instanceId.value_or(Container::CurrentId()), sheetContentNodeId]() {
86 ContainerScope scope(instanceId);
87 SheetManager::GetInstance().CleanBindSheetMap(instanceId, sheetContentNodeId);
88 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
89 CHECK_NULL_VOID(pipelineContext);
90 auto overlayManager = pipelineContext->GetOverlayManager();
91 if (showInPage) {
92 TAG_LOGD(AceLogTag::ACE_SHEET, "To showInPage, get overlayManager from GetOverlayFromPage");
93 overlayManager = SheetManager::GetOverlayFromPage(rootNodeId, rootNodeType);
94 }
95 CHECK_NULL_VOID(overlayManager);
96 overlayManager->DeleteModal(id);
97 };
98 targetNode->PushDestroyCallback(destructor);
99 return ERROR_CODE_NO_ERROR;
100 }
101 } // namespace
102
103 SheetManager::SheetManager() = default;
104
105 SheetManager::~SheetManager() = default;
106
OpenBindSheetByUIContext(const RefPtr<NG::FrameNode> & sheetContentNode,std::function<void ()> && titleBuildFunc,NG::SheetStyle & sheetStyle,std::function<void ()> && onAppear,std::function<void ()> && onDisappear,std::function<void ()> && shouldDismiss,std::function<void (const int32_t info)> && onWillDismiss,std::function<void ()> && onWillAppear,std::function<void ()> && onWillDisappear,std::function<void (const float)> && onHeightDidChange,std::function<void (const float)> && onDetentsDidChange,std::function<void (const float)> && onWidthDidChange,std::function<void (const float)> && onTypeDidChange,std::function<void ()> && sheetSpringBack,int32_t currentInstanceId,int32_t targetId)107 int32_t SheetManager::OpenBindSheetByUIContext(
108 const RefPtr<NG::FrameNode>& sheetContentNode, std::function<void()>&& titleBuildFunc, NG::SheetStyle& sheetStyle,
109 std::function<void()>&& onAppear, std::function<void()>&& onDisappear, std::function<void()>&& shouldDismiss,
110 std::function<void(const int32_t info)>&& onWillDismiss, std::function<void()>&& onWillAppear,
111 std::function<void()>&& onWillDisappear, std::function<void(const float)>&& onHeightDidChange,
112 std::function<void(const float)>&& onDetentsDidChange, std::function<void(const float)>&& onWidthDidChange,
113 std::function<void(const float)>&& onTypeDidChange, std::function<void()>&& sheetSpringBack,
114 int32_t currentInstanceId, int32_t targetId)
115 {
116 CHECK_NULL_RETURN(sheetContentNode, ERROR_CODE_BIND_SHEET_CONTENT_ERROR);
117 SheetContentKey sheetContentKey(currentInstanceId, sheetContentNode->GetId());
118 if (overlayManagerMap_.find(sheetContentKey) != overlayManagerMap_.end()) {
119 return ERROR_CODE_BIND_SHEET_CONTENT_ALREADY_EXIST;
120 }
121 auto buildTitleNodeFunc = [titleBuildFunc]() -> RefPtr<UINode> {
122 CHECK_NULL_RETURN(titleBuildFunc, nullptr);
123 NG::ScopedViewStackProcessor builderViewStackProcess;
124 titleBuildFunc();
125 auto customNode = NG::ViewStackProcessor::GetInstance()->Finish();
126 return customNode;
127 };
128
129 auto context = AceType::Claim(sheetContentNode->GetContext());
130 CHECK_NULL_RETURN(context, ERROR_CODE_INTERNAL_ERROR);
131 auto overlayManager = context->GetOverlayManager();
132 CHECK_NULL_RETURN(overlayManager, ERROR_CODE_INTERNAL_ERROR);
133
134 if (targetId < 0) {
135 sheetStyle.showInPage = false;
136 }
137
138 RefPtr<FrameNode> targetNode = AceType::DynamicCast<FrameNode>(overlayManager->GetRootNode().Upgrade());
139 auto retErrorCode =
140 GetOverlayAndTargetNode(targetId, sheetStyle, sheetContentNode->GetId(), overlayManager, targetNode);
141 if (retErrorCode) {
142 TAG_LOGE(AceLogTag::ACE_SHEET, "GetOverlayAndTargetNode failed errCode: %{public}d", retErrorCode);
143 return retErrorCode;
144 }
145 overlayManagerMap_.emplace(sheetContentKey, overlayManager);
146 targetIdMap_.emplace(sheetContentKey, targetId);
147
148 auto cleanMapFunc = [](const int32_t instanceId, const int32_t sheetContentNodeId) {
149 SheetManager::GetInstance().CleanBindSheetMap(instanceId, sheetContentNodeId);
150 };
151
152 overlayManager->OpenBindSheetByUIContext(sheetContentNode, std::move(buildTitleNodeFunc),
153 sheetStyle, std::move(onAppear), std::move(onDisappear), std::move(shouldDismiss), std::move(onWillDismiss),
154 std::move(onWillAppear), std::move(onWillDisappear), std::move(onHeightDidChange),
155 std::move(onDetentsDidChange), std::move(onWidthDidChange), std::move(onTypeDidChange),
156 std::move(sheetSpringBack), std::move(cleanMapFunc), targetNode);
157 return ERROR_CODE_NO_ERROR;
158 }
159
UpdateBindSheetByUIContext(const RefPtr<NG::FrameNode> & sheetContentNode,NG::SheetStyle & sheetStyle,bool isPartialUpdate,int32_t currentInstanceId)160 int32_t SheetManager::UpdateBindSheetByUIContext(const RefPtr<NG::FrameNode>& sheetContentNode,
161 NG::SheetStyle& sheetStyle, bool isPartialUpdate, int32_t currentInstanceId)
162 {
163 CHECK_NULL_RETURN(sheetContentNode, ERROR_CODE_BIND_SHEET_CONTENT_ERROR);
164 SheetContentKey sheetContentKey(currentInstanceId, sheetContentNode->GetId());
165 auto iter = overlayManagerMap_.find(sheetContentKey);
166 if (iter != overlayManagerMap_.end() && targetIdMap_.find(sheetContentKey) != targetIdMap_.end()) {
167 auto overlayManager = iter->second;
168 overlayManager->UpdateBindSheetByUIContext(
169 sheetContentNode, sheetStyle, targetIdMap_[sheetContentKey], isPartialUpdate);
170 return ERROR_CODE_NO_ERROR;
171 }
172 return ERROR_CODE_BIND_SHEET_CONTENT_NOT_FOUND;
173 }
174
CloseBindSheetByUIContext(const RefPtr<NG::FrameNode> & sheetContentNode,int32_t currentInstanceId)175 int32_t SheetManager::CloseBindSheetByUIContext(
176 const RefPtr<NG::FrameNode>& sheetContentNode, int32_t currentInstanceId)
177 {
178 CHECK_NULL_RETURN(sheetContentNode, ERROR_CODE_BIND_SHEET_CONTENT_ERROR);
179 SheetContentKey sheetContentKey(currentInstanceId, sheetContentNode->GetId());
180 auto iter = overlayManagerMap_.find(sheetContentKey);
181 if (iter != overlayManagerMap_.end() && targetIdMap_.find(sheetContentKey) != targetIdMap_.end()) {
182 auto overlayManager = iter->second;
183 overlayManager->CloseBindSheetByUIContext(sheetContentNode, targetIdMap_[sheetContentKey]);
184 return ERROR_CODE_NO_ERROR;
185 }
186 return ERROR_CODE_BIND_SHEET_CONTENT_NOT_FOUND;
187 }
188
DeleteOverlayForWindowScene(int32_t rootNodeId,RootNodeType rootNodeType)189 void SheetManager::DeleteOverlayForWindowScene(int32_t rootNodeId, RootNodeType rootNodeType)
190 {
191 #ifdef WINDOW_SCENE_SUPPORTED
192 if (rootNodeType == RootNodeType::WINDOW_SCENE_ETS_TAG) {
193 auto windowSceneNode = FrameNode::GetFrameNode(V2::WINDOW_SCENE_ETS_TAG, rootNodeId);
194 CHECK_NULL_VOID(windowSceneNode);
195 auto pattern = windowSceneNode->GetPattern<SystemWindowScene>();
196 CHECK_NULL_VOID(pattern);
197 pattern->DeleteOverlayManager();
198 }
199 #endif
200 }
201
FindPageNodeOverlay(const RefPtr<FrameNode> & targetNode,bool isShow,bool isStartByUIContext)202 RefPtr<OverlayManager> SheetManager::FindPageNodeOverlay(
203 const RefPtr<FrameNode>& targetNode, bool isShow, bool isStartByUIContext)
204 {
205 CHECK_NULL_RETURN(targetNode, nullptr);
206 if (targetNode->GetRootNodeId() > 0 && !isStartByUIContext) {
207 return SheetManager::GetOverlayFromPage(targetNode->GetRootNodeId(), targetNode->GetRootNodeType());
208 }
209 auto isNav = false;
210 RefPtr<OverlayManager> overlay;
211 RefPtr<UINode> parent = targetNode;
212 while (parent) {
213 if (parent->GetTag() == V2::PAGE_ETS_TAG) {
214 auto node = AceType::DynamicCast<FrameNode>(parent);
215 CHECK_NULL_RETURN(node, nullptr);
216 auto pattern = node->GetPattern<PagePattern>();
217 CHECK_NULL_RETURN(pattern, nullptr);
218 if (!isNav) {
219 pattern->CreateOverlayManager(isShow);
220 overlay = pattern->GetOverlayManager();
221 CHECK_NULL_RETURN(overlay, nullptr);
222 targetNode->SetRootNodeId(node->GetId());
223 targetNode->SetRootNodeType(RootNodeType::PAGE_ETS_TAG);
224 } else {
225 node->SetRootNodeType(RootNodeType::NAVDESTINATION_VIEW_ETS_TAG);
226 node->SetRootNodeId(targetNode->GetRootNodeId());
227 }
228 break;
229 }
230 if (parent->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG && !isNav) {
231 auto node = AceType::DynamicCast<FrameNode>(parent);
232 CHECK_NULL_RETURN(node, nullptr);
233 auto pattern = node->GetPattern<NavDestinationPattern>();
234 CHECK_NULL_RETURN(pattern, nullptr);
235 pattern->CreateOverlayManager(isShow);
236 overlay = pattern->GetOverlayManager();
237 CHECK_NULL_RETURN(overlay, nullptr);
238 targetNode->SetRootNodeId(node->GetId());
239 targetNode->SetRootNodeType(RootNodeType::NAVDESTINATION_VIEW_ETS_TAG);
240 isNav = true;
241 }
242 #ifdef WINDOW_SCENE_SUPPORTED
243 if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
244 overlay = FindTargetNodeOverlay(parent, targetNode, isShow);
245 break;
246 }
247 #endif
248 parent = parent->GetParent();
249 }
250 return overlay;
251 }
252
GetOverlayFromPage(int32_t rootNodeId,RootNodeType rootNodeType)253 RefPtr<OverlayManager> SheetManager::GetOverlayFromPage(int32_t rootNodeId, RootNodeType rootNodeType)
254 {
255 if (rootNodeId <= 0) {
256 return nullptr;
257 }
258 std::string tag = GetTagFromRootNodeType(rootNodeType);
259 auto frameNode = FrameNode::GetFrameNode(tag, rootNodeId);
260 CHECK_NULL_RETURN(frameNode, nullptr);
261 if (tag == V2::PAGE_ETS_TAG) {
262 auto node = AceType::DynamicCast<FrameNode>(frameNode);
263 CHECK_NULL_RETURN(node, nullptr);
264 auto pattern = node->GetPattern<PagePattern>();
265 return pattern->GetOverlayManager();
266 }
267 if (tag == V2::NAVDESTINATION_VIEW_ETS_TAG) {
268 auto node = AceType::DynamicCast<FrameNode>(frameNode);
269 CHECK_NULL_RETURN(node, nullptr);
270 auto pattern = node->GetPattern<NavDestinationPattern>();
271 CHECK_NULL_RETURN(pattern, nullptr);
272 return pattern->GetOverlayManager();
273 }
274 #ifdef WINDOW_SCENE_SUPPORTED
275 if (tag == V2::WINDOW_SCENE_ETS_TAG) {
276 auto node = AceType::DynamicCast<FrameNode>(frameNode);
277 CHECK_NULL_RETURN(node, nullptr);
278 auto pattern = node->GetPattern<SystemWindowScene>();
279 CHECK_NULL_RETURN(pattern, nullptr);
280 return pattern->GetOverlayManager();
281 }
282 #endif
283 return nullptr;
284 }
285 } // namespace OHOS::Ace::NG
286