• 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 
IsModeResize()43 bool SafeAreaManager::IsModeResize()
44 {
45     return keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
46            keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET;
47 }
48 
IsModeOffset()49 bool SafeAreaManager::IsModeOffset()
50 {
51     return keyboardAvoidMode_ == KeyBoardAvoidMode::OFFSET ||
52            keyboardAvoidMode_ == KeyBoardAvoidMode::OFFSET_WITH_CARET;
53 }
54 
CheckCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)55 bool SafeAreaManager::CheckCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
56 {
57     return cutoutSafeArea_ != GenerateCutOutAreaWithRoot(safeArea, rootSize);
58 }
59 
UpdateCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)60 bool SafeAreaManager::UpdateCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
61 {
62     auto safeAreaWithRoot = GenerateCutOutAreaWithRoot(safeArea, rootSize);
63     if (cutoutSafeArea_ == safeAreaWithRoot) {
64         return false;
65     }
66     ACE_SCOPED_TRACE("SafeAreaManager::UpdateCutoutSafeArea %s, safeAreaWithRoot %s", safeArea.ToString().c_str(),
67         safeAreaWithRoot.ToString().c_str());
68     cutoutSafeArea_ = safeAreaWithRoot;
69     return true;
70 }
71 
CheckSystemSafeArea(const SafeAreaInsets & safeArea)72 bool SafeAreaManager::CheckSystemSafeArea(const SafeAreaInsets& safeArea)
73 {
74     return systemSafeArea_ != safeArea;
75 }
76 
UpdateSystemSafeArea(const SafeAreaInsets & safeArea)77 bool SafeAreaManager::UpdateSystemSafeArea(const SafeAreaInsets& safeArea)
78 {
79     if (systemSafeArea_ == safeArea) {
80         return false;
81     }
82     ACE_SCOPED_TRACE("SafeAreaManager::UpdateSystemSafeArea %s", safeArea.ToString().c_str());
83     systemSafeArea_ = safeArea;
84     return true;
85 }
86 
CheckNavSafeArea(const SafeAreaInsets & safeArea)87 bool SafeAreaManager::CheckNavSafeArea(const SafeAreaInsets& safeArea)
88 {
89     return navSafeArea_ != safeArea;
90 }
91 
UpdateNavSafeArea(const SafeAreaInsets & safeArea)92 bool SafeAreaManager::UpdateNavSafeArea(const SafeAreaInsets& safeArea)
93 {
94     if (navSafeArea_ == safeArea) {
95         return false;
96     }
97     ACE_SCOPED_TRACE("SafeAreaManager::UpdateNavSafeArea %s", safeArea.ToString().c_str());
98     navSafeArea_ = safeArea;
99     return true;
100 }
101 
UpdateKeyboardSafeArea(float keyboardHeight,std::optional<uint32_t> rootHeight)102 bool SafeAreaManager::UpdateKeyboardSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight)
103 {
104     uint32_t bottom;
105     auto container = Container::Current();
106     if (container && systemSafeArea_.bottom_.IsValid() && !container->IsSceneBoardEnabled()) {
107         bottom = systemSafeArea_.bottom_.start;
108         ACE_SCOPED_TRACE("calc keyboardRect use systemSafeArea_.bottom_");
109     } else {
110         bottom = rootHeight.has_value() ? rootHeight.value() : PipelineContext::GetCurrentRootHeight();
111     }
112     SafeAreaInsets::Inset inset = { .start = bottom - keyboardHeight, .end = bottom };
113     if (inset == keyboardInset_) {
114         return false;
115     }
116     keyboardInset_ = inset;
117     ACE_SCOPED_TRACE("SafeAreaManager::UpdateKeyboardSafeArea %s", inset.ToString().c_str());
118     return true;
119 }
120 
UpdateKeyboardWebSafeArea(float keyboardHeight,std::optional<uint32_t> rootHeight)121 bool SafeAreaManager::UpdateKeyboardWebSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight)
122 {
123     uint32_t bottom;
124     auto container = Container::Current();
125     if (container && systemSafeArea_.bottom_.IsValid() && !container->IsSceneBoardEnabled()) {
126         bottom = systemSafeArea_.bottom_.start;
127         ACE_SCOPED_TRACE("calc keyboardWebRect use systemSafeArea_.bottom_");
128     } else {
129         bottom = rootHeight.has_value() ? rootHeight.value() : PipelineContext::GetCurrentRootHeight();
130     }
131     SafeAreaInsets::Inset inset = { .start = bottom - keyboardHeight, .end = bottom };
132     if (inset == keyboardWebInset_) {
133         return false;
134     }
135     keyboardWebInset_ = inset;
136     ACE_SCOPED_TRACE("SafeAreaManager::UpdateKeyboardWebSafeArea %s", inset.ToString().c_str());
137     return true;
138 }
139 
GetCombinedSafeArea(const SafeAreaExpandOpts & opts) const140 SafeAreaInsets SafeAreaManager::GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const
141 {
142     SafeAreaInsets res;
143     if (!IsSafeAreaValid()) {
144         return {};
145     }
146     if ((opts.type & SAFE_AREA_TYPE_CUTOUT) && useCutout_) {
147         res = res.Combine(cutoutSafeArea_);
148     }
149     if (opts.type & SAFE_AREA_TYPE_SYSTEM) {
150         res = res.Combine(systemSafeArea_).Combine(navSafeArea_);
151     }
152     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
153         return res;
154     }
155     if ((keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
156         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET) && (opts.type & SAFE_AREA_TYPE_KEYBOARD)) {
157         res.bottom_ = res.bottom_.Combine(keyboardInset_);
158     }
159     return res;
160 }
161 
UpdateScbSystemSafeArea(const SafeAreaInsets & safeArea)162 bool SafeAreaManager::UpdateScbSystemSafeArea(const SafeAreaInsets& safeArea)
163 {
164     if (scbSystemSafeArea_.has_value() && scbSystemSafeArea_.value() == safeArea) {
165         return false;
166     }
167     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbSystemSafeArea %s", safeArea.ToString().c_str());
168     scbSystemSafeArea_ = safeArea;
169     return true;
170 }
171 
UpdateScbCutoutSafeArea(const SafeAreaInsets & safeArea,NG::OptionalSize<uint32_t> rootSize)172 bool SafeAreaManager::UpdateScbCutoutSafeArea(const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize)
173 {
174     auto safeAreaWithRoot = GenerateCutOutAreaWithRoot(safeArea, rootSize);
175     if (scbCutoutSafeArea_.has_value() && scbCutoutSafeArea_.value() == safeAreaWithRoot) {
176         return false;
177     }
178     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbCutoutSafeArea %s", safeAreaWithRoot.ToString().c_str());
179     scbCutoutSafeArea_ = safeAreaWithRoot;
180     return true;
181 }
182 
UpdateScbNavSafeArea(const SafeAreaInsets & safeArea)183 bool SafeAreaManager::UpdateScbNavSafeArea(const SafeAreaInsets& safeArea)
184 {
185     if (scbNavSafeArea_.has_value() && scbNavSafeArea_.value() == safeArea) {
186         return false;
187     }
188     ACE_SCOPED_TRACE("SafeAreaManager::UpdateScbNavSafeArea %s", safeArea.ToString().c_str());
189     scbNavSafeArea_ = safeArea;
190     return true;
191 }
192 
IsSafeAreaValid() const193 bool SafeAreaManager::IsSafeAreaValid() const
194 {
195 #ifdef PREVIEW
196     return !ignoreSafeArea_;
197 #else
198     return !(ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_));
199 #endif
200 }
201 
SetIsFullScreen(bool value)202 bool SafeAreaManager::SetIsFullScreen(bool value)
203 {
204     if (isFullScreen_ == value) {
205         return false;
206     }
207     isFullScreen_ = value;
208     TAG_LOGI(ACE_SAFE_AREA, "SetIsFullScreen %{public}d", isFullScreen_);
209     return true;
210 }
211 
SetIsNeedAvoidWindow(bool value)212 bool SafeAreaManager::SetIsNeedAvoidWindow(bool value)
213 {
214     if (isNeedAvoidWindow_ == value) {
215         return false;
216     }
217     isNeedAvoidWindow_ = value;
218     TAG_LOGI(ACE_SAFE_AREA, "SetIsNeedAvoidWindow %{public}d", isNeedAvoidWindow_);
219     return true;
220 }
221 
SetIgnoreSafeArea(bool value)222 bool SafeAreaManager::SetIgnoreSafeArea(bool value)
223 {
224     if (ignoreSafeArea_ == value) {
225         return false;
226     }
227     ignoreSafeArea_ = value;
228     TAG_LOGI(ACE_SAFE_AREA, "SetIgnoreSafeArea %{public}d", ignoreSafeArea_);
229     return true;
230 }
231 
SetKeyBoardAvoidMode(KeyBoardAvoidMode value)232 bool SafeAreaManager::SetKeyBoardAvoidMode(KeyBoardAvoidMode value)
233 {
234     if (keyboardAvoidMode_ == value) {
235         return false;
236     }
237     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE || value == KeyBoardAvoidMode::NONE) {
238         keyboardOffset_ = 0.0f;
239     }
240     keyboardAvoidMode_ = value;
241     keyboardSafeAreaEnabled_ = keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE
242         || keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET;
243     TAG_LOGI(ACE_SAFE_AREA, "SetKeyBoardAvoidMode %{public}d", keyboardAvoidMode_);
244     return true;
245 }
246 
GetKeyBoardAvoidMode()247 KeyBoardAvoidMode SafeAreaManager::GetKeyBoardAvoidMode()
248 {
249     return keyboardAvoidMode_;
250 }
251 
SetIsAtomicService(bool value)252 bool SafeAreaManager::SetIsAtomicService(bool value)
253 {
254     if (isAtomicService_ == value) {
255         return false;
256     }
257     isAtomicService_ = value;
258     TAG_LOGI(ACE_SAFE_AREA, "SetIsAtomicService %{public}d", isAtomicService_);
259     return true;
260 }
261 
IsAtomicService() const262 bool SafeAreaManager::IsAtomicService() const
263 {
264     return isAtomicService_;
265 }
266 
GetSystemSafeArea() const267 SafeAreaInsets SafeAreaManager::GetSystemSafeArea() const
268 {
269     if (windowTypeConfig_.isSceneBoardWindow && scbSystemSafeArea_.has_value()) {
270         return scbSystemSafeArea_.value();
271     }
272     return systemSafeArea_;
273 }
274 
GetCutoutSafeArea() const275 SafeAreaInsets SafeAreaManager::GetCutoutSafeArea() const
276 {
277     if (IsSafeAreaValid() && useCutout_) {
278         if (windowTypeConfig_.isSceneBoardWindow && scbCutoutSafeArea_.has_value()) {
279             return scbCutoutSafeArea_.value();
280         }
281         return cutoutSafeArea_;
282     }
283     return {};
284 }
285 
GetCutoutSafeAreaWithoutProcess() const286 SafeAreaInsets SafeAreaManager::GetCutoutSafeAreaWithoutProcess() const
287 {
288     if (windowTypeConfig_.isSceneBoardWindow && scbCutoutSafeArea_.has_value()) {
289         return scbCutoutSafeArea_.value();
290     }
291     return cutoutSafeArea_;
292 }
293 
GetSafeArea() const294 SafeAreaInsets SafeAreaManager::GetSafeArea() const
295 {
296     if (!IsSafeAreaValid()) {
297         return {};
298     }
299     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
300     return systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
301 }
302 
GetSafeAreaWithoutCutout() const303 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutCutout() const
304 {
305     if (!IsSafeAreaValid()) {
306         return {};
307     }
308     return systemSafeArea_.Combine(navSafeArea_);
309 }
310 
GetSafeAreaWithoutProcess() const311 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutProcess() const
312 {
313     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
314     if (!windowTypeConfig_.isSceneBoardWindow) {
315         return systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
316     }
317     SafeAreaInsets scbSafeArea;
318     if (scbSystemSafeArea_.has_value()) {
319         scbSafeArea = scbSafeArea.Combine(scbSystemSafeArea_.value());
320     }
321     if (scbCutoutSafeArea_.has_value() && useCutout_) {
322         scbSafeArea = scbSafeArea.Combine(scbCutoutSafeArea_.value());
323     }
324     if (scbNavSafeArea_.has_value()) {
325         scbSafeArea = scbSafeArea.Combine(scbNavSafeArea_.value());
326     }
327     return scbSafeArea;
328 }
329 
SafeAreaToPadding(bool withoutProcess,LayoutSafeAreaType ignoreType)330 PaddingPropertyF SafeAreaManager::SafeAreaToPadding(bool withoutProcess, LayoutSafeAreaType ignoreType)
331 {
332     if (!withoutProcess) {
333 #ifdef PREVIEW
334         if (ignoreSafeArea_) {
335             return {};
336         }
337 #else
338         if (ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_)) {
339             return {};
340         }
341 #endif
342     }
343     SafeAreaInsets combinedSafeArea;
344     auto cutoutSafeArea = useCutout_ ? cutoutSafeArea_ : SafeAreaInsets();
345 
346     bool includeSystem = ignoreType & LAYOUT_SAFE_AREA_TYPE_SYSTEM;
347     bool includeKeyboard = ignoreType & LAYOUT_SAFE_AREA_TYPE_KEYBOARD;
348 
349     if (includeSystem) {
350         combinedSafeArea = systemSafeArea_.Combine(cutoutSafeArea).Combine(navSafeArea_);
351     }
352     if (includeKeyboard) {
353         if (IsModeResize()) {
354             combinedSafeArea.bottom_ = combinedSafeArea.bottom_.Combine(keyboardInset_);
355         } else if (IsModeOffset()) {
356             auto keyboardHeight = keyboardInset_.Length();
357             auto bottomLength = GetSafeArea().bottom_.Length();
358             auto distance = bottomLength - GetKeyboardOffset(withoutProcess);
359             if (GreatNotEqual(keyboardHeight, 0.0f) && distance <= keyboardHeight) {
360                 combinedSafeArea.bottom_ = GetSafeArea().bottom_;
361             }
362         }
363     }
364 
365     PaddingPropertyF result;
366     if (combinedSafeArea.left_.IsValid()) {
367         result.left = combinedSafeArea.left_.Length();
368     }
369     if (combinedSafeArea.top_.IsValid()) {
370         result.top = combinedSafeArea.top_.Length();
371     }
372     if (combinedSafeArea.right_.IsValid()) {
373         result.right = combinedSafeArea.right_.Length();
374     }
375     if (combinedSafeArea.bottom_.IsValid()) {
376         result.bottom = combinedSafeArea.bottom_.Length();
377     }
378     return result;
379 }
380 
GetKeyboardOffset(bool withoutProcess) const381 float SafeAreaManager::GetKeyboardOffset(bool withoutProcess) const
382 {
383     if (withoutProcess) {
384         return keyboardOffset_;
385     }
386     if (keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
387         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET ||
388         keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
389         return 0.0f;
390     }
391     return keyboardOffset_;
392 }
393 
GetWindowWrapperOffset()394 OffsetF SafeAreaManager::GetWindowWrapperOffset()
395 {
396     auto pipelineContext = PipelineContext::GetCurrentContext();
397     CHECK_NULL_RETURN(pipelineContext, OffsetF());
398     auto windowManager = pipelineContext->GetWindowManager();
399     auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
400                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
401     if (isContainerModal) {
402         auto wrapperOffset = OffsetF(static_cast<float>((CONTAINER_BORDER_WIDTH + CONTENT_PADDING).ConvertToPx()),
403             static_cast<float>((pipelineContext->GetCustomTitleHeight() + CONTAINER_BORDER_WIDTH).ConvertToPx()));
404         return wrapperOffset;
405     }
406     return OffsetF();
407 }
408 
ExpandSafeArea()409 void SafeAreaManager::ExpandSafeArea()
410 {
411     ACE_SCOPED_TRACE("ExpandSafeArea node count %zu, IsSafeAreaValid: %d, ignoreSafeArea: %d, isFullScreen: %d, "
412                      "isNeedAvoidWindow %d",
413         needExpandNodes_.size(), IsSafeAreaValid(), ignoreSafeArea_, isFullScreen_, isNeedAvoidWindow_);
414     auto pipeline = PipelineContext::GetCurrentContext();
415     CHECK_NULL_VOID(pipeline);
416     auto manager = pipeline->GetSafeAreaManager();
417     auto iter = needExpandNodes_.begin();
418     while (iter != needExpandNodes_.end()) {
419         auto frameNode = (*iter).Upgrade();
420         if (frameNode) {
421             manager->AddGeoRestoreNode(frameNode);
422             frameNode->ExpandSafeArea();
423         }
424         ++iter;
425     }
426     ClearNeedExpandNode();
427 }
428 
AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode> & node)429 bool SafeAreaManager::AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
430 {
431     if (needExpandNodes_.find(node) == needExpandNodes_.end()) {
432         AddNeedExpandNode(node);
433         return true;
434     }
435     return false;
436 }
437 
GetExpandNodeSet()438 std::vector<WeakPtr<FrameNode>> SafeAreaManager::GetExpandNodeSet()
439 {
440     // To isolate set comparator, use vector to collect a copy of nodes
441     std::vector<WeakPtr<FrameNode>> result;
442     std::copy(needExpandNodes_.begin(), needExpandNodes_.end(), std::back_inserter(result));
443     return result;
444 }
445 
SetKeyboardInfo(float height)446 void SafeAreaManager::SetKeyboardInfo(float height)
447 {
448     keyboardOrientation_ = -1;
449     auto container = Container::Current();
450     CHECK_NULL_VOID(container);
451     auto displayInfo = container->GetDisplayInfo();
452     CHECK_NULL_VOID(displayInfo);
453     auto keyboardOrientation = static_cast<int32_t>(displayInfo->GetRotation());
454     ACE_LAYOUT_SCOPED_TRACE("SetKeyboardInfo keyboardOrientation %d, rawKeyboardHeight %f",
455         keyboardOrientation, height);
456     SetRawKeyboardHeight(height);
457     keyboardOrientation_ = keyboardOrientation;
458     auto pipeline = container->GetPipelineContext();
459     CHECK_NULL_VOID(pipeline);
460     pipeline->OnRawKeyboardChangedCallback();
461 }
462 
CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode> & frameNode)463 bool SafeAreaManager::CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode)
464 {
465     if (frameNode->GetTag() != V2::PAGE_ETS_TAG) {
466         return false;
467     }
468     // page will not avoid keyboard when lastChild is sheet
469     RefPtr<OverlayManager> overlay;
470     if (frameNode->RootNodeIsPage()) {
471         auto pattern = frameNode->GetPattern<PagePattern>();
472         CHECK_NULL_RETURN(pattern, true);
473         overlay = pattern->GetOverlayManager();
474     } else {
475         auto navNode = FrameNode::GetFrameNode(V2::NAVDESTINATION_VIEW_ETS_TAG, frameNode->GetRootNodeId());
476         CHECK_NULL_RETURN(navNode, true);
477         auto pattern = navNode->GetPattern<NavDestinationPattern>();
478         CHECK_NULL_RETURN(pattern, true);
479         overlay = pattern->GetOverlayManager();
480     }
481     CHECK_NULL_RETURN(overlay, true);
482     return overlay->CheckPageNeedAvoidKeyboard();
483 }
484 } // namespace OHOS::Ace::NG
485