• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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