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 28 struct WindowTypeConfig { 29 WindowTypeConfig() = default; WindowTypeConfigWindowTypeConfig30 WindowTypeConfig(bool isAppWindow, bool isSystemWindow, bool isSceneBoardWindow) 31 : isAppWindow(isAppWindow), isSystemWindow(isSystemWindow), isSceneBoardWindow(isSceneBoardWindow) 32 {} 33 bool isAppWindow = true; 34 bool isSystemWindow = false; 35 bool isSceneBoardWindow = false; 36 }; 37 38 class SafeAreaManager : public virtual AceType { 39 DECLARE_ACE_TYPE(SafeAreaManager, AceType); 40 41 public: 42 SafeAreaManager() = default; 43 ~SafeAreaManager() override = default; 44 45 /** 46 * @brief Check if the incoming safe area is identical to the system safe area 47 * 48 * @param safeArea The new system safe area. 49 * @return True if the incoming safe area is identical to the current one, false otherwise. 50 */ 51 bool CheckSystemSafeArea(const SafeAreaInsets& safeArea); 52 53 /** 54 * @brief Updates the system safe area. 55 * 56 * @param safeArea The new system safe area. 57 * @return True if the system safe area was modified, false otherwise. 58 */ 59 bool UpdateSystemSafeArea(const SafeAreaInsets& safeArea); 60 61 /** 62 * @brief Check if the incoming safe area is identical to the navigation indictor safe area. 63 * 64 * @param safeArea The new navigation indictor safe area. 65 * @return True if the incoming safe area is identical to the current one, false otherwise. 66 */ 67 bool CheckNavSafeArea(const SafeAreaInsets& safeArea); 68 69 /** 70 * @brief Updates the navigation indictor safe area. 71 * 72 * @param safeArea The new navigation indictor safe area. 73 * @return True if the system safe area was modified, false otherwise. 74 */ 75 bool UpdateNavSafeArea(const SafeAreaInsets& safeArea); 76 77 /** 78 * @brief Retrieves the system safe area insets. 79 * 80 * This function returns the safe area insets of the system, which represents the portion of the screen that is 81 * covered by system UI elements such as the status bar or navigation bar. 82 * 83 * @return The system safe area insets. 84 */ 85 SafeAreaInsets GetSystemSafeArea() const; 86 GetNavSafeArea()87 SafeAreaInsets GetNavSafeArea() const 88 { 89 return navSafeArea_; 90 } 91 92 /** 93 * @brief Cut the incoming area with root size, then check if the result is identical to the cutout safe area. 94 * 95 * @param safeArea The SafeAreaInsets representing the new cutout safe area, which would be modified. 96 * @return True if the incoming safe area is identical to the current one, false otherwise. 97 */ 98 bool CheckCutoutSafeArea( 99 const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize = NG::OptionalSize<uint32_t>()); 100 101 /** 102 * @brief Updates the cutout safe area. 103 * 104 * This function is responsible for updating the cutout safe area based on the provided SafeAreaInsets. 105 * 106 * @param safeArea The SafeAreaInsets representing the new cutout safe area. 107 * @return true if the cutout safe area was successfully updated, false otherwise. 108 */ 109 bool UpdateCutoutSafeArea( 110 const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize = NG::OptionalSize<uint32_t>()); 111 112 /** 113 * @brief Retrieves the safe area insets that account for any cutout areas on the screen. 114 * 115 * @return The safe area insets that account for any cutout areas on the screen. 116 */ 117 SafeAreaInsets GetCutoutSafeArea() const; 118 119 /** 120 * @brief Retrieves the safe area insets that account for any cutout areas on the screen. 121 * 122 * @return The safe area insets that account for cutout areas on the screen without any judgement. 123 */ 124 SafeAreaInsets GetCutoutSafeAreaWithoutProcess() const; 125 126 bool UpdateScbSystemSafeArea(const SafeAreaInsets& safeArea); 127 128 bool UpdateScbCutoutSafeArea( 129 const SafeAreaInsets& safeArea, NG::OptionalSize<uint32_t> rootSize = NG::OptionalSize<uint32_t>()); 130 131 bool UpdateScbNavSafeArea(const SafeAreaInsets& safeArea); 132 133 /** 134 * @brief Retrieves the safe area insets combining System and Cutout. 135 * 136 * @return The System & Cutout safe area insets. 137 */ 138 SafeAreaInsets GetSafeArea() const; 139 140 /** 141 * @brief Retrieves the safe area insets only System. 142 * 143 * @return The System safe area insets. 144 */ 145 SafeAreaInsets GetSafeAreaWithoutCutout() const; 146 147 /** 148 * @brief Updates the safe area to accommodate the keyboard. 149 * 150 * This function is called to update the safe area when the keyboard is shown or hidden. 151 * 152 * @param keyboardHeight The height of the keyboard in pixels. 153 * @return true if the safe area was modified, false otherwise. 154 */ 155 bool UpdateKeyboardSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight = std::nullopt); 156 157 /** 158 * @brief Updates a mirror of safe area to accommodate the keyboard from web 159 * 160 * Third-party platform may use SafeArea, so web_pattern using safearea to keep menu away 161 * from keyboard might lead to several problem.This function is called to update a mirror of 162 * keyboardInset when the keyboard is shown or hidden by web. SelectOverlaylayoutAlgorithm will 163 * use it to calculate the position of menu, but not participate in other safearea calculation. 164 * 165 * @param keyboardHeight The height of the keyboard in pixels. 166 * @return true if the safe area was modified, false otherwise. 167 */ 168 bool UpdateKeyboardWebSafeArea(float keyboardHeight, std::optional<uint32_t> rootHeight = std::nullopt); 169 170 /** 171 * @brief Retrieves the inset of the safe area caused by the keyboard. 172 * 173 * @return The inset of the safe area caused by the keyboard. 174 */ GetKeyboardInset()175 SafeAreaInsets::Inset GetKeyboardInset() const 176 { 177 if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) { 178 SafeAreaInsets::Inset inset; 179 return inset; 180 } 181 return keyboardInset_; 182 } 183 GetKeyboardWebInset()184 SafeAreaInsets::Inset GetKeyboardWebInset() const 185 { 186 if (keyboardAvoidMode_ == KeyBoardAvoidMode::NONE) { 187 SafeAreaInsets::Inset inset; 188 return inset; 189 } 190 return keyboardWebInset_; 191 } 192 UpdateKeyboardOffset(float offset)193 void UpdateKeyboardOffset(float offset) 194 { 195 keyboardOffset_ = offset; 196 } 197 198 float GetKeyboardOffset(bool withoutProcess = false) const; 199 200 void SetKeyboardInfo(float height); 201 GetKeyboardOrientation()202 int32_t GetKeyboardOrientation() const 203 { 204 return keyboardOrientation_; 205 } 206 GetRawKeyboardHeight()207 float GetRawKeyboardHeight() const 208 { 209 return rawKeyboardHeight_; 210 } 211 SetRawKeyboardHeight(float height)212 void SetRawKeyboardHeight(float height) 213 { 214 rawKeyboardHeight_ = height; 215 } 216 KeyboardSafeAreaEnabled()217 bool KeyboardSafeAreaEnabled() const 218 { 219 return keyboardSafeAreaEnabled_; 220 } 221 222 SafeAreaInsets GetCombinedSafeArea(const SafeAreaExpandOpts& opts) const; 223 GetGeoRestoreNodes()224 const std::set<WeakPtr<FrameNode>>& GetGeoRestoreNodes() const 225 { 226 return geoRestoreNodes_; 227 } 228 AddGeoRestoreNode(const WeakPtr<FrameNode> & node)229 void AddGeoRestoreNode(const WeakPtr<FrameNode>& node) 230 { 231 geoRestoreNodes_.insert(node); 232 } 233 AddNeedExpandNode(const WeakPtr<FrameNode> & node)234 void AddNeedExpandNode(const WeakPtr<FrameNode>& node) 235 { 236 needExpandNodes_.insert(node); 237 } 238 239 std::vector<WeakPtr<FrameNode>> GetExpandNodeSet(); 240 241 bool AddNodeToExpandListIfNeeded(const WeakPtr<FrameNode>& node); 242 ClearNeedExpandNode()243 void ClearNeedExpandNode() 244 { 245 needExpandNodes_.clear(); 246 } 247 RemoveRestoreNode(const WeakPtr<FrameNode> & node)248 void RemoveRestoreNode(const WeakPtr<FrameNode>& node) 249 { 250 geoRestoreNodes_.erase(node); 251 } 252 GetSafeAreaCurve()253 RefPtr<InterpolatingSpring> GetSafeAreaCurve() const 254 { 255 return safeAreaCurve_; 256 } 257 void ExpandSafeArea(); 258 259 OffsetF GetWindowWrapperOffset(); 260 261 SafeAreaInsets GetSafeAreaWithoutProcess() const; 262 263 bool SetIsFullScreen(bool value); 264 bool SetIsNeedAvoidWindow(bool value); 265 bool SetIgnoreSafeArea(bool value); 266 bool SetKeyBoardAvoidMode(KeyBoardAvoidMode value); 267 268 KeyBoardAvoidMode GetKeyBoardAvoidMode(); 269 IsIgnoreSafeArea()270 bool IsIgnoreSafeArea() 271 { 272 return ignoreSafeArea_; 273 } 274 IsNeedAvoidWindow()275 bool IsNeedAvoidWindow() 276 { 277 return isNeedAvoidWindow_; 278 } 279 IsFullScreen()280 bool IsFullScreen() 281 { 282 return isFullScreen_; 283 } 284 285 bool SetIsAtomicService(bool value); 286 bool IsAtomicService() const; 287 GetSafeHeight()288 float GetSafeHeight() const 289 { 290 Dimension safeDistance = 16.0_vp; 291 return safeDistance.ConvertToPx(); 292 } 293 SetLastKeyboardPoistion(float position)294 void SetLastKeyboardPoistion(float position) 295 { 296 lastKeyboardY_ = position; 297 } 298 GetLastKeyboardPoistion()299 float GetLastKeyboardPoistion() const 300 { 301 return lastKeyboardY_; 302 } 303 304 bool IsSafeAreaValid() const; 305 306 // check if the page node needs to be avoid keyboard 307 bool CheckPageNeedAvoidKeyboard(const RefPtr<FrameNode>& frameNode); 308 309 PaddingPropertyF SafeAreaToPadding( 310 bool withoutProcess = false, LayoutSafeAreaType ignoreType = LAYOUT_SAFE_AREA_TYPE_SYSTEM); 311 SetWindowTypeConfig(bool isAppWindow,bool isSystemWindow,bool isSceneBoardWindow)312 void SetWindowTypeConfig(bool isAppWindow, bool isSystemWindow, bool isSceneBoardWindow) 313 { 314 windowTypeConfig_ = WindowTypeConfig(isAppWindow, isSystemWindow, isSceneBoardWindow); 315 } 316 GetWindowTypeConfig()317 WindowTypeConfig GetWindowTypeConfig() 318 { 319 return windowTypeConfig_; 320 } 321 GetkeyboardHeightConsideringUIExtension()322 uint32_t GetkeyboardHeightConsideringUIExtension() 323 { 324 return keyboardHeightConsideringUIExtension_; 325 } 326 SetkeyboardHeightConsideringUIExtension(uint32_t height)327 void SetkeyboardHeightConsideringUIExtension(uint32_t height) 328 { 329 if (keyboardHeightConsideringUIExtension_ != height) { 330 for (const auto& [nodeId, callback] : keyboardChangeCbsConsideringUIExt_) { 331 if (callback) { 332 callback(); 333 } 334 } 335 keyboardHeightConsideringUIExtension_ = height; 336 } 337 } 338 AddKeyboardChangeCallbackConsideringUIExt(int32_t nodeId,const std::function<void ()> & callback)339 void AddKeyboardChangeCallbackConsideringUIExt(int32_t nodeId, const std::function<void()>& callback) 340 { 341 keyboardChangeCbsConsideringUIExt_[nodeId] = callback; 342 } 343 RemoveKeyboardChangeCallbackConsideringUIExt(int32_t nodeId)344 void RemoveKeyboardChangeCallbackConsideringUIExt(int32_t nodeId) 345 { 346 keyboardChangeCbsConsideringUIExt_.erase(nodeId); 347 } 348 SetUseCutout(bool useCutout)349 void SetUseCutout(bool useCutout) 350 { 351 useCutout_ = useCutout; 352 } 353 GetUseCutout()354 bool GetUseCutout() 355 { 356 return useCutout_; 357 } 358 GetKeyboardInsetImpl()359 SafeAreaInsets::Inset GetKeyboardInsetImpl() 360 { 361 return getKeyboardInset ? getKeyboardInset(this) : GetKeyboardInset(); 362 } 363 SetKeyboardInsetImpl(std::function<SafeAreaInsets::Inset (SafeAreaManager *)> method)364 void SetKeyboardInsetImpl(std::function<SafeAreaInsets::Inset(SafeAreaManager*)> method) 365 { 366 getKeyboardInset = method; 367 } 368 369 private: 370 bool isAtomicService_ = false; 371 372 // app window is full screen 373 // todo: remove and only use isNeedAvoidWindow_ 374 bool isFullScreen_ = false; 375 376 /** 377 * @brief Indicates whether the UI within the current window type needs to avoid SafeAreaInsets. 378 */ 379 bool isNeedAvoidWindow_ = false; 380 381 /** 382 * @brief Indicates whether to ignore the SafeAreaInsets, specified by the developer from frontend. 383 */ 384 bool ignoreSafeArea_ = false; 385 386 /** 387 * @brief Indicates whether the keyboard safe area is enabled. When enabled, UI avoids the keyboard inset and the 388 * Page is compressed when the keyboard is up. When disabled, the size of Page doesn't change, but Page would 389 * offset vertically according to [keyboardOffset_] when [keyboardAvoidMode_] is OFFSET or stay still when 390 * [keyboardAvoidMode_] is NONE. 391 */ 392 bool keyboardSafeAreaEnabled_ = false; 393 394 bool useCutout_ = false; 395 396 KeyBoardAvoidMode keyboardAvoidMode_ = KeyBoardAvoidMode::OFFSET; 397 bool IsModeResize(); 398 bool IsModeOffset(); 399 400 SafeAreaInsets systemSafeArea_; 401 SafeAreaInsets cutoutSafeArea_; 402 SafeAreaInsets navSafeArea_; 403 // keyboard is bottom direction only 404 SafeAreaInsets::Inset keyboardInset_; 405 SafeAreaInsets::Inset keyboardWebInset_; 406 407 std::optional<SafeAreaInsets> scbSystemSafeArea_; 408 std::optional<SafeAreaInsets> scbCutoutSafeArea_; 409 std::optional<SafeAreaInsets> scbNavSafeArea_; 410 411 WindowTypeConfig windowTypeConfig_; 412 413 /** 414 * @brief A set of weak pointers to FrameNode objects whose geometry info are saved before their SafeArea 415 * expansion. The geometry info of these nodes need to be restored when their next Layout task begins. 416 */ 417 std::set<WeakPtr<FrameNode>> geoRestoreNodes_; 418 419 struct DepthCompare { operatorDepthCompare420 bool operator()(const WeakPtr<FrameNode>& a, const WeakPtr<FrameNode>& b) const 421 { 422 auto ptrA = a.Upgrade(); 423 auto ptrB = b.Upgrade(); 424 if (!ptrA || !ptrB) { 425 return false; 426 } 427 if (ptrA->GetDepth() < ptrB->GetDepth()) { 428 return true; 429 } 430 if (ptrA->GetDepth() == ptrB->GetDepth()) { 431 return ptrA < ptrB; 432 } 433 return false; 434 } 435 }; 436 std::set<WeakPtr<FrameNode>, DepthCompare> needExpandNodes_; 437 // amount of offset to apply to Page when keyboard is up 438 float keyboardOffset_ = 0.0f; 439 float lastKeyboardY_ = 0.0f; 440 float rawKeyboardHeight_ = 0.0f; 441 int32_t keyboardOrientation_ = -1; 442 443 static constexpr float SAFE_AREA_VELOCITY = 0.0f; 444 static constexpr float SAFE_AREA_MASS = 1.0f; 445 static constexpr float SAFE_AREA_STIFFNESS = 228.0f; 446 static constexpr float SAFE_AREA_DAMPING = 30.0f; 447 RefPtr<InterpolatingSpring> safeAreaCurve_ = AceType::MakeRefPtr<InterpolatingSpring>( 448 SAFE_AREA_VELOCITY, SAFE_AREA_MASS, SAFE_AREA_STIFFNESS, SAFE_AREA_DAMPING); 449 450 uint32_t keyboardHeightConsideringUIExtension_ = 0; 451 std::unordered_map<int32_t, std::function<void()>> keyboardChangeCbsConsideringUIExt_; 452 453 std::function<SafeAreaInsets::Inset(SafeAreaManager*)> getKeyboardInset = nullptr; 454 455 ACE_DISALLOW_COPY_AND_MOVE(SafeAreaManager); 456 }; 457 } // namespace OHOS::Ace::NG 458 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_MANAGER_SAFE_AREA_SAFE_AREA_MANAGER_H 459