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 "window_helper.h"
19 #include "window_inner_manager.h"
20 #include "window_manager_hilog.h"
21 #include "wm_trace.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicyTile"};
27 constexpr uint32_t EDGE_INTERVAL = 48;
28 constexpr uint32_t MID_INTERVAL = 24;
29 }
WindowLayoutPolicyTile(const Rect & displayRect,const uint64_t & screenId,sptr<WindowNode> & belowAppNode,sptr<WindowNode> & appNode,sptr<WindowNode> & aboveAppNode)30 WindowLayoutPolicyTile::WindowLayoutPolicyTile(const Rect& displayRect, const uint64_t& screenId,
31 sptr<WindowNode>& belowAppNode, sptr<WindowNode>& appNode, sptr<WindowNode>& aboveAppNode)
32 : WindowLayoutPolicy(displayRect, screenId, belowAppNode, appNode, aboveAppNode)
33 {
34 }
35
Launch()36 void WindowLayoutPolicyTile::Launch()
37 {
38 // compute limit rect
39 UpdateDisplayInfo();
40 // select app min win in queue, and minimize others
41 InitForegroundNodeQueue();
42 AssignNodePropertyForTileWindows();
43 LayoutForegroundNodeQueue();
44 LayoutWindowNode(belowAppWindowNode_);
45 WLOGFI("WindowLayoutPolicyTile::Launch");
46 }
47
UpdateDisplayInfo()48 void WindowLayoutPolicyTile::UpdateDisplayInfo()
49 {
50 limitRect_ = displayRect_;
51 LayoutWindowNode(aboveAppWindowNode_);
52 InitTileWindowRects();
53 }
54
GetMaxTileWinNum() const55 uint32_t WindowLayoutPolicyTile::GetMaxTileWinNum() const
56 {
57 float virtualPixelRatio = GetVirtualPixelRatio();
58 constexpr uint32_t half = 2;
59 uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * half * virtualPixelRatio);
60 uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
61 uint32_t minFloatingW = IsVertical() ? MIN_VERTICAL_FLOATING_WIDTH : MIN_VERTICAL_FLOATING_HEIGHT;
62 minFloatingW = static_cast<uint32_t>(minFloatingW * virtualPixelRatio);
63 uint32_t drawableW = limitRect_.width_ - edgeIntervalVp + midIntervalVp;
64 return static_cast<uint32_t>(drawableW / (minFloatingW + midIntervalVp));
65 }
66
InitTileWindowRects()67 void WindowLayoutPolicyTile::InitTileWindowRects()
68 {
69 float virtualPixelRatio = GetVirtualPixelRatio();
70 uint32_t edgeIntervalVp = static_cast<uint32_t>(EDGE_INTERVAL * virtualPixelRatio);
71 uint32_t midIntervalVp = static_cast<uint32_t>(MID_INTERVAL * virtualPixelRatio);
72
73 constexpr float ratio = 0.75; // 0.75: default height/width ratio
74 constexpr float edgeRatio = 0.125;
75 constexpr int half = 2;
76 maxTileWinNum_ = GetMaxTileWinNum();
77 WLOGFI("set max tile window num %{public}u", maxTileWinNum_);
78 presetRects_.clear();
79 int x = limitRect_.posX_ + (limitRect_.width_ * edgeRatio);
80 int y = limitRect_.posY_ + (limitRect_.height_ * edgeRatio);
81 uint32_t w = limitRect_.width_ * ratio;
82 uint32_t h = limitRect_.height_ * ratio;
83 std::vector<Rect> single = {{ x, y, w, h }};
84 presetRects_.emplace_back(single);
85 for (uint32_t num = 2; num <= maxTileWinNum_; num++) { // start calc preset with 2 windows
86 w = (limitRect_.width_ - edgeIntervalVp * half - midIntervalVp * (num - 1)) / num;
87 std::vector<Rect> curLevel;
88 for (uint32_t i = 0; i < num; i++) {
89 int curX = limitRect_.posX_ + edgeIntervalVp + i * (w + midIntervalVp);
90 Rect curRect = { curX, y, w, h };
91 WLOGFI("presetRects: level %{public}d, id %{public}d, [%{public}d %{public}d %{public}d %{public}d]",
92 num, i, curX, y, w, h);
93 curLevel.emplace_back(curRect);
94 }
95 presetRects_.emplace_back(curLevel);
96 }
97 }
98
AddWindowNode(sptr<WindowNode> & node)99 void WindowLayoutPolicyTile::AddWindowNode(sptr<WindowNode>& node)
100 {
101 WM_FUNCTION_TRACE();
102 if (WindowHelper::IsMainWindow(node->GetWindowType())) {
103 ForegroundNodeQueuePushBack(node);
104 AssignNodePropertyForTileWindows();
105 LayoutForegroundNodeQueue();
106 } else {
107 UpdateWindowNode(node); // currently, update and add do the same process
108 }
109 }
110
UpdateWindowNode(sptr<WindowNode> & node,bool isAddWindow)111 void WindowLayoutPolicyTile::UpdateWindowNode(sptr<WindowNode>& node, bool isAddWindow)
112 {
113 WM_FUNCTION_TRACE();
114 WindowLayoutPolicy::UpdateWindowNode(node);
115 if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
116 InitTileWindowRects();
117 AssignNodePropertyForTileWindows();
118 LayoutForegroundNodeQueue();
119 }
120 }
121
RemoveWindowNode(sptr<WindowNode> & node)122 void WindowLayoutPolicyTile::RemoveWindowNode(sptr<WindowNode>& node)
123 {
124 WM_FUNCTION_TRACE();
125 WLOGFI("RemoveWindowNode %{public}d in tile", node->GetWindowId());
126 auto type = node->GetWindowType();
127 // affect other windows, trigger off global layout
128 if (avoidTypes_.find(type) != avoidTypes_.end()) {
129 LayoutWindowTree();
130 } else {
131 ForegroundNodeQueueRemove(node);
132 AssignNodePropertyForTileWindows();
133 LayoutForegroundNodeQueue();
134 }
135 Rect winRect = node->GetWindowProperty()->GetWindowRect();
136 node->GetWindowToken()->UpdateWindowRect(winRect, WindowSizeChangeReason::HIDE);
137 }
138
LayoutForegroundNodeQueue()139 void WindowLayoutPolicyTile::LayoutForegroundNodeQueue()
140 {
141 for (auto& node : foregroundNodes_) {
142 Rect lastRect = node->GetLayoutRect();
143 Rect winRect = node->GetWindowProperty()->GetWindowRect();
144 node->SetLayoutRect(winRect);
145 CalcAndSetNodeHotZone(winRect, node);
146 if (!(lastRect == winRect)) {
147 node->GetWindowToken()->UpdateWindowRect(winRect, node->GetWindowSizeChangeReason());
148 node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
149 }
150 for (auto& childNode : node->children_) {
151 LayoutWindowNode(childNode);
152 }
153 }
154 }
155
InitForegroundNodeQueue()156 void WindowLayoutPolicyTile::InitForegroundNodeQueue()
157 {
158 foregroundNodes_.clear();
159 for (auto& node : appWindowNode_->children_) {
160 if (WindowHelper::IsMainWindow(node->GetWindowType())) {
161 ForegroundNodeQueuePushBack(node);
162 }
163 }
164 }
165
ForegroundNodeQueuePushBack(sptr<WindowNode> & node)166 void WindowLayoutPolicyTile::ForegroundNodeQueuePushBack(sptr<WindowNode>& node)
167 {
168 if (node == nullptr) {
169 return;
170 }
171 WLOGFI("add win in tile for win id: %{public}d", node->GetWindowId());
172 while (foregroundNodes_.size() >= maxTileWinNum_) {
173 auto removeNode = foregroundNodes_.front();
174 foregroundNodes_.pop_front();
175 WLOGFI("pop win in queue head id: %{public}d, for add new win", removeNode->GetWindowId());
176 if (removeNode->abilityToken_ != nullptr) {
177 WLOGFI("minimize win %{public}d in tile", removeNode->GetWindowId());
178 AAFwk::AbilityManagerClient::GetInstance()->MinimizeAbility(removeNode->abilityToken_);
179 }
180 }
181 foregroundNodes_.push_back(node);
182 }
183
ForegroundNodeQueueRemove(sptr<WindowNode> & node)184 void WindowLayoutPolicyTile::ForegroundNodeQueueRemove(sptr<WindowNode>& node)
185 {
186 if (node == nullptr) {
187 return;
188 }
189 auto iter = std::find(foregroundNodes_.begin(), foregroundNodes_.end(), node);
190 if (iter != foregroundNodes_.end()) {
191 WLOGFI("remove win in tile for win id: %{public}d", node->GetWindowId());
192 foregroundNodes_.erase(iter);
193 }
194 }
195
AssignNodePropertyForTileWindows()196 void WindowLayoutPolicyTile::AssignNodePropertyForTileWindows()
197 {
198 // set rect for foreground windows
199 uint32_t num = foregroundNodes_.size();
200 if (num > maxTileWinNum_ || num > presetRects_.size() || num == 0) {
201 WLOGE("invalid tile queue");
202 return;
203 }
204 std::vector<Rect>& presetRect = presetRects_[num - 1];
205 if (presetRect.size() != num) {
206 WLOGE("invalid preset rects");
207 return;
208 }
209 auto rectIt = presetRect.begin();
210 for (auto node : foregroundNodes_) {
211 auto& rect = (*rectIt);
212 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
213 node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
214 node->SetWindowRect(rect);
215 node->hasDecorated_ = true;
216 WLOGFI("set rect for qwin id: %{public}d [%{public}d %{public}d %{public}d %{public}d]",
217 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
218 rectIt++;
219 }
220 }
221
UpdateLayoutRect(sptr<WindowNode> & node)222 void WindowLayoutPolicyTile::UpdateLayoutRect(sptr<WindowNode>& node)
223 {
224 auto type = node->GetWindowType();
225 auto mode = node->GetWindowMode();
226 auto flags = node->GetWindowFlags();
227 auto decorEnbale = node->GetWindowProperty()->GetDecorEnable();
228 bool needAvoid = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
229 bool parentLimit = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
230 bool subWindow = WindowHelper::IsSubWindow(type);
231 bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
232 const Rect& layoutRect = node->GetLayoutRect();
233 Rect lastRect = layoutRect;
234 Rect displayRect = displayRect_;
235 Rect limitRect = displayRect;
236 Rect winRect = node->GetWindowProperty()->GetWindowRect();
237
238 WLOGFI("Id:%{public}d, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
239 "deco:%{public}d, type:%{public}d, requestRect:[%{public}d, %{public}d, %{public}d, %{public}d]",
240 node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, decorEnbale,
241 static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
242 if (needAvoid) {
243 limitRect = limitRect_;
244 }
245
246 if (!floatingWindow) { // fullscreen window
247 winRect = limitRect;
248 } else { // floating window
249 if (node->GetWindowProperty()->GetDecorEnable()) { // is decorable
250 winRect = ComputeDecoratedWindowRect(winRect);
251 }
252 if (subWindow && parentLimit) { // subwidow and limited by parent
253 limitRect = node->parent_->GetLayoutRect();
254 UpdateFloatingLayoutRect(limitRect, winRect);
255 }
256 }
257 LimitWindowSize(node, displayRect, winRect);
258 node->SetLayoutRect(winRect);
259 CalcAndSetNodeHotZone(winRect, node);
260 if (!(lastRect == winRect)) {
261 auto reason = node->GetWindowSizeChangeReason();
262 node->GetWindowToken()->UpdateWindowRect(winRect, reason);
263 if (reason == WindowSizeChangeReason::DRAG || reason == WindowSizeChangeReason::DRAG_END) {
264 node->ResetWindowSizeChangeReason();
265 }
266 }
267 // update node bounds
268 if (node->surfaceNode_ != nullptr) {
269 node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
270 }
271 }
272 } // Rosen
273 } // OHOS