• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/components/container_modal/container_modal_constants.h"
18 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
19 
20 namespace OHOS::Ace::NG {
GenerateCutOutAreaWithRoot(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)21 SafeAreaInsets GenerateCutOutAreaWithRoot(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
22 {
23     // cutout regions adjacent to edges.
24     auto cutoutArea = safeArea;
25 
26     if (cutoutArea.top_.IsValid()) {
27         cutoutArea.top_.start = 0;
28     }
29     if (cutoutArea.bottom_.IsValid()) {
30         cutoutArea.bottom_.end = rootSize.Height().has_value() ? rootSize.Height().value()
31                                                                : PipelineContext::GetCurrentRootHeight();
32     }
33     if (cutoutArea.left_.IsValid()) {
34         cutoutArea.left_.start = 0;
35     }
36     if (cutoutArea.right_.IsValid()) {
37         cutoutArea.right_.end = rootSize.Width().has_value() ? rootSize.Width().value()
38                                                              : PipelineContext::GetCurrentRootWidth();
39     }
40     return cutoutArea;
41 }
42 
CheckCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)43 bool SafeAreaManager::CheckCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
44 {
45     return cutoutSafeArea_ != GenerateCutOutAreaWithRoot(safeArea, rootSize);
46 }
47 
UpdateCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)48 bool SafeAreaManager::UpdateCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
49 {
50     auto safeAreaWithRoot = GenerateCutOutAreaWithRoot(safeArea, rootSize);
51     if (cutoutSafeArea_ == safeAreaWithRoot) {
52         return false;
53     }
54     ACE_SCOPED_TRACE("SafeAreaManager::UpdateCutoutSafeArea %s, safeAreaWithRoot %s", safeArea.ToString().c_str(),
55         safeAreaWithRoot.ToString().c_str());
56     cutoutSafeArea_ = safeAreaWithRoot;
57     return true;
58 }
59 
CheckSystemSafeArea(const SafeAreaInsets & safeArea)60 bool SafeAreaManager::CheckSystemSafeArea(const SafeAreaInsets& safeArea)
61 {
62     return systemSafeArea_ != safeArea;
63 }
64 
UpdateSystemSafeArea(const SafeAreaInsets & safeArea)65 bool SafeAreaManager::UpdateSystemSafeArea(const SafeAreaInsets& safeArea)
66 {
67     if (systemSafeArea_ == safeArea) {
68         return false;
69     }
70     ACE_SCOPED_TRACE("SafeAreaManager::UpdateSystemSafeArea %s", safeArea.ToString().c_str());
71     systemSafeArea_ = safeArea;
72     return true;
73 }
74 
CheckNavSafeArea(const SafeAreaInsets & safeArea)75 bool SafeAreaManager::CheckNavSafeArea(const SafeAreaInsets& safeArea)
76 {
77     return navSafeArea_ != safeArea;
78 }
79 
UpdateNavSafeArea(const SafeAreaInsets & safeArea)80 bool SafeAreaManager::UpdateNavSafeArea(const SafeAreaInsets& safeArea)
81 {
82     if (navSafeArea_ == safeArea) {
83         return false;
84     }
85     ACE_SCOPED_TRACE("SafeAreaManager::UpdateNavSafeArea %s", safeArea.ToString().c_str());
86     navSafeArea_ = safeArea;
87     return true;
88 }
89 
UpdateKeyboardSafeArea(float keyboardHeight,std::optional<uint32_t> rootHeight)90 bool SafeAreaManager::UpdateKeyboardSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight)
91 {
92     uint32_t bottom;
93     auto container = Container::Current();
94     if (container && systemSafeArea_.bottom_.IsValid() && !container->IsSceneBoardEnabled()) {
95         bottom = systemSafeArea_.bottom_.start;
96         ACE_SCOPED_TRACE("calc keyboardRect use systemSafeArea_.bottom_");
97     } else {
98         bottom = rootHeight.has_value() ? rootHeight.value() : PipelineContext::GetCurrentRootHeight();
99     }
100     SafeAreaInsets::Inset inset = { .start = bottom - keyboardHeight, .end = bottom };
101     if (inset == keyboardInset_) {
102         return false;
103     }
104     keyboardInset_ = inset;
105     ACE_SCOPED_TRACE("SafeAreaManager::UpdateKeyboardSafeArea %s", inset.ToString().c_str());
106     return true;
107 }
108 
GetCombinedSafeArea(const SafeAreaExpandOpts & opts) const109 SafeAreaInsets SafeAreaManager::GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const
110 {
111     SafeAreaInsets res;
112     if (!IsSafeAreaValid()) {
113         return {};
114     }
115     if ((opts.type & SAFE_AREA_TYPE_CUTOUT) && useCutout_) {
116         res = res.Combine(cutoutSafeArea_);
117     }
118     if (opts.type & SAFE_AREA_TYPE_SYSTEM) {
119         res = res.Combine(systemSafeArea_).Combine(navSafeArea_);
120     }
121     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
122         return res;
123     }
124     if ((keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
125         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET) && (opts.type & SAFE_AREA_TYPE_KEYBOARD)) {
126         res.bottom_ = res.bottom_.Combine(keyboardInset_);
127     }
128     return res;
129 }
130 
UpdateScbSystemSafeArea(const SafeAreaInsets & safeArea)131 bool SafeAreaManager::UpdateScbSystemSafeArea(const SafeAreaInsets& safeArea)
132 {
133     if (scbSystemSafeArea_.has_value() && scbSystemSafeArea_.value() == safeArea) {
134         return false;
135     }
136     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbSystemSafeArea %s", safeArea.ToString().c_str());
137     scbSystemSafeArea_ = safeArea;
138     return true;
139 }
140 
UpdateScbCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)141 bool SafeAreaManager::UpdateScbCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
142 {
143     auto safeAreaWithRoot = GenerateCutOutAreaWithRoot(safeArea, rootSize);
144     if (scbCutoutSafeArea_.has_value() && scbCutoutSafeArea_.value() == safeAreaWithRoot) {
145         return false;
146     }
147     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbCutoutSafeArea %s", safeAreaWithRoot.ToString().c_str());
148     scbCutoutSafeArea_ = safeAreaWithRoot;
149     return true;
150 }
151 
UpdateScbNavSafeArea(const SafeAreaInsets & safeArea)152 bool SafeAreaManager::UpdateScbNavSafeArea(const SafeAreaInsets& safeArea)
153 {
154     if (scbNavSafeArea_.has_value() && scbNavSafeArea_.value() == safeArea) {
155         return false;
156     }
157     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbNavSafeArea %s", safeArea.ToString().c_str());
158     scbNavSafeArea_ = safeArea;
159     return true;
160 }
161 
IsSafeAreaValid() const162 bool SafeAreaManager::IsSafeAreaValid() const
163 {
164 #ifdef PREVIEW
165     return !ignoreSafeArea_;
166 #else
167     return !(ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_));
168 #endif
169 }
170 
SetIsFullScreen(bool value)171 bool SafeAreaManager::SetIsFullScreen(bool value)
172 {
173     if (isFullScreen_ == value) {
174         return false;
175     }
176     isFullScreen_ = value;
177     TAG_LOGI(ACE_LAYOUT, "SetIsFullScreen %{public}d", isFullScreen_);
178     return true;
179 }
180 
SetIsNeedAvoidWindow(bool value)181 bool SafeAreaManager::SetIsNeedAvoidWindow(bool value)
182 {
183     if (isNeedAvoidWindow_ == value) {
184         return false;
185     }
186     isNeedAvoidWindow_ = value;
187     TAG_LOGI(ACE_LAYOUT, "SetIsNeedAvoidWindow %{public}d", isNeedAvoidWindow_);
188     return true;
189 }
190 
SetIgnoreSafeArea(bool value)191 bool SafeAreaManager::SetIgnoreSafeArea(bool value)
192 {
193     if (ignoreSafeArea_ == value) {
194         return false;
195     }
196     ignoreSafeArea_ = value;
197     TAG_LOGI(ACE_LAYOUT, "SetIgnoreSafeArea %{public}d", ignoreSafeArea_);
198     return true;
199 }
200 
SetKeyBoardAvoidMode(KeyBoardAvoidMode value)201 bool SafeAreaManager::SetKeyBoardAvoidMode(KeyBoardAvoidMode value)
202 {
203     if (keyboardAvoidMode_ == value) {
204         return false;
205     }
206     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE || value == KeyBoardAvoidMode::NONE) {
207         keyboardOffset_ = 0.0f;
208     }
209     keyboardAvoidMode_ = value;
210     keyboardSafeAreaEnabled_ = keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE
211         || keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET;
212     TAG_LOGI(ACE_LAYOUT, "SetKeyBoardAvoidMode %{public}d", keyboardAvoidMode_);
213     return true;
214 }
215 
GetKeyBoardAvoidMode()216 KeyBoardAvoidMode SafeAreaManager::GetKeyBoardAvoidMode()
217 {
218     return keyboardAvoidMode_;
219 }
220 
SetIsAtomicService(bool value)221 bool SafeAreaManager::SetIsAtomicService(bool value)
222 {
223     if (isAtomicService_ == value) {
224         return false;
225     }
226     isAtomicService_ = value;
227     TAG_LOGI(ACE_LAYOUT, "SetIsAtomicService %{public}d", isAtomicService_);
228     return true;
229 }
230 
IsAtomicService() const231 bool SafeAreaManager::IsAtomicService() const
232 {
233     return isAtomicService_;
234 }
235 
GetSystemSafeArea() const236 SafeAreaInsets SafeAreaManager::GetSystemSafeArea() const
237 {
238     if (windowTypeConfig_.isSceneBoardWindow && scbSystemSafeArea_.has_value()) {
239         return scbSystemSafeArea_.value();
240     }
241     return systemSafeArea_;
242 }
243 
GetCutoutSafeArea() const244 SafeAreaInsets SafeAreaManager::GetCutoutSafeArea() const
245 {
246     if (IsSafeAreaValid() && useCutout_) {
247         if (windowTypeConfig_.isSceneBoardWindow && scbCutoutSafeArea_.has_value()) {
248             return scbCutoutSafeArea_.value();
249         }
250         return cutoutSafeArea_;
251     }
252     return {};
253 }
254 
GetCutoutSafeAreaWithoutProcess() const255 SafeAreaInsets SafeAreaManager::GetCutoutSafeAreaWithoutProcess() const
256 {
257     if (windowTypeConfig_.isSceneBoardWindow && scbCutoutSafeArea_.has_value()) {
258         return scbCutoutSafeArea_.value();
259     }
260     return cutoutSafeArea_;
261 }
262 
GetSafeArea() const263 SafeAreaInsets SafeAreaManager::GetSafeArea() const
264 {
265     if (!IsSafeAreaValid()) {
266         return {};
267     }
268     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
269     return systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
270 }
271 
GetSafeAreaWithoutCutout() const272 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutCutout() const
273 {
274     if (!IsSafeAreaValid()) {
275         return {};
276     }
277     return systemSafeArea_.Combine(navSafeArea_);
278 }
279 
GetSafeAreaWithoutProcess() const280 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutProcess() const
281 {
282     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
283     if (!windowTypeConfig_.isSceneBoardWindow) {
284         return systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
285     }
286     SafeAreaInsets scbSafeArea;
287     if (scbSystemSafeArea_.has_value()) {
288         scbSafeArea = scbSafeArea.Combine(scbSystemSafeArea_.value());
289     }
290     if (scbCutoutSafeArea_.has_value() && useCutout_) {
291         scbSafeArea = scbSafeArea.Combine(scbCutoutSafeArea_.value());
292     }
293     if (scbNavSafeArea_.has_value()) {
294         scbSafeArea = scbSafeArea.Combine(scbNavSafeArea_.value());
295     }
296     return scbSafeArea;
297 }
298 
SafeAreaToPadding(bool withoutProcess)299 PaddingPropertyF SafeAreaManager::SafeAreaToPadding(bool withoutProcess)
300 {
301     if (!withoutProcess) {
302 #ifdef PREVIEW
303         if (ignoreSafeArea_) {
304             return {};
305         }
306 #else
307         if (ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_)) {
308             return {};
309         }
310 #endif
311     }
312     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
313     auto combinedSafeArea = systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
314     PaddingPropertyF result;
315     if (combinedSafeArea.left_.IsValid()) {
316         result.left = combinedSafeArea.left_.Length();
317     }
318     if (combinedSafeArea.top_.IsValid()) {
319         result.top = combinedSafeArea.top_.Length();
320     }
321     if (combinedSafeArea.right_.IsValid()) {
322         result.right = combinedSafeArea.right_.Length();
323     }
324     if (combinedSafeArea.bottom_.IsValid()) {
325         result.bottom = combinedSafeArea.bottom_.Length();
326     }
327     return result;
328 }
329 
GetKeyboardOffset(bool withoutProcess) const330 float SafeAreaManager::GetKeyboardOffset(bool withoutProcess) const
331 {
332     if (withoutProcess) {
333         return keyboardOffset_;
334     }
335     if (keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
336         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET ||
337         keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
338         return 0.0f;
339     }
340     return keyboardOffset_;
341 }
342 
GetWindowWrapperOffset()343 OffsetF SafeAreaManager::GetWindowWrapperOffset()
344 {
345     auto pipelineContext = PipelineContext::GetCurrentContext();
346     CHECK_NULL_RETURN(pipelineContext, OffsetF());
347     auto windowManager = pipelineContext->GetWindowManager();
348     auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
349                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
350     if (isContainerModal) {
351         auto wrapperOffset = OffsetF(static_cast<float>((CONTAINER_BORDER_WIDTH + CONTENT_PADDING).ConvertToPx()),
352             static_cast<float>((pipelineContext->GetCustomTitleHeight() + CONTAINER_BORDER_WIDTH).ConvertToPx()));
353         return wrapperOffset;
354     }
355     return OffsetF();
356 }
357 
ExpandSafeArea()358 void SafeAreaManager::ExpandSafeArea()
359 {
360     ACE_SCOPED_TRACE("ExpandSafeArea node count %zu, IsSafeAreaValid: %d, ignoreSafeArea: %d, isFullScreen: %d, "
361                      "isNeedAvoidWindow %d",
362         needExpandNodes_.size(), IsSafeAreaValid(), ignoreSafeArea_, isFullScreen_, isNeedAvoidWindow_);
363     auto pipeline = PipelineContext::GetCurrentContext();
364     CHECK_NULL_VOID(pipeline);
365     auto manager = pipeline->GetSafeAreaManager();
366     auto iter = needExpandNodes_.begin();
367     while (iter != needExpandNodes_.end()) {
368         auto frameNode = (*iter).Upgrade();
369         if (frameNode) {
370             manager->AddGeoRestoreNode(frameNode);
371             frameNode->ExpandSafeArea();
372         }
373         ++iter;
374     }
375     ClearNeedExpandNode();
376 }
377 
AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode> & node)378 bool SafeAreaManager::AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
379 {
380     if (needExpandNodes_.find(node) == needExpandNodes_.end()) {
381         AddNeedExpandNode(node);
382         return true;
383     }
384     return false;
385 }
386 
GetExpandNodeSet()387 std::vector<WeakPtr<FrameNode>> SafeAreaManager::GetExpandNodeSet()
388 {
389     // To isolate set comparator, use vector to collect a copy of nodes
390     std::vector<WeakPtr<FrameNode>> result;
391     std::copy(needExpandNodes_.begin(), needExpandNodes_.end(), std::back_inserter(result));
392     return result;
393 }
394 
SetKeyboardInfo(float height)395 void SafeAreaManager::SetKeyboardInfo(float height)
396 {
397     SetRawKeyboardHeight(height);
398     keyboardOrientation_ = -1;
399     auto container = Container::Current();
400     CHECK_NULL_VOID(container);
401     auto displayInfo = container->GetDisplayInfo();
402     CHECK_NULL_VOID(displayInfo);
403     keyboardOrientation_ = static_cast<int32_t>(displayInfo->GetRotation());
404 }
405 
CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode> & frameNode)406 bool SafeAreaManager::CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode)
407 {
408     if (frameNode->GetTag() != V2::PAGE_ETS_TAG) {
409         return false;
410     }
411     // page will not avoid keyboard when lastChild is sheet
412     RefPtr<OverlayManager> overlay;
413     if (frameNode->RootNodeIsPage()) {
414         auto pattern = frameNode->GetPattern<PagePattern>();
415         CHECK_NULL_RETURN(pattern, true);
416         overlay = pattern->GetOverlayManager();
417     } else {
418         auto navNode = FrameNode::GetFrameNode(V2::NAVDESTINATION_VIEW_ETS_TAG, frameNode->GetRootNodeId());
419         CHECK_NULL_RETURN(navNode, true);
420         auto pattern = navNode->GetPattern<NavDestinationPattern>();
421         CHECK_NULL_RETURN(pattern, true);
422         overlay = pattern->GetOverlayManager();
423     }
424     CHECK_NULL_RETURN(overlay, true);
425     return overlay->CheckPageNeedAvoidKeyboard();
426 }
427 } // namespace OHOS::Ace::NG
428