• 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/pattern/overlay/sheet_manager.h"
17 
18 #include "base/error/error_code.h"
19 #include "base/subwindow/subwindow_manager.h"
20 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
21 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
22 #include "core/components_ng/pattern/overlay/sheet_wrapper_pattern.h"
23 #include "core/components_ng/pattern/sheet/sheet_mask_pattern.h"
24 #ifdef WINDOW_SCENE_SUPPORTED
25 #include "core/components_ng/pattern/window_scene/scene/system_window_scene.h"
26 #endif
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->PushDestroyCallbackWithTag(destructor, V2::SHEET_WRAPPER_TAG);
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,const NG::SheetStyle & sheetStyle,bool isPartialUpdate,int32_t currentInstanceId)160 int32_t SheetManager::UpdateBindSheetByUIContext(const RefPtr<NG::FrameNode>& sheetContentNode,
161     const 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 
RemoveSheetByESC()286 bool SheetManager::RemoveSheetByESC()
287 {
288     if (!sheetFocusId_.has_value()) {
289         TAG_LOGE(AceLogTag::ACE_SHEET, "focus sheet id is null, can't respond to esc");
290         return false;
291     }
292     auto sheetNode = FrameNode::GetFrameNode(V2::SHEET_PAGE_TAG, sheetFocusId_.value());
293     CHECK_NULL_RETURN(sheetNode, false);
294     auto sheetPattern = sheetNode->GetPattern<SheetPresentationPattern>();
295     CHECK_NULL_RETURN(sheetPattern, false);
296     if (sheetPattern->GetAnimationProcess()) {
297         TAG_LOGW(AceLogTag::ACE_SHEET, "sheet is closing by esc");
298         return false;
299     }
300     auto overlayManager = sheetPattern->GetOverlayManager();
301     CHECK_NULL_RETURN(overlayManager, false);
302     TAG_LOGI(AceLogTag::ACE_SHEET, "sheet will close by esc, id is : %{public}d", sheetFocusId_.value());
303     return overlayManager->RemoveModalInOverlay();
304 }
305 
CloseSheetInSubWindow(const SheetKey & sheetKey)306 void SheetManager::CloseSheetInSubWindow(const SheetKey& sheetKey)
307 {
308     auto instanceId = Container::CurrentId();
309     TAG_LOGD(AceLogTag::ACE_SHEET, "close sheet in subwindow by user defined");
310     auto manager = SubwindowManager::GetInstance();
311     CHECK_NULL_VOID(manager);
312     auto parentId = manager->GetParentContainerId(instanceId);
313 #ifdef OHOS_STANDARD_SYSTEM
314     auto subwindow = manager->GetSubwindowByType(instanceId >= MIN_SUBCONTAINER_ID ?
315         parentId : instanceId, SubwindowType::TYPE_SHEET);
316 #else
317     auto subwindow = manager->GetSubwindowByType(parentId != INVALID_SUBWINDOW_ID ?
318         parentId : instanceId, SubwindowType::TYPE_SHEET);
319 #endif
320     CHECK_NULL_VOID(subwindow);
321     auto overlay = subwindow->GetOverlayManager();
322     CHECK_NULL_VOID(overlay);
323     overlay->CloseSheet(sheetKey);
324 }
325 
SetMaskInteractive(const RefPtr<FrameNode> & maskNode,bool isInteractive)326 void SheetManager::SetMaskInteractive(const RefPtr<FrameNode>& maskNode, bool isInteractive)
327 {
328     auto maskPattern = maskNode->GetPattern<SheetMaskPattern>();
329     if (maskPattern) {
330         maskPattern->SetIsMaskInteractive(isInteractive);
331     }
332 }
333 
RegisterDestroyCallback(const RefPtr<FrameNode> & targetNode,NG::SheetStyle & sheetStyle,const int32_t containerId)334 void SheetManager::RegisterDestroyCallback(const RefPtr<FrameNode>& targetNode, NG::SheetStyle& sheetStyle,
335     const int32_t containerId)
336 {
337     auto destructor = [id = targetNode->GetId(), rootNodeId = targetNode->GetRootNodeId(),
338         rootNodeType = targetNode->GetRootNodeType(),
339         showInPage = sheetStyle.showInPage.value_or(false), containerId]() {
340         ContainerScope scope(containerId);
341         auto pipeline = NG::PipelineContext::GetCurrentContext();
342         CHECK_NULL_VOID(pipeline);
343         auto overlayManager = pipeline->GetOverlayManager();
344         if (showInPage) {
345             TAG_LOGD(AceLogTag::ACE_SHEET, "To showInPage, get overlayManager from GetOverlayFromPage");
346             overlayManager = SheetManager::GetOverlayFromPage(rootNodeId, rootNodeType);
347         }
348         CHECK_NULL_VOID(overlayManager);
349         overlayManager->DeleteModal(id);
350         SheetManager::GetInstance().DeleteOverlayForWindowScene(rootNodeId, rootNodeType);
351         SheetManager::GetInstance().CloseSheetInSubWindow(SheetKey(id));
352     };
353     targetNode->PushDestroyCallbackWithTag(destructor, V2::SHEET_WRAPPER_TAG);
354 }
355 
CreateBreakPointState(WidthBreakpoint width,HeightBreakpoint height)356 std::unique_ptr<State> SheetManager::CreateBreakPointState(WidthBreakpoint width,
357     HeightBreakpoint height)
358 {
359     if (width == WidthBreakpoint::WIDTH_XS) {
360         return std::make_unique<WidthXSState>();
361     }
362     if (width == WidthBreakpoint::WIDTH_SM) {
363         return std::make_unique<WidthSMState>();
364     }
365     if (width == WidthBreakpoint::WIDTH_MD && height == HeightBreakpoint::HEIGHT_SM) {
366         return std::make_unique<WidthMDHeightSMState>();
367     }
368     if (width == WidthBreakpoint::WIDTH_MD &&
369         (height == HeightBreakpoint::HEIGHT_MD || height == HeightBreakpoint::HEIGHT_LG)) {
370         return std::make_unique<WidthMDHeightMDOrLGState>();
371     }
372     if (width == WidthBreakpoint::WIDTH_XL || width == WidthBreakpoint::WIDTH_LG) {
373         return std::make_unique<WidthLGState>();
374     }
375     return nullptr;
376 }
377 } // namespace OHOS::Ace::NG
378