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