1 /*
2 * Copyright (c) 2021-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 #include "window_layout_policy.h"
17 #include "display_manager_service_inner.h"
18 #include "persistent_storage.h"
19 #include "remote_animation.h"
20 #include "window_helper.h"
21 #include "window_inner_manager.h"
22 #include "window_manager_hilog.h"
23 #include "window_manager_service_utils.h"
24 #include "wm_common_inner.h"
25 #include "wm_math.h"
26 #include <transaction/rs_sync_transaction_controller.h>
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Layout"};
32 }
33
34 uint32_t WindowLayoutPolicy::floatingBottomPosY_ = 0;
35 uint32_t WindowLayoutPolicy::maxFloatingWindowSize_ = 1920; // 1920: default max size of floating window
36
WindowLayoutPolicy(DisplayGroupWindowTree & displayGroupWindowTree)37 WindowLayoutPolicy::WindowLayoutPolicy(DisplayGroupWindowTree& displayGroupWindowTree)
38 : displayGroupWindowTree_(displayGroupWindowTree)
39 {
40 limitRectMap_ = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
41 }
42
Launch()43 void WindowLayoutPolicy::Launch()
44 {
45 WLOGI("WindowLayoutPolicy::Launch");
46 }
47
Reorder()48 void WindowLayoutPolicy::Reorder()
49 {
50 WLOGI("WindowLayoutPolicy::Reorder");
51 }
52
LimitWindowToBottomRightCorner(const sptr<WindowNode> & node)53 void WindowLayoutPolicy::LimitWindowToBottomRightCorner(const sptr<WindowNode>& node)
54 {
55 Rect windowRect = node->GetRequestRect();
56 Rect displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
57 windowRect.posX_ = std::max(windowRect.posX_, displayRect.posX_);
58 windowRect.posY_ = std::max(windowRect.posY_, displayRect.posY_);
59 windowRect.width_ = std::min(windowRect.width_, displayRect.width_);
60 windowRect.height_ = std::min(windowRect.height_, displayRect.height_);
61
62 if (windowRect.posX_ + static_cast<int32_t>(windowRect.width_) >
63 displayRect.posX_ + static_cast<int32_t>(displayRect.width_)) {
64 windowRect.posX_ = displayRect.posX_ + static_cast<int32_t>(displayRect.width_) -
65 static_cast<int32_t>(windowRect.width_);
66 }
67
68 if (windowRect.posY_ + static_cast<int32_t>(windowRect.height_) >
69 displayRect.posY_ + static_cast<int32_t>(displayRect.height_)) {
70 windowRect.posY_ = displayRect.posY_ + static_cast<int32_t>(displayRect.height_) -
71 static_cast<int32_t>(windowRect.height_);
72 }
73 node->SetRequestRect(windowRect);
74
75 WLOGD("WindowId: %{public}d, newRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
76 node->GetWindowId(), windowRect.posX_, windowRect.posY_, windowRect.width_, windowRect.height_);
77
78 for (auto& childNode : node->children_) {
79 LimitWindowToBottomRightCorner(childNode);
80 }
81 }
82
UpdateDisplayGroupRect()83 void WindowLayoutPolicy::UpdateDisplayGroupRect()
84 {
85 Rect newDisplayGroupRect = { 0, 0, 0, 0 };
86 // current multi-display is only support left-right combination, maxNum is two
87 for (auto& elem : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
88 newDisplayGroupRect.posX_ = std::min(displayGroupRect_.posX_, elem.second.posX_);
89 newDisplayGroupRect.posY_ = std::min(displayGroupRect_.posY_, elem.second.posY_);
90 newDisplayGroupRect.width_ += elem.second.width_;
91 int32_t maxHeight = std::max(newDisplayGroupRect.posY_ + static_cast<int32_t>(newDisplayGroupRect.height_),
92 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
93 newDisplayGroupRect.height_ = maxHeight - newDisplayGroupRect.posY_;
94 }
95 displayGroupRect_ = newDisplayGroupRect;
96 WLOGD("Update displayGroupRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
97 displayGroupRect_.posX_, displayGroupRect_.posY_, displayGroupRect_.width_, displayGroupRect_.height_);
98 }
99
UpdateDisplayGroupLimitRect()100 void WindowLayoutPolicy::UpdateDisplayGroupLimitRect()
101 {
102 auto firstDisplayLimitRect = limitRectMap_.begin()->second;
103 Rect newDisplayGroupLimitRect = { firstDisplayLimitRect.posX_, firstDisplayLimitRect.posY_, 0, 0 };
104 for (auto& elem : limitRectMap_) {
105 newDisplayGroupLimitRect.posX_ = std::min(newDisplayGroupLimitRect.posX_, elem.second.posX_);
106 newDisplayGroupLimitRect.posY_ = std::min(newDisplayGroupLimitRect.posY_, elem.second.posY_);
107
108 int32_t maxWidth = std::max(newDisplayGroupLimitRect.posX_ +
109 static_cast<int32_t>(newDisplayGroupLimitRect.width_),
110 elem.second.posX_+ static_cast<int32_t>(elem.second.width_));
111
112 int32_t maxHeight = std::max(newDisplayGroupLimitRect.posY_ +
113 static_cast<int32_t>(newDisplayGroupLimitRect.height_),
114 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
115 newDisplayGroupLimitRect.width_ = static_cast<uint32_t>(maxWidth - newDisplayGroupLimitRect.posX_);
116 newDisplayGroupLimitRect.height_ = static_cast<uint32_t>(maxHeight - newDisplayGroupLimitRect.posY_);
117 }
118 displayGroupLimitRect_ = newDisplayGroupLimitRect;
119 WLOGFD("Update displayGroupLimitRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
120 displayGroupLimitRect_.posX_, displayGroupLimitRect_.posY_,
121 displayGroupLimitRect_.width_, displayGroupLimitRect_.height_);
122 }
123
UpdateRectInDisplayGroup(const sptr<WindowNode> & node,const Rect & oriDisplayRect,const Rect & newDisplayRect)124 void WindowLayoutPolicy::UpdateRectInDisplayGroup(const sptr<WindowNode>& node,
125 const Rect& oriDisplayRect,
126 const Rect& newDisplayRect)
127 {
128 Rect newRect = node->GetRequestRect();
129 WLOGD("Before update rect in display group, windowId: %{public}d, rect: [%{public}d, %{public}d, "
130 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
131
132 newRect.posX_ = newRect.posX_ - oriDisplayRect.posX_ + newDisplayRect.posX_;
133 newRect.posY_ = newRect.posY_ - oriDisplayRect.posY_ + newDisplayRect.posY_;
134 node->SetRequestRect(newRect);
135 WLOGD("After update rect in display group, windowId: %{public}d, newRect: [%{public}d, %{public}d, "
136 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
137
138 for (auto& childNode : node->children_) {
139 UpdateRectInDisplayGroup(childNode, oriDisplayRect, newDisplayRect);
140 }
141 }
142
IsMultiDisplay()143 bool WindowLayoutPolicy::IsMultiDisplay()
144 {
145 return isMultiDisplay_;
146 }
147
UpdateMultiDisplayFlag()148 void WindowLayoutPolicy::UpdateMultiDisplayFlag()
149 {
150 if (DisplayGroupInfo::GetInstance().GetAllDisplayIds().size() > 1) {
151 isMultiDisplay_ = true;
152 WLOGFD("Current mode is multi-display");
153 } else {
154 isMultiDisplay_ = false;
155 WLOGFD("Current mode is not multi-display");
156 }
157 }
158
UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,const Rect & oriDisplayRect,const Rect & newDisplayRect)159 void WindowLayoutPolicy::UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,
160 const Rect& oriDisplayRect,
161 const Rect& newDisplayRect)
162 {
163 WLOGFD("DisplayId: %{public}" PRIu64", oriDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d] "
164 "newDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d]",
165 displayId, oriDisplayRect.posX_, oriDisplayRect.posY_, oriDisplayRect.width_, oriDisplayRect.height_,
166 newDisplayRect.posX_, newDisplayRect.posY_, newDisplayRect.width_, newDisplayRect.height_);
167
168 auto& displayWindowTree = displayGroupWindowTree_[displayId];
169 for (auto& iter : displayWindowTree) {
170 auto& nodeVector = *(iter.second);
171 for (auto& node : nodeVector) {
172 if (!node->isShowingOnMultiDisplays_) {
173 UpdateRectInDisplayGroup(node, oriDisplayRect, newDisplayRect);
174 }
175 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
176 LimitWindowToBottomRightCorner(node);
177 }
178 }
179 WLOGFD("Recalculate window rect in display group, displayId: %{public}" PRIu64", rootType: %{public}d",
180 displayId, iter.first);
181 }
182 }
183
UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId,Rect> & displayRectMap)184 void WindowLayoutPolicy::UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId, Rect>& displayRectMap)
185 {
186 for (auto& elem : displayRectMap) {
187 auto& displayId = elem.first;
188 auto& displayRect = elem.second;
189 DisplayGroupInfo::GetInstance().SetDisplayRect(displayId, displayRect);
190 }
191 }
192
PostProcessWhenDisplayChange()193 void WindowLayoutPolicy::PostProcessWhenDisplayChange()
194 {
195 DisplayGroupInfo::GetInstance().UpdateLeftAndRightDisplayId();
196 UpdateMultiDisplayFlag();
197 Launch();
198 }
199
ProcessDisplayCreate(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)200 void WindowLayoutPolicy::ProcessDisplayCreate(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
201 {
202 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
203 // check displayId and displayRectMap size
204 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
205 displayRectMap.size() != oriDisplayRectMap.size()) {
206 WLOGFE("current display is exited or displayInfo map size is error, displayId: %{public}" PRIu64"", displayId);
207 return;
208 }
209 for (auto& elem : displayRectMap) {
210 auto iter = oriDisplayRectMap.find(elem.first);
211 if (iter != oriDisplayRectMap.end()) {
212 const auto& oriDisplayRect = iter->second;
213 const auto& newDisplayRect = elem.second;
214 UpdateRectInDisplayGroupForAllNodes(elem.first, oriDisplayRect, newDisplayRect);
215 } else {
216 if (elem.first != displayId) {
217 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
218 return;
219 }
220 }
221 }
222 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
223 PostProcessWhenDisplayChange();
224 WLOGI("Process display create, displayId: %{public}" PRIu64"", displayId);
225 }
226
ProcessDisplayDestroy(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)227 void WindowLayoutPolicy::ProcessDisplayDestroy(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
228 {
229 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
230 // check displayId and displayRectMap size
231 if (oriDisplayRectMap.find(displayId) != oriDisplayRectMap.end() ||
232 displayRectMap.size() != oriDisplayRectMap.size()) {
233 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
234 displayId);
235 return;
236 }
237 for (auto oriIter = oriDisplayRectMap.begin(); oriIter != oriDisplayRectMap.end();) {
238 auto newIter = displayRectMap.find(oriIter->first);
239 if (newIter != displayRectMap.end()) {
240 const auto& oriDisplayRect = oriIter->second;
241 const auto& newDisplayRect = newIter->second;
242 UpdateRectInDisplayGroupForAllNodes(oriIter->first, oriDisplayRect, newDisplayRect);
243 } else {
244 if (oriIter->first != displayId) {
245 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
246 return;
247 }
248 }
249 ++oriIter;
250 }
251
252 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
253 PostProcessWhenDisplayChange();
254 WLOGI("Process display destroy, displayId: %{public}" PRIu64"", displayId);
255 }
256
ProcessDisplaySizeChangeOrRotation(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)257 void WindowLayoutPolicy::ProcessDisplaySizeChangeOrRotation(DisplayId displayId,
258 const std::map<DisplayId, Rect>& displayRectMap)
259 {
260 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
261 // check displayId and displayRectMap size
262 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
263 displayRectMap.size() != oriDisplayRectMap.size()) {
264 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
265 displayId);
266 return;
267 }
268
269 for (auto& elem : displayRectMap) {
270 auto iter = oriDisplayRectMap.find(elem.first);
271 if (iter != oriDisplayRectMap.end()) {
272 UpdateRectInDisplayGroupForAllNodes(elem.first, iter->second, elem.second);
273 }
274 }
275
276 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
277 PostProcessWhenDisplayChange();
278 WLOGI("Process display change, displayId: %{public}" PRIu64"", displayId);
279 }
280
ProcessDisplayVprChange(DisplayId displayId)281 void WindowLayoutPolicy::ProcessDisplayVprChange(DisplayId displayId)
282 {
283 Launch();
284 }
285
LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>> & nodeVec)286 void WindowLayoutPolicy::LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>>& nodeVec)
287 {
288 if (nodeVec.empty()) {
289 WLOGW("The node vector is empty!");
290 return;
291 }
292 for (auto& node : nodeVec) {
293 LayoutWindowNode(node);
294 }
295 }
296
NotifyAnimationSizeChangeIfNeeded()297 void WindowLayoutPolicy::NotifyAnimationSizeChangeIfNeeded()
298 {
299 if (!RemoteAnimation::CheckAnimationController()) {
300 WLOGFD("no animation controller!");
301 return;
302 }
303 std::vector<uint32_t> fullScreenWinIds;
304 std::vector<uint32_t> floatMainIds;
305 for (auto& iter : displayGroupWindowTree_) {
306 auto& displayWindowTree = iter.second;
307 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]);
308 if (nodeVec.empty()) {
309 WLOGE("The node vector is empty!");
310 return;
311 }
312 for (auto& node : nodeVec) {
313 // just has one fullscreen app node on foreground
314 if (WindowHelper::IsMainFullScreenWindow(node->GetWindowType(), node->GetWindowMode())) {
315 fullScreenWinIds.emplace_back(node->GetWindowId());
316 }
317 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
318 floatMainIds.emplace_back(node->GetWindowId());
319 }
320 }
321 }
322 RemoteAnimation::NotifyAnimationTargetsUpdate(fullScreenWinIds, floatMainIds);
323 }
324
LayoutWindowTree(DisplayId displayId)325 void WindowLayoutPolicy::LayoutWindowTree(DisplayId displayId)
326 {
327 // reset limit rect
328 limitRectMap_[displayId] = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
329 displayGroupLimitRect_ = displayGroupRect_;
330
331 // ensure that the avoid area windows are traversed first
332 auto& displayWindowTree = displayGroupWindowTree_[displayId];
333 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
334 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
335 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
336 }
337
LayoutWindowNode(const sptr<WindowNode> & node)338 void WindowLayoutPolicy::LayoutWindowNode(const sptr<WindowNode>& node)
339 {
340 if (node == nullptr || node->parent_ == nullptr) {
341 WLOGFE("Node or it's parent is nullptr");
342 return;
343 }
344 if (!node->currentVisibility_) {
345 WLOGFD("window[%{public}u] currently not visible, no need to layout", node->GetWindowId());
346 return;
347 }
348
349 /*
350 * 1. update window rect
351 * 2. update diplayLimitRect and displayGroupRect if this is avoidNode
352 */
353 UpdateLayoutRect(node);
354 if (WindowHelper::IsSystemBarWindow(node->GetWindowType())) {
355 UpdateDisplayLimitRect(node, limitRectMap_[node->GetDisplayId()]);
356 UpdateDisplayGroupLimitRect();
357 WindowInnerManager::GetInstance().NotifyDisplayLimitRectChange(limitRectMap_);
358 }
359 for (auto& childNode : node->children_) {
360 LayoutWindowNode(childNode);
361 }
362 }
363
IsVerticalDisplay(DisplayId displayId) const364 bool WindowLayoutPolicy::IsVerticalDisplay(DisplayId displayId) const
365 {
366 return DisplayGroupInfo::GetInstance().GetDisplayRect(displayId).width_ <
367 DisplayGroupInfo::GetInstance().GetDisplayRect(displayId).height_;
368 }
369
NotifyClientAndAnimation(const sptr<WindowNode> & node,const Rect & winRect,WindowSizeChangeReason reason)370 void WindowLayoutPolicy::NotifyClientAndAnimation(const sptr<WindowNode>& node,
371 const Rect& winRect, WindowSizeChangeReason reason)
372 {
373 if (node->GetWindowToken()) {
374 auto type = node->GetWindowType();
375 auto syncTransactionController = RSSyncTransactionController::GetInstance();
376 if (reason == WindowSizeChangeReason::ROTATION && syncTransactionController && IsNeedAnimationSync(type)) {
377 node->GetWindowToken()->UpdateWindowRect(winRect, node->GetDecoStatus(), reason,
378 syncTransactionController->GetRSTransaction());
379 } else {
380 node->GetWindowToken()->UpdateWindowRect(winRect, node->GetDecoStatus(), reason);
381 }
382 WLOGFD("Id: %{public}d, winRect:[%{public}d, %{public}d, %{public}u, %{public}u], reason: "
383 "%{public}u", node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_, reason);
384 }
385 if ((reason != WindowSizeChangeReason::MOVE) && (node->GetWindowType() != WindowType::WINDOW_TYPE_DOCK_SLICE)) {
386 node->ResetWindowSizeChangeReason();
387 }
388 NotifyAnimationSizeChangeIfNeeded();
389 }
390
IsNeedAnimationSync(WindowType type)391 bool WindowLayoutPolicy::IsNeedAnimationSync(WindowType type)
392 {
393 if (type == WindowType::WINDOW_TYPE_POINTER ||
394 type == WindowType::WINDOW_TYPE_BOOT_ANIMATION) {
395 return false;
396 }
397 return true;
398 }
399
CalcEntireWindowHotZone(const sptr<WindowNode> & node,const Rect & winRect,uint32_t hotZone,float vpr,TransformHelper::Vector2 hotZoneScale)400 Rect WindowLayoutPolicy::CalcEntireWindowHotZone(const sptr<WindowNode>& node, const Rect& winRect, uint32_t hotZone,
401 float vpr, TransformHelper::Vector2 hotZoneScale)
402 {
403 Rect rect = winRect;
404 uint32_t hotZoneX = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.x_);
405 uint32_t hotZoneY = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.y_);
406
407 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
408 if (rect.width_ < rect.height_) {
409 rect.posX_ -= static_cast<int32_t>(hotZoneX);
410 rect.width_ += (hotZoneX + hotZoneX);
411 } else {
412 rect.posY_ -= static_cast<int32_t>(hotZoneY);
413 rect.height_ += (hotZoneY + hotZoneY);
414 }
415 } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
416 rect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
417 } else if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
418 rect.posX_ -= static_cast<int32_t>(hotZoneX);
419 rect.posY_ -= static_cast<int32_t>(hotZoneY);
420 rect.width_ += (hotZoneX + hotZoneX);
421 rect.height_ += (hotZoneY + hotZoneY);
422 }
423 return rect;
424 }
425
CalcAndSetNodeHotZone(const Rect & winRect,const sptr<WindowNode> & node)426 void WindowLayoutPolicy::CalcAndSetNodeHotZone(const Rect& winRect, const sptr<WindowNode>& node)
427 {
428 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
429 TransformHelper::Vector2 hotZoneScale(1, 1);
430 if (node->GetWindowProperty()->isNeedComputerTransform()) {
431 node->ComputeTransform();
432 hotZoneScale = WindowHelper::CalculateHotZoneScale(node->GetWindowProperty()->GetTransformMat());
433 }
434
435 auto hotZoneRectTouch = CalcEntireWindowHotZone(node, winRect, HOTZONE_TOUCH, virtualPixelRatio, hotZoneScale);
436 auto hotZoneRectPointer = CalcEntireWindowHotZone(node, winRect, HOTZONE_POINTER, virtualPixelRatio, hotZoneScale);
437
438 node->SetEntireWindowTouchHotArea(hotZoneRectTouch);
439 node->SetEntireWindowPointerHotArea(hotZoneRectPointer);
440
441 std::vector<Rect> requestedHotAreas;
442 node->GetWindowProperty()->GetTouchHotAreas(requestedHotAreas);
443 std::vector<Rect> touchHotAreas;
444 std::vector<Rect> pointerHotAreas;
445 if (requestedHotAreas.empty()) {
446 touchHotAreas.emplace_back(hotZoneRectTouch);
447 pointerHotAreas.emplace_back(hotZoneRectPointer);
448 } else {
449 if (!WindowHelper::CalculateTouchHotAreas(winRect, requestedHotAreas, touchHotAreas)) {
450 WLOGFW("some parameters in requestedHotAreas are abnormal");
451 }
452 pointerHotAreas = touchHotAreas;
453 }
454 node->SetTouchHotAreas(touchHotAreas);
455 node->SetPointerHotAreas(pointerHotAreas);
456 }
457
GetSystemSizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,float vpr)458 WindowSizeLimits WindowLayoutPolicy::GetSystemSizeLimits(const sptr<WindowNode>& node,
459 const Rect& displayRect, float vpr)
460 {
461 WindowSizeLimits systemLimits;
462 systemLimits.maxWidth_ = static_cast<uint32_t>(maxFloatingWindowSize_ * vpr);
463 systemLimits.maxHeight_ = static_cast<uint32_t>(maxFloatingWindowSize_ * vpr);
464
465 // Float camera window has a special limit:
466 // if display sw <= 600dp, portrait: min width = display sw * 30%, landscape: min width = sw * 50%
467 // if display sw > 600dp, portrait: min width = display sw * 12%, landscape: min width = sw * 30%
468 if (node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
469 uint32_t smallWidth = displayRect.height_ <= displayRect.width_ ? displayRect.height_ : displayRect.width_;
470 float hwRatio = static_cast<float>(displayRect.height_) / static_cast<float>(displayRect.width_);
471 if (smallWidth <= static_cast<uint32_t>(600 * vpr)) { // sw <= 600dp
472 if (displayRect.width_ <= displayRect.height_) {
473 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
474 } else {
475 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.5); // min width = display sw * 0.5
476 }
477 } else {
478 if (displayRect.width_ <= displayRect.height_) {
479 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.12); // min width = display sw * 0.12
480 } else {
481 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
482 }
483 }
484 systemLimits.minHeight_ = static_cast<uint32_t>(systemLimits.minWidth_ * hwRatio);
485 } else {
486 systemLimits.minWidth_ = static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr);
487 systemLimits.minHeight_ = static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr);
488 }
489 WLOGFD("[System SizeLimits] [maxWidth: %{public}u, minWidth: %{public}u, maxHeight: %{public}u, "
490 "minHeight: %{public}u]", systemLimits.maxWidth_, systemLimits.minWidth_,
491 systemLimits.maxHeight_, systemLimits.minHeight_);
492 return systemLimits;
493 }
494
UpdateWindowSizeLimits(const sptr<WindowNode> & node)495 void WindowLayoutPolicy::UpdateWindowSizeLimits(const sptr<WindowNode>& node)
496 {
497 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
498 const auto& virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
499 const auto& systemLimits = GetSystemSizeLimits(node, displayRect, virtualPixelRatio);
500 const auto& customizedLimits = node->GetWindowSizeLimits();
501
502 WindowSizeLimits newLimits = systemLimits;
503
504 // configured limits of floating window
505 uint32_t configuredMaxWidth = static_cast<uint32_t>(customizedLimits.maxWidth_ * virtualPixelRatio);
506 uint32_t configuredMaxHeight = static_cast<uint32_t>(customizedLimits.maxHeight_ * virtualPixelRatio);
507 uint32_t configuredMinWidth = static_cast<uint32_t>(customizedLimits.minWidth_ * virtualPixelRatio);
508 uint32_t configuredMinHeight = static_cast<uint32_t>(customizedLimits.minHeight_ * virtualPixelRatio);
509
510 // calculate new limit size
511 if (systemLimits.minWidth_ <= configuredMaxWidth && configuredMaxWidth <= systemLimits.maxWidth_) {
512 newLimits.maxWidth_ = configuredMaxWidth;
513 }
514 if (systemLimits.minHeight_ <= configuredMaxHeight && configuredMaxHeight <= systemLimits.maxHeight_) {
515 newLimits.maxHeight_ = configuredMaxHeight;
516 }
517 if (systemLimits.minWidth_ <= configuredMinWidth && configuredMinWidth <= newLimits.maxWidth_) {
518 newLimits.minWidth_ = configuredMinWidth;
519 }
520 if (systemLimits.minHeight_ <= configuredMinHeight && configuredMinHeight <= newLimits.maxHeight_) {
521 newLimits.minHeight_ = configuredMinHeight;
522 }
523
524 // calculate new limit ratio
525 newLimits.maxRatio_ = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
526 newLimits.minRatio_ = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
527 if (newLimits.minRatio_ <= customizedLimits.maxRatio_ && customizedLimits.maxRatio_ <= newLimits.maxRatio_) {
528 newLimits.maxRatio_ = customizedLimits.maxRatio_;
529 }
530 if (newLimits.minRatio_ <= customizedLimits.minRatio_ && customizedLimits.minRatio_ <= newLimits.maxRatio_) {
531 newLimits.minRatio_ = customizedLimits.minRatio_;
532 }
533
534 // recalculate limit size by new ratio
535 uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * newLimits.maxRatio_);
536 newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
537 uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * newLimits.minRatio_);
538 newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
539 uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / newLimits.minRatio_);
540 newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
541 uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / newLimits.maxRatio_);
542 newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
543
544 WLOGFD("[Update SizeLimits] winId: %{public}u, Width: [max:%{public}u, min:%{public}u], Height: [max:%{public}u, "
545 "min:%{public}u], Ratio: [max:%{public}f, min:%{public}f]", node->GetWindowId(), newLimits.maxWidth_,
546 newLimits.minWidth_, newLimits.maxHeight_, newLimits.minHeight_, newLimits.maxRatio_, newLimits.minRatio_);
547 node->SetWindowUpdatedSizeLimits(newLimits);
548 }
549
GetAvoidPosType(const Rect & rect,DisplayId displayId) const550 AvoidPosType WindowLayoutPolicy::GetAvoidPosType(const Rect& rect, DisplayId displayId) const
551 {
552 const auto& displayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
553 if (displayRectMap.find(displayId) == std::end(displayRectMap)) {
554 WLOGFE("GetAvoidPosType fail. Get display fail. displayId: %{public}" PRIu64"", displayId);
555 return AvoidPosType::AVOID_POS_UNKNOWN;
556 }
557 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
558 return WindowHelper::GetAvoidPosType(rect, displayRect);
559 }
560
UpdateDisplayLimitRect(const sptr<WindowNode> & node,Rect & limitRect)561 void WindowLayoutPolicy::UpdateDisplayLimitRect(const sptr<WindowNode>& node, Rect& limitRect)
562 {
563 const auto& layoutRect = node->GetWindowRect();
564 int32_t limitH = static_cast<int32_t>(limitRect.height_);
565 int32_t limitW = static_cast<int32_t>(limitRect.width_);
566 int32_t layoutH = static_cast<int32_t>(layoutRect.height_);
567 int32_t layoutW = static_cast<int32_t>(layoutRect.width_);
568 if (node->GetWindowType() == WindowType::WINDOW_TYPE_STATUS_BAR ||
569 node->GetWindowType() == WindowType::WINDOW_TYPE_NAVIGATION_BAR) {
570 auto avoidPosType = GetAvoidPosType(layoutRect, node->GetDisplayId());
571 int32_t offsetH = 0;
572 int32_t offsetW = 0;
573 switch (avoidPosType) {
574 case AvoidPosType::AVOID_POS_TOP:
575 offsetH = layoutRect.posY_ + layoutH - limitRect.posY_;
576 limitRect.posY_ += offsetH;
577 limitH -= offsetH;
578 break;
579 case AvoidPosType::AVOID_POS_BOTTOM:
580 offsetH = limitRect.posY_ + limitH - layoutRect.posY_;
581 limitH -= offsetH;
582 break;
583 case AvoidPosType::AVOID_POS_LEFT:
584 offsetW = layoutRect.posX_ + layoutW - limitRect.posX_;
585 limitRect.posX_ += offsetW;
586 limitW -= offsetW;
587 break;
588 case AvoidPosType::AVOID_POS_RIGHT:
589 offsetW = limitRect.posX_ + limitW - layoutRect.posX_;
590 limitW -= offsetW;
591 break;
592 default:
593 WLOGFE("invalid avoidPosType: %{public}d", avoidPosType);
594 }
595 }
596 limitRect.height_ = static_cast<uint32_t>(limitH < 0 ? 0 : limitH);
597 limitRect.width_ = static_cast<uint32_t>(limitW < 0 ? 0 : limitW);
598 WLOGFD("AvoidNodeId: %{public}d, avoidNodeRect: [%{public}d %{public}d "
599 "%{public}u %{public}u], limitDisplayRect: [%{public}d %{public}d, %{public}u %{public}u]",
600 node->GetWindowId(), layoutRect.posX_, layoutRect.posY_, layoutRect.width_, layoutRect.height_,
601 limitRect.posX_, limitRect.posY_, limitRect.width_, limitRect.height_);
602 }
603
IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>> & nodeVec) const604 bool WindowLayoutPolicy::IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>>& nodeVec) const
605 {
606 for (auto& node : nodeVec) {
607 if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT &&
608 node->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN) {
609 return true;
610 }
611 }
612 return false;
613 }
614
AdjustFixedOrientationRSSurfaceNode(const sptr<WindowNode> & node,const Rect & winRect,std::shared_ptr<RSSurfaceNode> surfaceNode,sptr<DisplayInfo> displayInfo)615 static void AdjustFixedOrientationRSSurfaceNode(const sptr<WindowNode>& node, const Rect& winRect,
616 std::shared_ptr<RSSurfaceNode> surfaceNode, sptr<DisplayInfo> displayInfo)
617 {
618 if (!displayInfo) {
619 WLOGFE("display invaild");
620 return;
621 }
622 auto requestOrientation = node->GetRequestedOrientation();
623 if (!WmsUtils::IsFixedOrientation(requestOrientation, node->GetWindowMode(), node->GetWindowFlags())) {
624 return;
625 }
626
627 auto displayOri = displayInfo->GetDisplayOrientation();
628 auto displayW = displayInfo->GetWidth();
629 auto displayH = displayInfo->GetHeight();
630 if (WINDOW_TO_DISPLAY_ORIENTATION_MAP.count(requestOrientation) == 0) {
631 return;
632 }
633 int32_t diffOrientation = static_cast<int32_t>(WINDOW_TO_DISPLAY_ORIENTATION_MAP.at(requestOrientation)) -
634 static_cast<int32_t>(displayOri);
635 float rotation = (displayInfo->GetIsDefaultVertical() ? -90.f : 90.f) * (diffOrientation); // 90.f is base degree
636 WLOGFD("[FixOrientation] %{public}d adjust display [%{public}d, %{public}d], rotation: %{public}f",
637 node->GetWindowId(), displayW, displayH, rotation);
638 surfaceNode->SetTranslateX((displayW - static_cast<int32_t>(winRect.width_)) / 2); // 2 is half
639 surfaceNode->SetTranslateY((displayH - static_cast<int32_t>(winRect.height_)) / 2); // 2 is half
640 surfaceNode->SetPivotX(0.5); // 0.5 means center
641 surfaceNode->SetPivotY(0.5); // 0.5 means center
642 surfaceNode->SetRotation(rotation);
643 }
644
SetBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)645 static void SetBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
646 {
647 if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT ||
648 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::TRANSFORM) {
649 WLOGI("not need to update bounds");
650 return;
651 }
652
653 WLOGFD("Name:%{public}s id:%{public}u preRect: [%{public}d, %{public}d, %{public}d, %{public}d], "
654 "winRect: [%{public}d, %{public}d, %{public}d, %{public}d], %{public}u", node->GetWindowName().c_str(),
655 node->GetWindowId(), preRect.posX_, preRect.posY_, preRect.width_, preRect.height_,
656 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_, node->GetWindowSizeChangeReason());
657 auto& displayGroupInfo = DisplayGroupInfo::GetInstance();
658 if (node->leashWinSurfaceNode_) {
659 if (winRect != preRect) {
660 // avoid animation interpreted when client coming
661 node->leashWinSurfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
662 }
663 if (node->startingWinSurfaceNode_) {
664 node->startingWinSurfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
665 }
666 if (node->surfaceNode_) {
667 node->surfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
668 }
669 AdjustFixedOrientationRSSurfaceNode(node, winRect, node->leashWinSurfaceNode_,
670 displayGroupInfo.GetDisplayInfo(node->GetDisplayId()));
671 } else if (node->surfaceNode_) {
672 node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
673 AdjustFixedOrientationRSSurfaceNode(node, winRect, node->surfaceNode_,
674 displayGroupInfo.GetDisplayInfo(node->GetDisplayId()));
675 }
676 }
677
UpdateSurfaceBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)678 void WindowLayoutPolicy::UpdateSurfaceBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
679 {
680 wptr<WindowNode> weakNode = node;
681 auto SetBoundsFunc = [weakNode, winRect, preRect]() {
682 auto winNode = weakNode.promote();
683 if (winNode == nullptr) {
684 WLOGI("winNode is nullptr");
685 return;
686 }
687 SetBounds(winNode, winRect, preRect);
688 };
689
690 switch (node->GetWindowSizeChangeReason()) {
691 case WindowSizeChangeReason::MAXIMIZE:
692 [[fallthrough]];
693 case WindowSizeChangeReason::RECOVER: {
694 const RSAnimationTimingProtocol timingProtocol(400); // animation time
695 RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
696 break;
697 }
698 case WindowSizeChangeReason::ROTATION: {
699 if (WmsUtils::IsFixedOrientation(node->GetRequestedOrientation(),
700 node->GetWindowMode(), node->GetWindowFlags())) {
701 auto disInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(node->GetDisplayId());
702 if (disInfo && disInfo->GetDisplayStateChangeType() != DisplayStateChangeType::UPDATE_ROTATION) {
703 WLOGI("[FixOrientation] winNode %{public}u orientation, skip animation", node->GetWindowId());
704 SetBoundsFunc();
705 return;
706 }
707 }
708 const RSAnimationTimingProtocol timingProtocol(600); // animation time
709 const RSAnimationTimingCurve curve_ = RSAnimationTimingCurve::CreateCubicCurve(
710 0.2, 0.0, 0.2, 1.0); // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
711 RSNode::Animate(timingProtocol, curve_, SetBoundsFunc);
712 break;
713 }
714 case WindowSizeChangeReason::FULL_TO_SPLIT:
715 case WindowSizeChangeReason::SPLIT_TO_FULL: {
716 const RSAnimationTimingProtocol timingProtocol(350); // animation time
717 RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
718 break;
719 }
720 case WindowSizeChangeReason::UNDEFINED:
721 [[fallthrough]];
722 default:
723 SetBoundsFunc();
724 }
725 }
726
GetDisplayGroupRect() const727 Rect WindowLayoutPolicy::GetDisplayGroupRect() const
728 {
729 return displayGroupRect_;
730 }
731
SetSplitRatioPoints(DisplayId displayId,const std::vector<int32_t> & splitRatioPoints)732 void WindowLayoutPolicy::SetSplitRatioPoints(DisplayId displayId, const std::vector<int32_t>& splitRatioPoints)
733 {
734 splitRatioPointsMap_[displayId] = splitRatioPoints;
735 }
736
GetDividerRect(DisplayId displayId) const737 Rect WindowLayoutPolicy::GetDividerRect(DisplayId displayId) const
738 {
739 return INVALID_EMPTY_RECT;
740 }
741
IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode> & node)742 bool WindowLayoutPolicy::IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode>& node)
743 {
744 return true;
745 }
746
SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)747 void WindowLayoutPolicy::SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)
748 {
749 floatingBottomPosY_ = floatingBottomPosY;
750 }
751
SetMaxFloatingWindowSize(uint32_t maxSize)752 void WindowLayoutPolicy::SetMaxFloatingWindowSize(uint32_t maxSize)
753 {
754 maxFloatingWindowSize_ = maxSize;
755 }
756
GetStoragedAspectRatio(const sptr<WindowNode> & node)757 void WindowLayoutPolicy::GetStoragedAspectRatio(const sptr<WindowNode>& node)
758 {
759 if (!WindowHelper::IsMainWindow(node->GetWindowType())) {
760 return;
761 }
762
763 std::string abilityName = node->abilityInfo_.abilityName_;
764 std::vector<std::string> nameVector;
765 if (abilityName.size() > 0) {
766 nameVector = WindowHelper::Split(abilityName, ".");
767 }
768 std::string keyName = nameVector.empty() ? node->abilityInfo_.bundleName_ :
769 node->abilityInfo_.bundleName_ + "." + nameVector.back();
770 if (PersistentStorage::HasKey(keyName, PersistentStorageType::ASPECT_RATIO)) {
771 float ratio = 0.0;
772 PersistentStorage::Get(keyName, ratio, PersistentStorageType::ASPECT_RATIO);
773 node->SetAspectRatio(ratio);
774 }
775 }
776
FixWindowRectWithinDisplay(const sptr<WindowNode> & node) const777 void WindowLayoutPolicy::FixWindowRectWithinDisplay(const sptr<WindowNode>& node) const
778 {
779 auto displayId = node->GetDisplayId();
780 const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
781 auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
782 auto type = node->GetWindowType();
783 Rect rect = node->GetRequestRect();
784 switch (type) {
785 case WindowType::WINDOW_TYPE_STATUS_BAR:
786 rect.posY_ = displayRect.posY_;
787 break;
788 case WindowType::WINDOW_TYPE_NAVIGATION_BAR:
789 rect.posY_ = static_cast<int32_t>(displayRect.height_) + displayRect.posY_ -
790 static_cast<int32_t>(rect.height_);
791 break;
792 default:
793 if (!displayInfo->GetWaterfallDisplayCompressionStatus()) {
794 return;
795 }
796 rect.posY_ = std::max(rect.posY_, displayRect.posY_);
797 rect.posY_ = std::min(rect.posY_, displayRect.posY_ + static_cast<int32_t>(displayRect.height_));
798 }
799 node->SetRequestRect(rect);
800 WLOGFD("WinId: %{public}d, requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]",
801 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
802 }
803
GetMaximizeRect(const sptr<WindowNode> & node,Rect & maxRect)804 void WindowLayoutPolicy::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)
805 {
806 WLOGFI("WindowLayoutPolicy GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ",
807 maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_);
808 }
809 }
810 }