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 int32_t right = std::max(newDisplayGroupRect.posX_ + static_cast<int32_t>(newDisplayGroupRect.width_),
91 elem.second.posX_+ static_cast<int32_t>(elem.second.width_));
92 newDisplayGroupRect.width_ = right - newDisplayGroupRect.posX_;
93 int32_t maxHeight = std::max(newDisplayGroupRect.posY_ + static_cast<int32_t>(newDisplayGroupRect.height_),
94 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
95 newDisplayGroupRect.height_ = maxHeight - newDisplayGroupRect.posY_;
96 }
97 displayGroupRect_ = newDisplayGroupRect;
98 WLOGD("Update displayGroupRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
99 displayGroupRect_.posX_, displayGroupRect_.posY_, displayGroupRect_.width_, displayGroupRect_.height_);
100 }
101
UpdateDisplayGroupLimitRect()102 void WindowLayoutPolicy::UpdateDisplayGroupLimitRect()
103 {
104 auto firstDisplayLimitRect = limitRectMap_.begin()->second;
105 Rect newDisplayGroupLimitRect = { firstDisplayLimitRect.posX_, firstDisplayLimitRect.posY_, 0, 0 };
106 for (auto& elem : limitRectMap_) {
107 newDisplayGroupLimitRect.posX_ = std::min(newDisplayGroupLimitRect.posX_, elem.second.posX_);
108 newDisplayGroupLimitRect.posY_ = std::min(newDisplayGroupLimitRect.posY_, elem.second.posY_);
109
110 int32_t maxWidth = std::max(newDisplayGroupLimitRect.posX_ +
111 static_cast<int32_t>(newDisplayGroupLimitRect.width_),
112 elem.second.posX_+ static_cast<int32_t>(elem.second.width_));
113
114 int32_t maxHeight = std::max(newDisplayGroupLimitRect.posY_ +
115 static_cast<int32_t>(newDisplayGroupLimitRect.height_),
116 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
117 newDisplayGroupLimitRect.width_ = static_cast<uint32_t>(maxWidth - newDisplayGroupLimitRect.posX_);
118 newDisplayGroupLimitRect.height_ = static_cast<uint32_t>(maxHeight - newDisplayGroupLimitRect.posY_);
119 }
120 displayGroupLimitRect_ = newDisplayGroupLimitRect;
121 WLOGFD("Update displayGroupLimitRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
122 displayGroupLimitRect_.posX_, displayGroupLimitRect_.posY_,
123 displayGroupLimitRect_.width_, displayGroupLimitRect_.height_);
124 }
125
UpdateRectInDisplayGroup(const sptr<WindowNode> & node,const Rect & oriDisplayRect,const Rect & newDisplayRect)126 void WindowLayoutPolicy::UpdateRectInDisplayGroup(const sptr<WindowNode>& node,
127 const Rect& oriDisplayRect,
128 const Rect& newDisplayRect)
129 {
130 Rect newRect = node->GetRequestRect();
131 WLOGD("Before update rect in display group, windowId: %{public}d, rect: [%{public}d, %{public}d, "
132 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
133
134 newRect.posX_ = newRect.posX_ - oriDisplayRect.posX_ + newDisplayRect.posX_;
135 newRect.posY_ = newRect.posY_ - oriDisplayRect.posY_ + newDisplayRect.posY_;
136 node->SetRequestRect(newRect);
137 WLOGD("After update rect in display group, windowId: %{public}d, newRect: [%{public}d, %{public}d, "
138 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
139
140 for (auto& childNode : node->children_) {
141 UpdateRectInDisplayGroup(childNode, oriDisplayRect, newDisplayRect);
142 }
143 }
144
IsMultiDisplay()145 bool WindowLayoutPolicy::IsMultiDisplay()
146 {
147 return isMultiDisplay_;
148 }
149
UpdateMultiDisplayFlag()150 void WindowLayoutPolicy::UpdateMultiDisplayFlag()
151 {
152 if (DisplayGroupInfo::GetInstance().GetAllDisplayIds().size() > 1) {
153 isMultiDisplay_ = true;
154 WLOGFD("Current mode is multi-display");
155 } else {
156 isMultiDisplay_ = false;
157 WLOGFD("Current mode is not multi-display");
158 }
159 }
160
UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,const Rect & oriDisplayRect,const Rect & newDisplayRect)161 void WindowLayoutPolicy::UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,
162 const Rect& oriDisplayRect,
163 const Rect& newDisplayRect)
164 {
165 WLOGFD("DisplayId: %{public}" PRIu64", oriDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d] "
166 "newDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d]",
167 displayId, oriDisplayRect.posX_, oriDisplayRect.posY_, oriDisplayRect.width_, oriDisplayRect.height_,
168 newDisplayRect.posX_, newDisplayRect.posY_, newDisplayRect.width_, newDisplayRect.height_);
169
170 auto& displayWindowTree = displayGroupWindowTree_[displayId];
171 for (auto& iter : displayWindowTree) {
172 auto& nodeVector = *(iter.second);
173 for (auto& node : nodeVector) {
174 if (!node->isShowingOnMultiDisplays_) {
175 UpdateRectInDisplayGroup(node, oriDisplayRect, newDisplayRect);
176 }
177 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
178 LimitWindowToBottomRightCorner(node);
179 }
180 }
181 WLOGFD("Recalculate window rect in display group, displayId: %{public}" PRIu64", rootType: %{public}d",
182 displayId, iter.first);
183 }
184 }
185
UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId,Rect> & displayRectMap)186 void WindowLayoutPolicy::UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId, Rect>& displayRectMap)
187 {
188 for (auto& elem : displayRectMap) {
189 auto& displayId = elem.first;
190 auto& displayRect = elem.second;
191 DisplayGroupInfo::GetInstance().SetDisplayRect(displayId, displayRect);
192 }
193 }
194
PostProcessWhenDisplayChange()195 void WindowLayoutPolicy::PostProcessWhenDisplayChange()
196 {
197 DisplayGroupInfo::GetInstance().UpdateLeftAndRightDisplayId();
198 UpdateMultiDisplayFlag();
199 Launch();
200 }
201
ProcessDisplayCreate(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)202 void WindowLayoutPolicy::ProcessDisplayCreate(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
203 {
204 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
205 // check displayId and displayRectMap size
206 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
207 displayRectMap.size() != oriDisplayRectMap.size()) {
208 WLOGFE("current display is exited or displayInfo map size is error, displayId: %{public}" PRIu64"", displayId);
209 return;
210 }
211 for (auto& elem : displayRectMap) {
212 auto iter = oriDisplayRectMap.find(elem.first);
213 if (iter != oriDisplayRectMap.end()) {
214 const auto& oriDisplayRect = iter->second;
215 const auto& newDisplayRect = elem.second;
216 UpdateRectInDisplayGroupForAllNodes(elem.first, oriDisplayRect, newDisplayRect);
217 } else {
218 if (elem.first != displayId) {
219 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
220 return;
221 }
222 }
223 }
224 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
225 PostProcessWhenDisplayChange();
226 WLOGI("Process display create, displayId: %{public}" PRIu64"", displayId);
227 }
228
ProcessDisplayDestroy(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)229 void WindowLayoutPolicy::ProcessDisplayDestroy(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
230 {
231 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
232 // check displayId and displayRectMap size
233 if (oriDisplayRectMap.find(displayId) != oriDisplayRectMap.end() ||
234 displayRectMap.size() != oriDisplayRectMap.size()) {
235 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
236 displayId);
237 return;
238 }
239 for (auto oriIter = oriDisplayRectMap.begin(); oriIter != oriDisplayRectMap.end();) {
240 auto newIter = displayRectMap.find(oriIter->first);
241 if (newIter != displayRectMap.end()) {
242 const auto& oriDisplayRect = oriIter->second;
243 const auto& newDisplayRect = newIter->second;
244 UpdateRectInDisplayGroupForAllNodes(oriIter->first, oriDisplayRect, newDisplayRect);
245 } else {
246 if (oriIter->first != displayId) {
247 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
248 return;
249 }
250 }
251 ++oriIter;
252 }
253
254 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
255 PostProcessWhenDisplayChange();
256 WLOGI("Process display destroy, displayId: %{public}" PRIu64"", displayId);
257 }
258
ProcessDisplaySizeChangeOrRotation(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)259 void WindowLayoutPolicy::ProcessDisplaySizeChangeOrRotation(DisplayId displayId,
260 const std::map<DisplayId, Rect>& displayRectMap)
261 {
262 const auto& oriDisplayRectMap = DisplayGroupInfo::GetInstance().GetAllDisplayRects();
263 // check displayId and displayRectMap size
264 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
265 displayRectMap.size() != oriDisplayRectMap.size()) {
266 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
267 displayId);
268 return;
269 }
270
271 for (auto& elem : displayRectMap) {
272 auto iter = oriDisplayRectMap.find(elem.first);
273 if (iter != oriDisplayRectMap.end()) {
274 UpdateRectInDisplayGroupForAllNodes(elem.first, iter->second, elem.second);
275 }
276 }
277
278 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
279 PostProcessWhenDisplayChange();
280 WLOGI("Process display change, displayId: %{public}" PRIu64"", displayId);
281 }
282
ProcessDisplayVprChange(DisplayId displayId)283 void WindowLayoutPolicy::ProcessDisplayVprChange(DisplayId displayId)
284 {
285 Launch();
286 }
287
LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>> & nodeVec)288 void WindowLayoutPolicy::LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>>& nodeVec)
289 {
290 if (nodeVec.empty()) {
291 WLOGW("The node vector is empty!");
292 return;
293 }
294 for (auto& node : nodeVec) {
295 LayoutWindowNode(node);
296 }
297 }
298
NotifyAnimationSizeChangeIfNeeded()299 void WindowLayoutPolicy::NotifyAnimationSizeChangeIfNeeded()
300 {
301 if (!RemoteAnimation::CheckAnimationController()) {
302 WLOGFD("no animation controller!");
303 return;
304 }
305 std::vector<uint32_t> fullScreenWinIds;
306 std::vector<uint32_t> floatMainIds;
307 for (auto& iter : displayGroupWindowTree_) {
308 auto& displayWindowTree = iter.second;
309 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]);
310 if (nodeVec.empty()) {
311 WLOGE("The node vector is empty!");
312 return;
313 }
314 for (auto& node : nodeVec) {
315 // just has one fullscreen app node on foreground
316 if (WindowHelper::IsMainFullScreenWindow(node->GetWindowType(), node->GetWindowMode())) {
317 fullScreenWinIds.emplace_back(node->GetWindowId());
318 }
319 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
320 floatMainIds.emplace_back(node->GetWindowId());
321 }
322 }
323 }
324 RemoteAnimation::NotifyAnimationTargetsUpdate(fullScreenWinIds, floatMainIds);
325 }
326
LayoutWindowTree(DisplayId displayId)327 void WindowLayoutPolicy::LayoutWindowTree(DisplayId displayId)
328 {
329 // reset limit rect
330 limitRectMap_[displayId] = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
331 displayGroupLimitRect_ = displayGroupRect_;
332
333 // ensure that the avoid area windows are traversed first
334 auto& displayWindowTree = displayGroupWindowTree_[displayId];
335 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
336 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
337 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
338 }
339
LayoutWindowNode(const sptr<WindowNode> & node)340 void WindowLayoutPolicy::LayoutWindowNode(const sptr<WindowNode>& node)
341 {
342 if (node == nullptr || node->parent_ == nullptr) {
343 WLOGFE("Node or it's parent is nullptr");
344 return;
345 }
346 if (!node->currentVisibility_) {
347 WLOGFD("window[%{public}u] currently not visible, no need to layout", node->GetWindowId());
348 return;
349 }
350
351 /*
352 * 1. update window rect
353 * 2. update diplayLimitRect and displayGroupRect if this is avoidNode
354 */
355 UpdateLayoutRect(node);
356 if (WindowHelper::IsSystemBarWindow(node->GetWindowType())) {
357 UpdateDisplayLimitRect(node, limitRectMap_[node->GetDisplayId()]);
358 UpdateDisplayGroupLimitRect();
359 WindowInnerManager::GetInstance().NotifyDisplayLimitRectChange(limitRectMap_);
360 }
361 for (auto& childNode : node->children_) {
362 LayoutWindowNode(childNode);
363 }
364 }
365
IsVerticalDisplay(DisplayId displayId) const366 bool WindowLayoutPolicy::IsVerticalDisplay(DisplayId displayId) const
367 {
368 return DisplayGroupInfo::GetInstance().GetDisplayRect(displayId).width_ <
369 DisplayGroupInfo::GetInstance().GetDisplayRect(displayId).height_;
370 }
371
NotifyClientAndAnimation(const sptr<WindowNode> & node,const Rect & winRect,WindowSizeChangeReason reason)372 void WindowLayoutPolicy::NotifyClientAndAnimation(const sptr<WindowNode>& node,
373 const Rect& winRect, WindowSizeChangeReason reason)
374 {
375 if (node->GetWindowToken()) {
376 auto type = node->GetWindowType();
377 auto syncTransactionController = RSSyncTransactionController::GetInstance();
378 if (reason == WindowSizeChangeReason::ROTATION && syncTransactionController && IsNeedAnimationSync(type)) {
379 node->GetWindowToken()->UpdateWindowRect(winRect, node->GetDecoStatus(), reason,
380 syncTransactionController->GetRSTransaction());
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 switch (node->GetWindowSizeChangeReason()) {
693 case WindowSizeChangeReason::MAXIMIZE:
694 [[fallthrough]];
695 case WindowSizeChangeReason::RECOVER: {
696 const RSAnimationTimingProtocol timingProtocol(400); // animation time
697 RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
698 break;
699 }
700 case WindowSizeChangeReason::ROTATION: {
701 if (WmsUtils::IsFixedOrientation(node->GetRequestedOrientation(),
702 node->GetWindowMode(), node->GetWindowFlags())) {
703 auto disInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(node->GetDisplayId());
704 if (disInfo && disInfo->GetDisplayStateChangeType() != DisplayStateChangeType::UPDATE_ROTATION) {
705 WLOGI("[FixOrientation] winNode %{public}u orientation, skip animation", node->GetWindowId());
706 SetBoundsFunc();
707 return;
708 }
709 }
710 const RSAnimationTimingProtocol timingProtocol(600); // animation time
711 const RSAnimationTimingCurve curve_ = RSAnimationTimingCurve::CreateCubicCurve(
712 0.2, 0.0, 0.2, 1.0); // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
713 RSNode::Animate(timingProtocol, curve_, SetBoundsFunc);
714 break;
715 }
716 case WindowSizeChangeReason::FULL_TO_SPLIT:
717 case WindowSizeChangeReason::SPLIT_TO_FULL: {
718 const RSAnimationTimingProtocol timingProtocol(350); // animation time
719 RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
720 break;
721 }
722 case WindowSizeChangeReason::UNDEFINED:
723 [[fallthrough]];
724 default:
725 SetBoundsFunc();
726 }
727 }
728
GetDisplayGroupRect() const729 Rect WindowLayoutPolicy::GetDisplayGroupRect() const
730 {
731 return displayGroupRect_;
732 }
733
SetSplitRatioPoints(DisplayId displayId,const std::vector<int32_t> & splitRatioPoints)734 void WindowLayoutPolicy::SetSplitRatioPoints(DisplayId displayId, const std::vector<int32_t>& splitRatioPoints)
735 {
736 splitRatioPointsMap_[displayId] = splitRatioPoints;
737 }
738
GetDividerRect(DisplayId displayId) const739 Rect WindowLayoutPolicy::GetDividerRect(DisplayId displayId) const
740 {
741 return INVALID_EMPTY_RECT;
742 }
743
IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode> & node)744 bool WindowLayoutPolicy::IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode>& node)
745 {
746 return true;
747 }
748
SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)749 void WindowLayoutPolicy::SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)
750 {
751 floatingBottomPosY_ = floatingBottomPosY;
752 }
753
SetMaxFloatingWindowSize(uint32_t maxSize)754 void WindowLayoutPolicy::SetMaxFloatingWindowSize(uint32_t maxSize)
755 {
756 maxFloatingWindowSize_ = maxSize;
757 }
758
GetStoragedAspectRatio(const sptr<WindowNode> & node)759 void WindowLayoutPolicy::GetStoragedAspectRatio(const sptr<WindowNode>& node)
760 {
761 if (!WindowHelper::IsMainWindow(node->GetWindowType())) {
762 return;
763 }
764
765 std::string abilityName = node->abilityInfo_.abilityName_;
766 std::vector<std::string> nameVector;
767 if (abilityName.size() > 0) {
768 nameVector = WindowHelper::Split(abilityName, ".");
769 }
770 std::string keyName = nameVector.empty() ? node->abilityInfo_.bundleName_ :
771 node->abilityInfo_.bundleName_ + "." + nameVector.back();
772 if (PersistentStorage::HasKey(keyName, PersistentStorageType::ASPECT_RATIO)) {
773 float ratio = 0.0;
774 PersistentStorage::Get(keyName, ratio, PersistentStorageType::ASPECT_RATIO);
775 node->SetAspectRatio(ratio);
776 }
777 }
778
FixWindowRectWithinDisplay(const sptr<WindowNode> & node) const779 void WindowLayoutPolicy::FixWindowRectWithinDisplay(const sptr<WindowNode>& node) const
780 {
781 auto displayId = node->GetDisplayId();
782 const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
783 auto type = node->GetWindowType();
784 Rect rect = node->GetRequestRect();
785 switch (type) {
786 case WindowType::WINDOW_TYPE_STATUS_BAR:
787 rect.posY_ = displayRect.posY_;
788 break;
789 case WindowType::WINDOW_TYPE_NAVIGATION_BAR:
790 rect.posY_ = static_cast<int32_t>(displayRect.height_) + displayRect.posY_ -
791 static_cast<int32_t>(rect.height_);
792 break;
793 default:
794 auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
795 if (displayInfo == nullptr) {
796 WLOGE("displayInfo is nullptr");
797 return;
798 }
799 if (!displayInfo->GetWaterfallDisplayCompressionStatus()) {
800 return;
801 }
802 rect.posY_ = std::max(rect.posY_, displayRect.posY_);
803 rect.posY_ = std::min(rect.posY_, displayRect.posY_ + static_cast<int32_t>(displayRect.height_));
804 }
805 node->SetRequestRect(rect);
806 WLOGFD("WinId: %{public}d, requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]",
807 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
808 }
809
GetMaximizeRect(const sptr<WindowNode> & node,Rect & maxRect)810 void WindowLayoutPolicy::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)
811 {
812 WLOGFI("WindowLayoutPolicy GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ",
813 maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_);
814 }
815 }
816 }