1 /*
2 * Copyright (c) 2022 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_tile.h"
17 #include <ability_manager_client.h>
18 #include <hitrace_meter.h>
19
20 #include "minimize_app.h"
21 #include "window_helper.h"
22 #include "window_inner_manager.h"
23 #include "window_manager_hilog.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicyTile"};
29 constexpr uint32_t EDGE_INTERVAL = 48;
30 constexpr uint32_t MID_INTERVAL = 24;
31 }
32
WindowLayoutPolicyTile(const sptr<DisplayGroupInfo> & displayGroupInfo,DisplayGroupWindowTree & displayGroupWindowTree)33 WindowLayoutPolicyTile::WindowLayoutPolicyTile(const sptr<DisplayGroupInfo>& displayGroupInfo,
34 DisplayGroupWindowTree& displayGroupWindowTree)
35 : WindowLayoutPolicy(displayGroupInfo, displayGroupWindowTree)
36 {
37 for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
38 maxTileWinNumMap_.insert(std::make_pair(iter.first, static_cast<uint32_t>(1)));
39 }
40 }
41
Launch()42 void WindowLayoutPolicyTile::Launch()
43 {
44 // compute limit rect
45 InitAllRects();
46 // select app min win in queue, and minimize others
47 InitForegroundNodeQueue();
48 for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
49 DisplayId displayId = iter.first;
50 AssignNodePropertyForTileWindows(displayId);
51 LayoutForegroundNodeQueue(displayId);
52 auto& displayWindowTree = displayGroupWindowTree_[displayId];
53 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
54 }
55 WLOGFI("WindowLayoutPolicyTile::Launch");
56 }
57
InitAllRects()58 void WindowLayoutPolicyTile::InitAllRects()
59 {
60 displayGroupLimitRect_ = displayGroupRect_;
61 for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
62 DisplayId displayId = iter.first;
63 limitRectMap_[displayId] = iter.second;
64 auto& displayWindowTree = displayGroupWindowTree_[displayId];
65 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
66 InitTileWindowRects(displayId);
67 }
68 }
69
GetMaxTileWinNum(DisplayId displayId) const70 uint32_t WindowLayoutPolicyTile::GetMaxTileWinNum(DisplayId displayId) const
71 {
72 float virtualPixelRatio = GetVirtualPixelRatio(displayId);
73 constexpr uint32_t half = 2;
74 uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * half * virtualPixelRatio);
75 uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
76 uint32_t minFloatingW = static_cast<uint32_t>(MIN_FLOATING_WIDTH * virtualPixelRatio);
77 uint32_t drawableW = limitRectMap_[displayId].width_ - edgeIntervalVp + midIntervalVp;
78 return static_cast<uint32_t>(drawableW / (minFloatingW + midIntervalVp));
79 }
80
InitTileWindowRects(DisplayId displayId)81 void WindowLayoutPolicyTile::InitTileWindowRects(DisplayId displayId)
82 {
83 float virtualPixelRatio = GetVirtualPixelRatio(displayId);
84 uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * virtualPixelRatio);
85 uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
86
87 constexpr float ratio = DEFAULT_ASPECT_RATIO;
88 const Rect& limitRect = limitRectMap_[displayId];
89 const Rect& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
90 constexpr int half = 2;
91 maxTileWinNumMap_[displayId] = GetMaxTileWinNum(displayId);
92 WLOGFI("set max tile window num %{public}u", maxTileWinNumMap_[displayId]);
93 auto& presetRects = presetRectsMap_[displayId];
94 presetRects.clear();
95 uint32_t w = displayRect.width_ * ratio;
96 uint32_t h = displayRect.height_ * ratio;
97 w = w > limitRect.width_ ? limitRect.width_ : w;
98 h = h > limitRect.height_ ? limitRect.height_ : h;
99 int x = limitRect.posX_ + ((limitRect.width_ - w) / half);
100 int y = limitRect.posY_ + ((limitRect.height_ - h) / half);
101
102 std::vector<Rect> single = {{ x, y, w, h }};
103 presetRects.emplace_back(single);
104 for (uint32_t num = 2; num <= maxTileWinNumMap_[displayId]; num++) { // start calc preset with 2 windows
105 w = (limitRect.width_ - edgeIntervalVp * half - midIntervalVp * (num - 1)) / num;
106 std::vector<Rect> curLevel;
107 for (uint32_t i = 0; i < num; i++) {
108 int curX = limitRect.posX_ + edgeIntervalVp + i * (w + midIntervalVp);
109 Rect curRect = { curX, y, w, h };
110 WLOGFI("presetRects: level %{public}u, id %{public}u, [%{public}d %{public}d %{public}u %{public}u]",
111 num, i, curX, y, w, h);
112 curLevel.emplace_back(curRect);
113 }
114 presetRects.emplace_back(curLevel);
115 }
116 }
117
IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode> & node)118 bool WindowLayoutPolicyTile::IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode>& node)
119 {
120 if (!WindowHelper::IsMainWindow(node->GetWindowType())) {
121 return true;
122 }
123 const auto& displayId = node->GetDisplayId();
124 auto& foregroundNodes = foregroundNodesMap_[displayId];
125 auto num = foregroundNodes.size();
126 if (num > maxTileWinNumMap_[displayId] || maxTileWinNumMap_[displayId] == 0) {
127 return false;
128 }
129
130 UpdateWindowSizeLimits(node);
131
132 // find if node already exits in foreground nodes map
133 auto iter = std::find_if(foregroundNodes.begin(), foregroundNodes.end(),
134 [node](sptr<WindowNode> foregroundNode) {
135 return foregroundNode->GetWindowId() == node->GetWindowId();
136 });
137 if (iter != foregroundNodes.end()) {
138 return true;
139 }
140
141 const auto& presetRects = presetRectsMap_[displayId];
142 Rect tileRect;
143 // if size of foreground nodes is equal to or more than max tile window number
144 if (num == maxTileWinNumMap_[displayId]) {
145 tileRect = *(presetRects[num - 1].begin());
146 } else { // if size of foreground nodes is less than max tile window number
147 tileRect = *(presetRects[num].begin());
148 }
149 WLOGFI("id %{public}u, tileRect: [%{public}d %{public}d %{public}u %{public}u]",
150 node->GetWindowId(), tileRect.posX_, tileRect.posY_, tileRect.width_, tileRect.height_);
151 return WindowHelper::IsRectSatisfiedWithSizeLimits(tileRect, node->GetWindowUpdatedSizeLimits());
152 }
153
AddWindowNode(const sptr<WindowNode> & node)154 void WindowLayoutPolicyTile::AddWindowNode(const sptr<WindowNode>& node)
155 {
156 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
157
158 if (WindowHelper::IsMainWindow(node->GetWindowType())) {
159 DisplayId displayId = node->GetDisplayId();
160 ForegroundNodeQueuePushBack(node, displayId);
161 AssignNodePropertyForTileWindows(displayId);
162 LayoutForegroundNodeQueue(displayId);
163 } else {
164 UpdateWindowNode(node); // currently, update and add do the same process
165 }
166 }
167
UpdateWindowNode(const sptr<WindowNode> & node,bool isAddWindow)168 void WindowLayoutPolicyTile::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
169 {
170 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
171 WindowLayoutPolicy::UpdateWindowNode(node);
172 if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
173 DisplayId displayId = node->GetDisplayId();
174 InitTileWindowRects(displayId);
175 AssignNodePropertyForTileWindows(displayId);
176 LayoutForegroundNodeQueue(displayId);
177 }
178 }
179
RemoveWindowNode(const sptr<WindowNode> & node)180 void WindowLayoutPolicyTile::RemoveWindowNode(const sptr<WindowNode>& node)
181 {
182 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
183 WLOGFI("RemoveWindowNode %{public}u in tile", node->GetWindowId());
184 auto type = node->GetWindowType();
185 auto displayId = node->GetDisplayId();
186 // affect other windows, trigger off global layout
187 if (avoidTypes_.find(type) != avoidTypes_.end()) {
188 LayoutWindowTree(displayId);
189 } else {
190 ForegroundNodeQueueRemove(node);
191 AssignNodePropertyForTileWindows(displayId);
192 LayoutForegroundNodeQueue(displayId);
193 }
194 UpdateClientRect(node->GetRequestRect(), node, WindowSizeChangeReason::HIDE);
195 }
196
LayoutForegroundNodeQueue(DisplayId displayId)197 void WindowLayoutPolicyTile::LayoutForegroundNodeQueue(DisplayId displayId)
198 {
199 for (auto& node : foregroundNodesMap_[displayId]) {
200 Rect winRect = node->GetRequestRect();
201 Rect lastRect = node->GetWindowRect();
202 node->SetWindowRect(winRect);
203 CalcAndSetNodeHotZone(winRect, node);
204 UpdateClientRect(winRect, node, node->GetWindowSizeChangeReason());
205 UpdateSurfaceBounds(node, winRect, lastRect);
206 for (auto& childNode : node->children_) {
207 LayoutWindowNode(childNode);
208 }
209 }
210 }
211
InitForegroundNodeQueue()212 void WindowLayoutPolicyTile::InitForegroundNodeQueue()
213 {
214 for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
215 DisplayId displayId = iter.first;
216 foregroundNodesMap_[displayId].clear();
217 const auto& appWindowNodes = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
218 for (auto& node : appWindowNodes) {
219 if (WindowHelper::IsMainWindow(node->GetWindowType())) {
220 ForegroundNodeQueuePushBack(node, displayId);
221 }
222 }
223 }
224 }
225
ForegroundNodeQueuePushBack(const sptr<WindowNode> & node,DisplayId displayId)226 void WindowLayoutPolicyTile::ForegroundNodeQueuePushBack(const sptr<WindowNode>& node, DisplayId displayId)
227 {
228 if (node == nullptr) {
229 return;
230 }
231 auto& foregroundNodes = foregroundNodesMap_[displayId];
232 auto iter = std::find_if(foregroundNodes.begin(), foregroundNodes.end(),
233 [node](sptr<WindowNode> foregroundNode) {
234 return foregroundNode->GetWindowId() == node->GetWindowId();
235 });
236 if (iter != foregroundNodes.end()) {
237 return;
238 }
239
240 if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING)) {
241 WLOGFD("window don't support tile mode, winId: %{public}d", node->GetWindowId());
242 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_TILE);
243 return;
244 }
245 WLOGFI("add win in tile, displayId: %{public}" PRIu64", winId: %{public}d", displayId, node->GetWindowId());
246 while (!foregroundNodes.empty() && foregroundNodes.size() >= maxTileWinNumMap_[displayId]) {
247 auto removeNode = foregroundNodes.front();
248 foregroundNodes.pop_front();
249 WLOGFI("pop win in queue head for add new win, windowId: %{public}d", removeNode->GetWindowId());
250 MinimizeApp::AddNeedMinimizeApp(removeNode, MinimizeReason::LAYOUT_TILE);
251 }
252 foregroundNodes.push_back(node);
253 }
254
ForegroundNodeQueueRemove(const sptr<WindowNode> & node)255 void WindowLayoutPolicyTile::ForegroundNodeQueueRemove(const sptr<WindowNode>& node)
256 {
257 if (node == nullptr) {
258 return;
259 }
260 DisplayId displayId = node->GetDisplayId();
261 auto& foregroundNodes = foregroundNodesMap_[displayId];
262 auto iter = std::find(foregroundNodes.begin(), foregroundNodes.end(), node);
263 if (iter != foregroundNodes.end()) {
264 WLOGFI("remove win in tile for win id: %{public}d", node->GetWindowId());
265 foregroundNodes.erase(iter);
266 }
267 }
268
AssignNodePropertyForTileWindows(DisplayId displayId)269 void WindowLayoutPolicyTile::AssignNodePropertyForTileWindows(DisplayId displayId)
270 {
271 // set rect for foreground windows
272 auto& foregroundNodes = foregroundNodesMap_[displayId];
273 uint32_t num = foregroundNodes.size();
274 auto& presetRects = presetRectsMap_[displayId];
275 if (num > maxTileWinNumMap_[displayId] || num > presetRects.size() || num == 0) {
276 WLOGE("invalid tile queue");
277 return;
278 }
279 std::vector<Rect>& presetRect = presetRects[num - 1];
280 if (presetRect.size() != num) {
281 WLOGE("invalid preset rects");
282 return;
283 }
284 auto rectIt = presetRect.begin();
285 std::vector<sptr<WindowNode>> needMinimizeNodes;
286 std::vector<sptr<WindowNode>> needRecoverNodes;
287 for (auto node : foregroundNodes) {
288 auto& rect = (*rectIt);
289 if (WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) &&
290 WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
291 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
292 if (node->GetWindowToken()) {
293 node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
294 }
295 node->SetRequestRect(rect);
296 node->SetDecoStatus(true);
297 WLOGFI("set rect for qwin id: %{public}d [%{public}d %{public}d %{public}d %{public}d]",
298 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
299 rectIt++;
300 } else {
301 // if foreground nodes is equal to max tileWinNum, means need recover one node before minimize cur node
302 if (num == maxTileWinNumMap_[displayId]) {
303 auto recoverNode = MinimizeApp::GetRecoverdNodeFromMinimizeList();
304 if (recoverNode != nullptr) {
305 needRecoverNodes.push_back(recoverNode);
306 }
307 }
308 needMinimizeNodes.push_back(node);
309 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_TILE);
310 }
311 }
312 for (auto& miniNode : needMinimizeNodes) {
313 auto iter = std::find(foregroundNodes.begin(), foregroundNodes.end(), miniNode);
314 if (iter != foregroundNodes.end()) {
315 foregroundNodes.erase(iter);
316 }
317 }
318 needMinimizeNodes.clear();
319
320 for (auto& recNode : needRecoverNodes) {
321 foregroundNodes.push_back(recNode);
322 }
323 needRecoverNodes.clear();
324 }
325
UpdateLayoutRect(const sptr<WindowNode> & node)326 void WindowLayoutPolicyTile::UpdateLayoutRect(const sptr<WindowNode>& node)
327 {
328 auto type = node->GetWindowType();
329 auto mode = node->GetWindowMode();
330 auto flags = node->GetWindowFlags();
331 auto property = node->GetWindowProperty();
332 if (property == nullptr) {
333 WLOGFE("window property is nullptr.");
334 return;
335 }
336 UpdateWindowSizeLimits(node);
337 auto decorEnable = property->GetDecorEnable();
338 bool needAvoid = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
339 bool parentLimit = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
340 bool subWindow = WindowHelper::IsSubWindow(type) || WindowHelper::IsSystemSubWindow(type);
341 bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
342 const Rect lastRect = node->GetWindowRect();
343 Rect limitRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
344 ComputeDecoratedRequestRect(node);
345 Rect winRect = node->GetRequestRect();
346
347 WLOGFI("Id:%{public}u, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
348 "deco:%{public}d, type:%{public}u, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
349 node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, decorEnable,
350 static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
351 if (needAvoid) {
352 limitRect = limitRectMap_[node->GetDisplayId()];
353 }
354
355 if (!floatingWindow) { // fullscreen window
356 winRect = limitRect;
357 } else { // floating window
358 if (subWindow && parentLimit && node->parent_) { // subwindow and limited by parent
359 limitRect = node->parent_->GetWindowRect();
360 UpdateFloatingLayoutRect(limitRect, winRect);
361 }
362 }
363
364 LimitFloatingWindowSize(node, displayGroupInfo_->GetDisplayRect(node->GetDisplayId()), winRect);
365 LimitMainFloatingWindowPosition(node, winRect);
366
367 node->SetWindowRect(winRect);
368 CalcAndSetNodeHotZone(winRect, node);
369 // update Node Bounds before reset Reason
370 UpdateSurfaceBounds(node, winRect, lastRect);
371 UpdateClientRectAndResetReason(node, winRect);
372 }
373 } // Rosen
374 } // OHOS
375