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