• 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 "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     auto container = Container::Current();
100     if (container && systemSafeArea_.bottom_.IsValid() && !container->IsSceneBoardEnabled()) {
101         bottom = systemSafeArea_.bottom_.start;
102         ACE_SCOPED_TRACE("calc keyboardRect use systemSafeArea_.bottom_");
103     } else {
104         bottom = rootHeight.has_value() ? rootHeight.value() : PipelineContext::GetCurrentRootHeight();
105     }
106     SafeAreaInsets::Inset inset = { .start = bottom - keyboardHeight, .end = bottom };
107     if (inset == keyboardInset_) {
108         return false;
109     }
110     keyboardInset_ = inset;
111     ACE_SCOPED_TRACE("SafeAreaManager::UpdateKeyboardSafeArea %s", inset.ToString().c_str());
112     return true;
113 }
114 
GetCombinedSafeArea(const SafeAreaExpandOpts & opts) const115 SafeAreaInsets SafeAreaManager::GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const
116 {
117     SafeAreaInsets res;
118     if (!IsSafeAreaValid()) {
119         return {};
120     }
121     if (opts.type & SAFE_AREA_TYPE_CUTOUT) {
122         res = res.Combine(cutoutSafeArea_);
123     }
124     if (opts.type & SAFE_AREA_TYPE_SYSTEM) {
125         res = res.Combine(systemSafeArea_).Combine(navSafeArea_);
126     }
127     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
128         return res;
129     }
130     if ((keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
131         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET) && (opts.type & SAFE_AREA_TYPE_KEYBOARD)) {
132         res.bottom_ = res.bottom_.Combine(keyboardInset_);
133     }
134     return res;
135 }
136 
IsSafeAreaValid() const137 bool SafeAreaManager::IsSafeAreaValid() const
138 {
139 #ifdef PREVIEW
140     return !ignoreSafeArea_;
141 #else
142     return !(ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_));
143 #endif
144 }
145 
SetIsFullScreen(bool value)146 bool SafeAreaManager::SetIsFullScreen(bool value)
147 {
148     if (isFullScreen_ == value) {
149         return false;
150     }
151     isFullScreen_ = value;
152     LOGI("SafeAreaManager::SetIsFullScreen %{public}d", isFullScreen_);
153     return true;
154 }
155 
SetIsNeedAvoidWindow(bool value)156 bool SafeAreaManager::SetIsNeedAvoidWindow(bool value)
157 {
158     if (isNeedAvoidWindow_ == value) {
159         return false;
160     }
161     isNeedAvoidWindow_ = value;
162     LOGI("SafeAreaManager::SetIsNeedAvoidWindow %{public}d", isNeedAvoidWindow_);
163     return true;
164 }
165 
SetIgnoreSafeArea(bool value)166 bool SafeAreaManager::SetIgnoreSafeArea(bool value)
167 {
168     if (ignoreSafeArea_ == value) {
169         return false;
170     }
171     ignoreSafeArea_ = value;
172     LOGI("SafeAreaManager::SetIgnoreSafeArea %{public}d", ignoreSafeArea_);
173     return true;
174 }
175 
SetKeyBoardAvoidMode(KeyBoardAvoidMode value)176 bool SafeAreaManager::SetKeyBoardAvoidMode(KeyBoardAvoidMode value)
177 {
178     if (keyboardAvoidMode_ == value) {
179         return false;
180     }
181     if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE || value == KeyBoardAvoidMode::NONE) {
182         keyboardOffset_ = 0.0f;
183     }
184     keyboardAvoidMode_ = value;
185     keyboardSafeAreaEnabled_ = keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE
186         || keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET;
187     TAG_LOGI(ACE_LAYOUT, "SetKeyBoardAvoidMode %{public}d", keyboardAvoidMode_);
188     return true;
189 }
190 
GetKeyBoardAvoidMode()191 KeyBoardAvoidMode SafeAreaManager::GetKeyBoardAvoidMode()
192 {
193     return keyboardAvoidMode_;
194 }
195 
SetIsAtomicService(bool value)196 bool SafeAreaManager::SetIsAtomicService(bool value)
197 {
198     if (isAtomicService_ == value) {
199         return false;
200     }
201     isAtomicService_ = value;
202     LOGI("SafeAreaManager::SetIsAtomicService %{public}d", isAtomicService_);
203     return true;
204 }
205 
IsAtomicService() const206 bool SafeAreaManager::IsAtomicService() const
207 {
208     return isAtomicService_;
209 }
210 
GetSystemSafeArea() const211 SafeAreaInsets SafeAreaManager::GetSystemSafeArea() const
212 {
213     return systemSafeArea_;
214 }
215 
GetCutoutSafeArea() const216 SafeAreaInsets SafeAreaManager::GetCutoutSafeArea() const
217 {
218     if (!IsSafeAreaValid()) {
219         return {};
220     }
221     return cutoutSafeArea_;
222 }
223 
GetSafeArea() const224 SafeAreaInsets SafeAreaManager::GetSafeArea() const
225 {
226     if (!IsSafeAreaValid()) {
227         return {};
228     }
229     return systemSafeArea_.Combine(cutoutSafeArea_).Combine(navSafeArea_);
230 }
231 
GetSafeAreaWithoutCutout() const232 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutCutout() const
233 {
234     if (!IsSafeAreaValid()) {
235         return {};
236     }
237     return systemSafeArea_.Combine(navSafeArea_);
238 }
239 
GetSafeAreaWithoutProcess() const240 SafeAreaInsets SafeAreaManager::GetSafeAreaWithoutProcess() const
241 {
242     return systemSafeArea_.Combine(cutoutSafeArea_).Combine(navSafeArea_);
243 }
244 
SafeAreaToPadding(bool withoutProcess)245 PaddingPropertyF SafeAreaManager::SafeAreaToPadding(bool withoutProcess)
246 {
247     if (!withoutProcess) {
248 #ifdef PREVIEW
249         if (ignoreSafeArea_) {
250             return {};
251         }
252 #else
253         if (ignoreSafeArea_ || (!isFullScreen_ && !isNeedAvoidWindow_)) {
254             return {};
255         }
256 #endif
257     }
258     auto combinedSafeArea = systemSafeArea_.Combine(cutoutSafeArea_).Combine(navSafeArea_);
259     PaddingPropertyF result;
260     if (combinedSafeArea.left_.IsValid()) {
261         result.left = combinedSafeArea.left_.Length();
262     }
263     if (combinedSafeArea.top_.IsValid()) {
264         result.top = combinedSafeArea.top_.Length();
265     }
266     if (combinedSafeArea.right_.IsValid()) {
267         result.right = combinedSafeArea.right_.Length();
268     }
269     if (combinedSafeArea.bottom_.IsValid()) {
270         result.bottom = combinedSafeArea.bottom_.Length();
271     }
272     return result;
273 }
274 
GetKeyboardOffset(bool withoutProcess) const275 float SafeAreaManager::GetKeyboardOffset(bool withoutProcess) const
276 {
277     if (withoutProcess) {
278         return keyboardOffset_;
279     }
280     if (keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE ||
281         keyboardAvoidMode_ == KeyBoardAvoidMode::RESIZE_WITH_CARET ||
282         keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
283         return 0.0f;
284     }
285     return keyboardOffset_;
286 }
287 
GetWindowWrapperOffset()288 OffsetF SafeAreaManager::GetWindowWrapperOffset()
289 {
290     auto pipelineContext = PipelineContext::GetCurrentContext();
291     CHECK_NULL_RETURN(pipelineContext, OffsetF());
292     auto windowManager = pipelineContext->GetWindowManager();
293     auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
294                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
295     if (isContainerModal) {
296         auto wrapperOffset = OffsetF(static_cast<float>((CONTAINER_BORDER_WIDTH + CONTENT_PADDING).ConvertToPx()),
297             static_cast<float>((pipelineContext->GetCustomTitleHeight() + CONTAINER_BORDER_WIDTH).ConvertToPx()));
298         return wrapperOffset;
299     }
300     return OffsetF();
301 }
302 
ExpandSafeArea()303 void SafeAreaManager::ExpandSafeArea()
304 {
305     ACE_SCOPED_TRACE("ExpandSafeArea node count %zu, IsSafeAreaValid: %d, ignoreSafeArea: %d, isFullScreen: %d, "
306                      "isNeedAvoidWindow %d",
307         needExpandNodes_.size(), IsSafeAreaValid(), ignoreSafeArea_, isFullScreen_, isNeedAvoidWindow_);
308     auto pipeline = PipelineContext::GetCurrentContext();
309     CHECK_NULL_VOID(pipeline);
310     auto manager = pipeline->GetSafeAreaManager();
311     auto iter = needExpandNodes_.begin();
312     while (iter != needExpandNodes_.end()) {
313         auto frameNode = (*iter).Upgrade();
314         if (frameNode) {
315             manager->AddGeoRestoreNode(frameNode);
316             frameNode->ExpandSafeArea();
317         }
318         ++iter;
319     }
320     ClearNeedExpandNode();
321 }
322 
AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode> & node)323 bool SafeAreaManager::AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node)
324 {
325     if (needExpandNodes_.find(node) == needExpandNodes_.end()) {
326         AddNeedExpandNode(node);
327         return true;
328     }
329     return false;
330 }
331 
CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode> & frameNode)332 bool SafeAreaManager::CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode)
333 {
334     if (frameNode->GetTag() != V2::PAGE_ETS_TAG) {
335         return false;
336     }
337     // page will not avoid keyboard when lastChild is sheet
338     RefPtr<OverlayManager> overlay;
339     if (frameNode->RootNodeIsPage()) {
340         auto pattern = frameNode->GetPattern<PagePattern>();
341         CHECK_NULL_RETURN(pattern, true);
342         overlay = pattern->GetOverlayManager();
343     } else {
344         auto navNode = FrameNode::GetFrameNode(V2::NAVDESTINATION_VIEW_ETS_TAG, frameNode->GetRootNodeId());
345         CHECK_NULL_RETURN(navNode, true);
346         auto pattern = navNode->GetPattern<NavDestinationPattern>();
347         CHECK_NULL_RETURN(pattern, true);
348         overlay = pattern->GetOverlayManager();
349     }
350     CHECK_NULL_RETURN(overlay, true);
351     return overlay->CheckPageNeedAvoidKeyboard();
352 }
353 } // namespace OHOS::Ace::NG
354