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 #include "safe_area_manager.h"
16
17 #include "base/utils/utils.h"
18 #include "core/components/container_modal/container_modal_constants.h"
19 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
20 #include "core/components_ng/pattern/stage/page_pattern.h"
21 #include "core/components_ng/property/safe_area_insets.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23
24 namespace OHOS::Ace::NG {
GenerateCutOutAreaWithRoot(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)25 SafeAreaInsets GenerateCutOutAreaWithRoot(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
26 {
27 auto pipeline = PipelineContext::GetCurrentContext();
28 CHECK_NULL_RETURN(pipeline, {});
29 CHECK_NULL_RETURN(pipeline->GetUseCutout(), {});
30 // cutout regions adjacent to edges.
31 auto cutoutArea = safeArea;
32
33 if (cutoutArea.top_.IsValid()) {
34 cutoutArea.top_.start = 0;
35 }
36 if (safeArea.bottom_.IsValid()) {
37 cutoutArea.bottom_.end = rootSize.Height().has_value() ? rootSize.Height().value()
38 : PipelineContext::GetCurrentRootHeight();
39 }
40 if (cutoutArea.left_.IsValid()) {
41 cutoutArea.left_.start = 0;
42 }
43 if (cutoutArea.right_.IsValid()) {
44 cutoutArea.right_.end = rootSize.Width().has_value() ? rootSize.Width().value()
45 : PipelineContext::GetCurrentRootWidth();
46 }
47 return cutoutArea;
48 }
49
CheckCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)50 bool SafeAreaManager::CheckCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
51 {
52 return cutoutSafeArea_ != GenerateCutOutAreaWithRoot(safeArea, rootSize);
53 }
54
UpdateCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)55 bool SafeAreaManager::UpdateCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
56 {
57 auto safeAreaWithRoot = GenerateCutOutAreaWithRoot(safeArea, rootSize);
58 if (cutoutSafeArea_ == safeAreaWithRoot) {
59 return false;
60 }
61 ACE_SCOPED_TRACE("SafeAreaManager::UpdateCutoutSafeArea %s", safeAreaWithRoot.ToString().c_str());
62 cutoutSafeArea_ = safeAreaWithRoot;
63 return true;
64 }
65
CheckSystemSafeArea(const SafeAreaInsets & safeArea)66 bool SafeAreaManager::CheckSystemSafeArea(const SafeAreaInsets& safeArea)
67 {
68 return systemSafeArea_ != safeArea;
69 }
70
UpdateSystemSafeArea(const SafeAreaInsets & safeArea)71 bool SafeAreaManager::UpdateSystemSafeArea(const SafeAreaInsets& safeArea)
72 {
73 if (systemSafeArea_ == safeArea) {
74 return false;
75 }
76 ACE_SCOPED_TRACE("SafeAreaManager::UpdateSystemSafeArea %s", safeArea.ToString().c_str());
77 systemSafeArea_ = safeArea;
78 return true;
79 }
80
CheckNavArea(const SafeAreaInsets & safeArea)81 bool SafeAreaManager::CheckNavArea(const SafeAreaInsets& safeArea)
82 {
83 return navSafeArea_ != safeArea;
84 }
85
UpdateNavArea(const SafeAreaInsets & safeArea)86 bool SafeAreaManager::UpdateNavArea(const SafeAreaInsets& safeArea)
87 {
88 if (navSafeArea_ == safeArea) {
89 return false;
90 }
91 ACE_SCOPED_TRACE("SafeAreaManager::UpdateNavArea %s", safeArea.ToString().c_str());
92 navSafeArea_ = safeArea;
93 return true;
94 }
95
UpdateKeyboardSafeArea(float keyboardHeight,std::optional<uint32_t> rootHeight)96 bool SafeAreaManager::UpdateKeyboardSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight)
97 {
98 uint32_t bottom;
99 if (systemSafeArea_.bottom_.IsValid()) {
100 bottom = systemSafeArea_.bottom_.start;
101 } else {
102 bottom = rootHeight.has_value() ? rootHeight.value() : PipelineContext::GetCurrentRootHeight();
103 }
104 SafeAreaInsets::Inset inset = { .start = bottom - keyboardHeight, .end = bottom };
105 if (inset == keyboardInset_) {
106 return false;
107 }
108 keyboardInset_ = inset;
109 return true;
110 }
111
GetCombinedSafeArea(const SafeAreaExpandOpts & opts) const112 SafeAreaInsets SafeAreaManager::GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const
113 {
114 SafeAreaInsets res;
115 if (!IsSafeAreaValid()) {
116 return {};
117 }
118 if (opts.type & SAFE_AREA_TYPE_CUTOUT) {
119 res = res.Combine(cutoutSafeArea_);
120 }
121 if (opts.type & SAFE_AREA_TYPE_SYSTEM) {
122 res = res.Combine(systemSafeArea_).Combine(navSafeArea_);
123 }
124 if (keyboardSafeAreaEnabled_ && (opts.type & SAFE_AREA_TYPE_KEYBOARD)) {
125 res.bottom_ = res.bottom_.Combine(keyboardInset_);
126 }
127 return res;
128 }
129
IsSafeAreaValid() const130 bool SafeAreaManager::IsSafeAreaValid() const
131 {
132 #ifdef PREVIEW
133 return !ignoreSafeArea_;
134 #else
135 return !(ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_));
136 #endif
137 }
138
SetIsFullScreen(bool value)139 bool SafeAreaManager::SetIsFullScreen(bool value)
140 {
141 if (isFullScreen_ == value) {
142 return false;
143 }
144 isFullScreen_ = value;
145 LOGI("SafeAreaManager::SetIsFullScreen %{public}d", isFullScreen_);
146 return true;
147 }
148
SetIsNeedAvoidWindow(bool value)149 bool SafeAreaManager::SetIsNeedAvoidWindow(bool value)
150 {
151 if (isNeedAvoidWindow_ == value) {
152 return false;
153 }
154 isNeedAvoidWindow_ = value;
155 LOGI("SafeAreaManager::SetIsNeedAvoidWindow %{public}d", isNeedAvoidWindow_);
156 return true;
157 }
158
SetIgnoreSafeArea(bool value)159 bool SafeAreaManager::SetIgnoreSafeArea(bool value)
160 {
161 if (ignoreSafeArea_ == value) {
162 return false;
163 }
164 ignoreSafeArea_ = value;
165 LOGI("SafeAreaManager::SetIgnoreSafeArea %{public}d", ignoreSafeArea_);
166 return true;
167 }
168
SetKeyBoardAvoidMode(bool value)169 bool SafeAreaManager::SetKeyBoardAvoidMode(bool value)
170 {
171 if (keyboardSafeAreaEnabled_ == value) {
172 return false;
173 }
174 keyboardSafeAreaEnabled_ = value;
175 LOGI("SafeAreaManager::SetKeyBoardAvoidMode %{public}d", keyboardSafeAreaEnabled_);
176 return true;
177 }
178
SetIsAtomicService(bool value)179 bool SafeAreaManager::SetIsAtomicService(bool value)
180 {
181 if (isAtomicService_ == value) {
182 return false;
183 }
184 isAtomicService_ = value;
185 LOGI("SafeAreaManager::SetIsAtomicService %{public}d", isAtomicService_);
186 return true;
187 }
188
IsAtomicService() const189 bool SafeAreaManager::IsAtomicService() const
190 {
191 return isAtomicService_;
192 }
193
GetSystemSafeArea() const194 SafeAreaInsets SafeAreaManager::GetSystemSafeArea() const
195 {
196 return systemSafeArea_;
197 }
198
GetCutoutSafeArea() const199 SafeAreaInsets SafeAreaManager::GetCutoutSafeArea() const
200 {
201 if (!IsSafeAreaValid()) {
202 return {};
203 }
204 return cutoutSafeArea_;
205 }
206
GetSafeArea() const207 SafeAreaInsets SafeAreaManager::GetSafeArea() const
208 {
209 if (!IsSafeAreaValid()) {
210 return {};
211 }
212 return systemSafeArea_.Combine(cutoutSafeArea_).Combine(navSafeArea_);
213 }
214
GetSafeAreaWithoutCutout() const215 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutCutout() const
216 {
217 if (!IsSafeAreaValid()) {
218 return {};
219 }
220 return systemSafeArea_.Combine(navSafeArea_);
221 }
222
GetSafeAreaWithoutProcess() const223 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutProcess() const
224 {
225 return systemSafeArea_.Combine(cutoutSafeArea_).Combine(navSafeArea_);
226 }
227
GetKeyboardOffset() const228 float SafeAreaManager::GetKeyboardOffset() const
229 {
230 if (keyboardSafeAreaEnabled_) {
231 return 0.0f;
232 }
233 return keyboardOffset_;
234 }
235
GetWindowWrapperOffset()236 OffsetF SafeAreaManager::GetWindowWrapperOffset()
237 {
238 auto pipelineContext = PipelineContext::GetCurrentContext();
239 CHECK_NULL_RETURN(pipelineContext, OffsetF());
240 auto windowManager = pipelineContext->GetWindowManager();
241 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
242 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
243 if (isContainerModal) {
244 auto wrapperOffset = OffsetF(static_cast<float>((CONTAINER_BORDER_WIDTH + CONTENT_PADDING).ConvertToPx()),
245 static_cast<float>((pipelineContext->GetCustomTitleHeight() + CONTAINER_BORDER_WIDTH).ConvertToPx()));
246 return wrapperOffset;
247 }
248 return OffsetF();
249 }
250
ExpandSafeArea()251 void SafeAreaManager::ExpandSafeArea()
252 {
253 ACE_SCOPED_TRACE("ExpandSafeArea node count %zu, IsSafeAreaValid: %d, ignoreSafeArea: %d, isFullScreen: %d, "
254 "isNeedAvoidWindow %d",
255 needExpandNodes_.size(), IsSafeAreaValid(), ignoreSafeArea_, isFullScreen_, isNeedAvoidWindow_);
256 auto pipeline = PipelineContext::GetCurrentContext();
257 CHECK_NULL_VOID(pipeline);
258 auto manager = pipeline->GetSafeAreaManager();
259 auto iter = needExpandNodes_.begin();
260 while (iter != needExpandNodes_.end()) {
261 auto frameNode = (*iter).Upgrade();
262 if (frameNode) {
263 manager->AddGeoRestoreNode(frameNode);
264 frameNode->ExpandSafeArea();
265 }
266 ++iter;
267 }
268 ClearNeedExpandNode();
269 }
270
AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode> & node)271 bool SafeAreaManager::AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
272 {
273 if (needExpandNodes_.find(node) == needExpandNodes_.end()) {
274 AddNeedExpandNode(node);
275 return true;
276 }
277 return false;
278 }
279
CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode> & frameNode)280 bool SafeAreaManager::CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode)
281 {
282 if (frameNode->GetTag() != V2::PAGE_ETS_TAG) {
283 return false;
284 }
285 // page will not avoid keyboard when lastChild is sheet
286 RefPtr<OverlayManager> overlay;
287 if (frameNode->RootNodeIsPage()) {
288 auto pattern = frameNode->GetPattern<PagePattern>();
289 CHECK_NULL_RETURN(pattern, true);
290 overlay = pattern->GetOverlayManager();
291 } else {
292 auto navNode = FrameNode::GetFrameNode(V2::NAVDESTINATION_VIEW_ETS_TAG, frameNode->GetRootNodeId());
293 CHECK_NULL_RETURN(navNode, true);
294 auto pattern = navNode->GetPattern<NavDestinationPattern>();
295 CHECK_NULL_RETURN(pattern, true);
296 overlay = pattern->GetOverlayManager();
297 }
298 CHECK_NULL_RETURN(overlay, true);
299 return overlay->CheckPageNeedAvoidKeyboard();
300 }
301 } // namespace OHOS::Ace::NG
302