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 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_SAFE_AREA_SAFE_AREA_MANAGER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_SAFE_AREA_SAFE_AREA_MANAGER_H
18 
19 #include "base/memory/ace_type.h"
20 #include "base/utils/noncopyable.h"
21 #include "core/components_ng/base/frame_node.h"
22 #include "core/components_ng/property/safe_area_insets.h"
23 #include "core/components_ng/property/transition_property.h"
24 
25 namespace OHOS::Ace::NG {
26 // SafeAreaManager stores layout information to apply SafeArea correctly.
27 class SafeAreaManager : public virtual AceType {
28     DECLARE_ACE_TYPE(SafeAreaManager, AceType);
29 
30 public:
31     SafeAreaManager() = default;
32     ~SafeAreaManager() override = default;
33 
34     /**
35      * @brief Check if the incoming safe area is identical to the system safe area
36      *
37      * @param safeArea The new system safe area.
38      * @return True if the incoming safe area is identical to the current one, false otherwise.
39      */
40     bool CheckSystemSafeArea(const SafeAreaInsets& safeArea);
41 
42     /**
43      * @brief Updates the system safe area.
44      *
45      * @param safeArea The new system safe area.
46      * @return True if the system safe area was modified, false otherwise.
47      */
48     bool UpdateSystemSafeArea(const SafeAreaInsets& safeArea);
49 
50     /**
51      * @brief Check if the incoming safe area is identical to the navigation indictor safe area.
52      *
53      * @param safeArea The new navigation indictor safe area.
54      * @return True if the incoming safe area is identical to the current one, false otherwise.
55      */
56     bool CheckNavArea(const SafeAreaInsets& safeArea);
57 
58     /**
59      * @brief Updates the navigation indictor safe area.
60      *
61      * @param safeArea The new navigation indictor safe area.
62      * @return True if the system safe area was modified, false otherwise.
63      */
64     bool UpdateNavArea(const SafeAreaInsets& safeArea);
65 
66     /**
67      * @brief Retrieves the system safe area insets.
68      *
69      * This function returns the safe area insets of the system, which represents the portion of the screen that is
70      * covered by system UI elements such as the status bar or navigation bar.
71      *
72      * @return The system safe area insets.
73      */
74     SafeAreaInsets GetSystemSafeArea() const;
75 
76     /**
77      * @brief Cut the incoming area with root size, then check if the result is identical to the cutout safe area.
78      *
79      * @param safeArea The SafeAreaInsets representing the new cutout safe area, which would be modified.
80      * @return True if the incoming safe area is identical to the current one, false otherwise.
81      */
82     bool CheckCutoutSafeArea(
83         const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize = NG::OptionalSize<uint32_t>());
84 
85     /**
86      * @brief Updates the cutout safe area.
87      *
88      * This function is responsible for updating the cutout safe area based on the provided SafeAreaInsets.
89      *
90      * @param safeArea The SafeAreaInsets representing the new cutout safe area.
91      * @return true if the cutout safe area was successfully updated, false otherwise.
92      */
93     bool UpdateCutoutSafeArea(
94         const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize = NG::OptionalSize<uint32_t>());
95 
96     /**
97      * @brief Retrieves the safe area insets that account for any cutout areas on the screen.
98      *
99      * @return The safe area insets that account for any cutout areas on the screen.
100      */
101     SafeAreaInsets GetCutoutSafeArea() const;
102 
103     /**
104      * @brief Retrieves the safe area insets combining System and Cutout.
105      *
106      * @return The System & Cutout safe area insets.
107      */
108     SafeAreaInsets GetSafeArea() const;
109 
110     /**
111      * @brief Retrieves the safe area insets only System.
112      *
113      * @return The System safe area insets.
114      */
115     SafeAreaInsets GetSafeAreaWithoutCutout() const;
116 
117     /**
118      * @brief Updates the safe area to accommodate the keyboard.
119      *
120      * This function is called to update the safe area when the keyboard is shown or hidden.
121      *
122      * @param keyboardHeight The height of the keyboard in pixels.
123      * @return true if the safe area was modified, false otherwise.
124      */
125     bool UpdateKeyboardSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight = std::nullopt);
126 
127     /**
128      * @brief Retrieves the inset of the safe area caused by the keyboard.
129      *
130      * @return The inset of the safe area caused by the keyboard.
131      */
GetKeyboardInset()132     SafeAreaInsets::Inset GetKeyboardInset() const
133     {
134         if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) {
135             SafeAreaInsets::Inset inset;
136             return inset;
137         }
138         return keyboardInset_;
139     }
140 
UpdateKeyboardOffset(float offset)141     void UpdateKeyboardOffset(float offset)
142     {
143         keyboardOffset_ = offset;
144     }
145 
146     float GetKeyboardOffset(bool withoutProcess = false) const;
147 
GetKeyboardOffsetDirectly()148     float GetKeyboardOffsetDirectly() const
149     {
150         return keyboardOffset_;
151     }
152 
GetRawKeyboardHeight()153     float GetRawKeyboardHeight() const
154     {
155         return rawKeyboardHeight_;
156     }
157 
SetRawKeyboardHeight(float height)158     void SetRawKeyboardHeight(float height)
159     {
160         rawKeyboardHeight_ = height;
161     }
162 
KeyboardSafeAreaEnabled()163     bool KeyboardSafeAreaEnabled() const
164     {
165         return keyboardSafeAreaEnabled_;
166     }
167 
168     SafeAreaInsets GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const;
169 
GetGeoRestoreNodes()170     const std::set<WeakPtr<FrameNode>>& GetGeoRestoreNodes() const
171     {
172         return geoRestoreNodes_;
173     }
174 
AddGeoRestoreNode(const WeakPtr<FrameNode> & node)175     void AddGeoRestoreNode(const WeakPtr<FrameNode>& node)
176     {
177         geoRestoreNodes_.insert(node);
178     }
179 
AddNeedExpandNode(const WeakPtr<FrameNode> & node)180     void AddNeedExpandNode(const WeakPtr<FrameNode>& node)
181     {
182         needExpandNodes_.insert(node);
183     }
184 
185     bool AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node);
186 
ClearNeedExpandNode()187     void ClearNeedExpandNode()
188     {
189         needExpandNodes_.clear();
190     }
191 
RemoveRestoreNode(const WeakPtr<FrameNode> & node)192     void RemoveRestoreNode(const WeakPtr<FrameNode>& node)
193     {
194         geoRestoreNodes_.erase(node);
195     }
196 
GetSafeAreaCurve()197     RefPtr<InterpolatingSpring> GetSafeAreaCurve() const
198     {
199         return safeAreaCurve_;
200     }
201     void ExpandSafeArea();
202 
203     OffsetF GetWindowWrapperOffset();
204 
205     SafeAreaInsets GetSafeAreaWithoutProcess() const;
206 
207     bool SetIsFullScreen(bool value);
208     bool SetIsNeedAvoidWindow(bool value);
209     bool SetIgnoreSafeArea(bool value);
210     bool SetKeyBoardAvoidMode(KeyBoardAvoidMode value);
211     KeyBoardAvoidMode GetKeyBoardAvoidMode();
IsIgnoreAsfeArea()212     bool IsIgnoreAsfeArea()
213     {
214         return ignoreSafeArea_;
215     }
IsNeedAvoidWindow()216     bool IsNeedAvoidWindow()
217     {
218         return isNeedAvoidWindow_;
219     }
IsFullScreen()220     bool IsFullScreen()
221     {
222         return isFullScreen_;
223     }
224     bool SetIsAtomicService(bool value);
225     bool IsAtomicService() const;
226 
GetSafeHeight()227     float GetSafeHeight() const
228     {
229         Dimension safeDistance = 16.0_vp;
230         return safeDistance.ConvertToPx();
231     }
232 
SetLastKeyboardPoistion(float position)233     void SetLastKeyboardPoistion(float position)
234     {
235         lastKeyboardY_ = position;
236     }
237 
GetLastKeyboardPoistion()238     float GetLastKeyboardPoistion() const
239     {
240         return lastKeyboardY_;
241     }
242 
243     bool IsSafeAreaValid() const;
244     // check if the page node needs to be avoid keyboard
245     bool CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode);
246 
GetkeyboardHeightConsideringUIExtension()247     uint32_t GetkeyboardHeightConsideringUIExtension()
248     {
249         return keyboardHeightConsideringUIExtension_;
250     }
SetkeyboardHeightConsideringUIExtension(uint32_t height)251     void SetkeyboardHeightConsideringUIExtension(uint32_t height)
252     {
253         if (keyboardHeightConsideringUIExtension_ != height) {
254             for (const auto& [nodeId, callback] : keyboardChangeCbsConsideringUIExt_) {
255                 if (callback) {
256                     callback();
257                 }
258             }
259             keyboardHeightConsideringUIExtension_ = height;
260         }
261     }
AddKeyboardChangeCallbackConsideringUIExt(int32_t nodeId,const std::function<void ()> & callback)262     void AddKeyboardChangeCallbackConsideringUIExt(int32_t nodeId, const std::function<void()>& callback)
263     {
264         keyboardChangeCbsConsideringUIExt_[nodeId] = callback;
265     }
RemoveKeyboardChangeCallbackConsideringUIExt(int32_t nodeId)266     void RemoveKeyboardChangeCallbackConsideringUIExt(int32_t nodeId)
267     {
268         keyboardChangeCbsConsideringUIExt_.erase(nodeId);
269     }
270 
271     PaddingPropertyF SafeAreaToPadding(bool withoutProcess = false);
272 
273 private:
274     bool isAtomicService_ = false;
275 
276     // app window is full screen
277     // todo: remove and only use isNeedAvoidWindow_
278     bool isFullScreen_ = false;
279 
280     /**
281      * @brief Indicates whether the UI within the current window type needs to avoid SafeAreaInsets.
282      */
283     bool isNeedAvoidWindow_ = false;
284 
285     /**
286      * @brief Indicates whether to ignore the SafeAreaInsets, specified by the developer from frontend.
287      */
288     bool ignoreSafeArea_ = false;
289 
290     /**
291      * @brief Indicates whether the keyboard safe area is enabled. When enabled, UI avoids the keyboard inset and the
292      * Page is compressed when the keyboard is up. When disabled, the size of Page doesn't change, but Page would
293      * offset vertically according to [keyboardOffset_].
294      */
295     bool keyboardSafeAreaEnabled_ = false;
296 
297     KeyBoardAvoidMode keyboardAvoidMode_ = KeyBoardAvoidMode::OFFSET;
298 
299     SafeAreaInsets systemSafeArea_;
300     SafeAreaInsets cutoutSafeArea_;
301     SafeAreaInsets navSafeArea_;
302     // keyboard is bottom direction only
303     SafeAreaInsets::Inset keyboardInset_;
304 
305     /**
306      * @brief A set of weak pointers to FrameNode objects whose geometry info are saved before their SafeArea
307      * expansion. The geometry info of these nodes need to be restored when their next Layout task begins.
308      */
309     std::set<WeakPtr<FrameNode>> geoRestoreNodes_;
310 
311     struct DepthCompare {
operatorDepthCompare312         bool operator()(const WeakPtr<FrameNode>& a, const WeakPtr<FrameNode>& b) const
313         {
314             auto ptrA = a.Upgrade();
315             auto ptrB = b.Upgrade();
316             if (!ptrA || !ptrB) {
317                 return false;
318             }
319             if (ptrA->GetDepth() < ptrB->GetDepth()) {
320                 return true;
321             }
322             if (ptrA->GetDepth() == ptrB->GetDepth()) {
323                 return ptrA < ptrB;
324             }
325             return false;
326         }
327     };
328     std::set<WeakPtr<FrameNode>, DepthCompare> needExpandNodes_;
329     // amount of offset to apply to Page when keyboard is up
330     float keyboardOffset_ = 0.0f;
331     float lastKeyboardY_ = 0.0f;
332     float rawKeyboardHeight_ = 0.0f;
333 
334     static constexpr float SAFE_AREA_VELOCITY = 0.0f;
335     static constexpr float SAFE_AREA_MASS = 1.0f;
336     static constexpr float SAFE_AREA_STIFFNESS = 228.0f;
337     static constexpr float SAFE_AREA_DAMPING = 30.0f;
338     RefPtr<InterpolatingSpring> safeAreaCurve_ = AceType::MakeRefPtr<InterpolatingSpring>(
339         SAFE_AREA_VELOCITY, SAFE_AREA_MASS, SAFE_AREA_STIFFNESS, SAFE_AREA_DAMPING);
340 
341     uint32_t keyboardHeightConsideringUIExtension_ = 0;
342     std::unordered_map<int32_t, std::function<void()>> keyboardChangeCbsConsideringUIExt_;
343 
344     ACE_DISALLOW_COPY_AND_MOVE(SafeAreaManager);
345 };
346 } // namespace OHOS::Ace::NG
347 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_SAFE_AREA_SAFE_AREA_MANAGER_H
348