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 }