1 /*
2 * Copyright (c) 2024 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 "session/host/include/pc_fold_screen_manager.h"
17 #include "display_manager.h"
18 #include "window_manager_hilog.h"
19 #include "wm_math.h"
20
21 namespace OHOS::Rosen {
22 namespace {
23 // moving
24 constexpr int32_t MOVING_RESPONSE = 50;
25 constexpr float MOVING_DAMPING_RATIO = 0.98f;
26 const RSAnimationTimingProtocol MOVING_TIMING_PROTOCOL(MOVING_RESPONSE); // animation time
27 const RSAnimationTimingCurve MOVING_CURVE =
28 RSAnimationTimingCurve::CreateSpring(static_cast<float>(MOVING_RESPONSE / 1000.0f), MOVING_DAMPING_RATIO, 0.0f);
29
30 // throw-slip
31 constexpr float TAN_25_DEG = 0.4663; // throw slip angle = 25 deg
32 constexpr float VEL_B_THRESHOLD = 1.732; // 1732 dp/s
33 constexpr float VEL_C_THRESHOLD = 1.345; // 1345 dp/s
34 constexpr float THROW_BACKTRACING_DURATION = 100.0f;
35 constexpr int32_t THROW_BACKTRACING_THRESHOLD = 200;
36 constexpr float THROW_SLIP_TIME = 416.0f;
37 constexpr float THROW_SLIP_DAMPING_RATIO = 0.7947f; // stiffness = 228, damping = 24
38 constexpr float THROW_SLIP_DECELERATION_RATE = 0.002;
39 const RSAnimationTimingProtocol THROW_SLIP_TIMING_PROTOCOL(std::round(THROW_SLIP_TIME)); // animation time
40 const RSAnimationTimingCurve THROW_SLIP_CURVE =
41 RSAnimationTimingCurve::CreateSpring(THROW_SLIP_TIME / 1000.0f, THROW_SLIP_DAMPING_RATIO, 0.0f);
42
43 // arrange rule
44 constexpr int32_t RULE_TRANS_X = 48; // dp
45 constexpr int32_t MIN_DECOR_HEIGHT = 37;
46 constexpr WSRect RECT_ZERO = { 0, 0, 0, 0 };
47
48 // all displayId
49 constexpr DisplayId DEFAULT_DISPLAY_ID = 0;
50 constexpr DisplayId VIRTUAL_DISPLAY_ID = 999;
51 } // namespace
52
53 WM_IMPLEMENT_SINGLE_INSTANCE(PcFoldScreenManager);
54
UpdateFoldScreenStatus(DisplayId displayId,SuperFoldStatus status,const WSRect & defaultDisplayRect,const WSRect & virtualDisplayRect,const WSRect & foldCreaseRect)55 void PcFoldScreenManager::UpdateFoldScreenStatus(DisplayId displayId, SuperFoldStatus status,
56 const WSRect& defaultDisplayRect, const WSRect& virtualDisplayRect, const WSRect& foldCreaseRect)
57 {
58 SetDisplayInfo(displayId, status);
59 SetDisplayRects(defaultDisplayRect, virtualDisplayRect, foldCreaseRect);
60 }
61
SetDisplayInfo(DisplayId displayId,SuperFoldStatus status)62 void PcFoldScreenManager::SetDisplayInfo(DisplayId displayId, SuperFoldStatus status)
63 {
64 std::unique_lock<std::shared_mutex> lock(displayInfoMutex_);
65 if (displayId_ == displayId && screenFoldStatus_ == status) {
66 return;
67 }
68 TLOGI(WmsLogTag::WMS_MAIN, "display: %{public}" PRIu64", fold status: %{public}d",
69 displayId, static_cast<int32_t>(status));
70 prevScreenFoldStatus_ = screenFoldStatus_;
71 screenFoldStatus_ = status;
72 ResetArrangeRule();
73 displayId_ = displayId;
74 ExecuteFoldScreenStatusChangeCallbacks(displayId_, screenFoldStatus_, prevScreenFoldStatus_);
75 auto display = DisplayManager::GetInstance().GetDisplayById(displayId);
76 if (display == nullptr) {
77 TLOGE(WmsLogTag::WMS_MAIN, "Failed to get display");
78 return;
79 }
80 vpr_ = display->GetVirtualPixelRatio();
81 TLOGI(WmsLogTag::WMS_MAIN, "vpr: %{public}f", vpr_);
82 }
83
SetDisplayRects(const WSRect & defaultDisplayRect,const WSRect & virtualDisplayRect,const WSRect & foldCreaseRect)84 void PcFoldScreenManager::SetDisplayRects(
85 const WSRect& defaultDisplayRect, const WSRect& virtualDisplayRect, const WSRect& foldCreaseRect)
86 {
87 TLOGI(WmsLogTag::WMS_LAYOUT_PC, "%{public}s, %{public}s, %{public}s",
88 defaultDisplayRect.ToString().c_str(), virtualDisplayRect.ToString().c_str(),
89 foldCreaseRect.ToString().c_str());
90 std::unique_lock<std::shared_mutex> lock(rectsMutex_);
91 defaultDisplayRect_ = defaultDisplayRect;
92 virtualDisplayRect_ = virtualDisplayRect;
93 foldCreaseRect_ = foldCreaseRect;
94 }
95
GetScreenFoldStatus() const96 SuperFoldStatus PcFoldScreenManager::GetScreenFoldStatus() const
97 {
98 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
99 return screenFoldStatus_;
100 }
101
GetScreenFoldStatus(DisplayId displayId) const102 SuperFoldStatus PcFoldScreenManager::GetScreenFoldStatus(DisplayId displayId) const
103 {
104 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
105 if (displayId_ != displayId) {
106 return SuperFoldStatus::UNKNOWN;
107 }
108 return screenFoldStatus_;
109 }
110
IsHalfFolded(DisplayId displayId) const111 bool PcFoldScreenManager::IsHalfFolded(DisplayId displayId) const
112 {
113 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
114 return screenFoldStatus_ == SuperFoldStatus::HALF_FOLDED && displayId_ == displayId;
115 }
116
IsHalfFoldedOnMainDisplay(DisplayId displayId) const117 bool PcFoldScreenManager::IsHalfFoldedOnMainDisplay(DisplayId displayId) const
118 {
119 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
120 return screenFoldStatus_ == SuperFoldStatus::HALF_FOLDED && displayId == DEFAULT_DISPLAY_ID;
121 }
122
IsPcFoldScreen(DisplayId displayId) const123 bool PcFoldScreenManager::IsPcFoldScreen(DisplayId displayId) const
124 {
125 return displayId == DEFAULT_DISPLAY_ID || displayId == VIRTUAL_DISPLAY_ID;
126 }
127
UpdateSystemKeyboardStatus(bool hasSystemKeyboard)128 void PcFoldScreenManager::UpdateSystemKeyboardStatus(bool hasSystemKeyboard)
129 {
130 TLOGI(WmsLogTag::WMS_KEYBOARD, "status: %{public}d", hasSystemKeyboard);
131 std::unique_lock<std::shared_mutex> lock(displayInfoMutex_);
132 if (hasSystemKeyboard_ == hasSystemKeyboard) {
133 return;
134 }
135 hasSystemKeyboard_ = hasSystemKeyboard;
136 ExecuteSystemKeyboardStatusChangeCallbacks(displayId_, hasSystemKeyboard_);
137 }
138
HasSystemKeyboard() const139 bool PcFoldScreenManager::HasSystemKeyboard() const
140 {
141 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
142 return hasSystemKeyboard_;
143 }
144
GetVpr() const145 float PcFoldScreenManager::GetVpr() const
146 {
147 std::shared_lock<std::shared_mutex> lock(displayInfoMutex_);
148 return vpr_;
149 }
150
GetDisplayRects() const151 std::tuple<WSRect, WSRect, WSRect> PcFoldScreenManager::GetDisplayRects() const
152 {
153 std::shared_lock<std::shared_mutex> lock(rectsMutex_);
154 return { defaultDisplayRect_, virtualDisplayRect_, foldCreaseRect_ };
155 }
156
GetMovingTimingProtocol()157 RSAnimationTimingProtocol PcFoldScreenManager::GetMovingTimingProtocol()
158 {
159 return MOVING_TIMING_PROTOCOL;
160 }
161
GetMovingTimingCurve()162 RSAnimationTimingCurve PcFoldScreenManager::GetMovingTimingCurve()
163 {
164 return MOVING_CURVE;
165 }
166
GetThrowSlipTimingProtocol()167 RSAnimationTimingProtocol PcFoldScreenManager::GetThrowSlipTimingProtocol()
168 {
169 return THROW_SLIP_TIMING_PROTOCOL;
170 }
171
GetThrowSlipTimingCurve()172 RSAnimationTimingCurve PcFoldScreenManager::GetThrowSlipTimingCurve()
173 {
174 return THROW_SLIP_CURVE;
175 }
176
CalculateScreenSide(const WSRect & rect)177 ScreenSide PcFoldScreenManager::CalculateScreenSide(const WSRect& rect)
178 {
179 int32_t midPosY = rect.height_ / 2 + rect.posY_; // 2: center
180 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
181 return midPosY <= (foldCreaseRect.posY_ + foldCreaseRect.height_ / 2) ? // 2: center
182 ScreenSide::FOLD_B : ScreenSide::FOLD_C;
183 }
184
IsCrossFoldCrease(const WSRect & rect)185 bool PcFoldScreenManager::IsCrossFoldCrease(const WSRect& rect)
186 {
187 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
188 const int32_t midScreenY = foldCreaseRect.posY_ + foldCreaseRect.height_ / 2; // 2: center
189 return rect.posY_ < midScreenY && rect.posY_ + rect.height_ > midScreenY;
190 }
191
ResetArrangeRule()192 void PcFoldScreenManager::ResetArrangeRule()
193 {
194 std::unique_lock<std::mutex> lock(arrangedRectsMutex_);
195 defaultArrangedRect_ = RECT_ZERO;
196 virtualArrangedRect_ = RECT_ZERO;
197 }
198
ResetArrangeRule(const WSRect & rect)199 void PcFoldScreenManager::ResetArrangeRule(const WSRect& rect)
200 {
201 ResetArrangeRule(CalculateScreenSide(rect));
202 }
203
ResetArrangeRule(ScreenSide side)204 void PcFoldScreenManager::ResetArrangeRule(ScreenSide side)
205 {
206 if (side != ScreenSide::FOLD_B && side != ScreenSide::FOLD_C) {
207 TLOGD(WmsLogTag::WMS_LAYOUT, "invalid side: %{public}d", static_cast<int32_t>(side));
208 return;
209 }
210 std::unique_lock<std::mutex> lock(arrangedRectsMutex_);
211 if (side == ScreenSide::FOLD_B) {
212 defaultArrangedRect_ = RECT_ZERO;
213 } else { // FOLD_C
214 virtualArrangedRect_ = RECT_ZERO;
215 }
216 }
217
ResizeToFullScreen(WSRect & rect,int32_t topAvoidHeight,int32_t botAvoidHeight)218 void PcFoldScreenManager::ResizeToFullScreen(WSRect& rect, int32_t topAvoidHeight, int32_t botAvoidHeight)
219 {
220 ScreenSide side = CalculateScreenSide(rect);
221 TLOGD(WmsLogTag::WMS_LAYOUT, "side: %{public}d, rect: %{public}s",
222 static_cast<int32_t>(side), rect.ToString().c_str());
223 if (side != ScreenSide::FOLD_B && side != ScreenSide::FOLD_C) {
224 TLOGW(WmsLogTag::WMS_LAYOUT, "rule not avaliable, side %{public}d", static_cast<int32_t>(side));
225 return;
226 }
227
228 ResetArrangeRule(side);
229 // calculate limit rect
230 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
231 WSRect limitRect = RECT_ZERO;
232 if (side == ScreenSide::FOLD_B) {
233 limitRect.posX_ = defaultDisplayRect.posX_;
234 limitRect.posY_ = defaultDisplayRect.posY_ + topAvoidHeight;
235 limitRect.width_ = defaultDisplayRect.width_;
236 limitRect.height_ = foldCreaseRect.posY_ - limitRect.posY_;
237 } else { // FOLD_C
238 limitRect.posX_ = virtualDisplayRect.posX_;
239 limitRect.posY_ = foldCreaseRect.posY_ + foldCreaseRect.height_;
240 limitRect.width_ = virtualDisplayRect.width_;
241 limitRect.height_ = virtualDisplayRect.posY_ + virtualDisplayRect.height_ - botAvoidHeight - limitRect.posY_;
242 }
243
244 rect = limitRect;
245 }
246
NeedDoThrowSlip(const WSRect & rect,const WSRectF & velocity,ScreenSide & throwSide)247 bool PcFoldScreenManager::NeedDoThrowSlip(const WSRect& rect, const WSRectF& velocity, ScreenSide& throwSide)
248 {
249 TLOGD(WmsLogTag::WMS_LAYOUT_PC, "rect: %{public}s, velocity: %{public}s, throwSide: %{public}d",
250 rect.ToString().c_str(), velocity.ToString().c_str(), static_cast<int32_t>(throwSide));
251
252 // velocity check
253 const WSRect& backtracingRect = CalculateThrowBacktracingRect(rect, velocity);
254 if (!CheckVelocityOrientation(backtracingRect, velocity) && !IsCrossFoldCrease(rect)) {
255 TLOGD(WmsLogTag::WMS_LAYOUT_PC, "orientation check failed, rect: %{public}s, velocity: %{public}s",
256 backtracingRect.ToString().c_str(), velocity.ToString().c_str());
257 return false;
258 }
259
260 ScreenSide startSide = CalculateScreenSide(backtracingRect);
261 if (IsCrossFoldCrease(rect)) {
262 startSide = MathHelper::GreatNotEqual(velocity.posY_, 0.0f) ? ScreenSide::FOLD_B : ScreenSide::FOLD_C;
263 }
264 const WSRect& endRect = CalculateThrowEnd(backtracingRect, velocity);
265 const ScreenSide endSide = CalculateScreenSide(endRect);
266 TLOGD(WmsLogTag::WMS_LAYOUT_PC, "backtracingRect: %{public}s, endRect: %{public}s",
267 backtracingRect.ToString().c_str(), endRect.ToString().c_str());
268 if (startSide == ScreenSide::FOLD_B && endSide == ScreenSide::FOLD_C) {
269 throwSide = startSide;
270 return true;
271 }
272 if (startSide == ScreenSide::FOLD_C && endSide == ScreenSide::FOLD_B) {
273 throwSide = startSide;
274 return true;
275 }
276 return false;
277 }
278
279 /*
280 * only for fullscreen cross-axis throw slip
281 */
NeedDoEasyThrowSlip(const WSRect & rect,const WSRect & startRect,const WSRectF & velocity,ScreenSide & throwSide)282 bool PcFoldScreenManager::NeedDoEasyThrowSlip(const WSRect& rect, const WSRect& startRect,
283 const WSRectF& velocity, ScreenSide& throwSide)
284 {
285 TLOGD(WmsLogTag::WMS_LAYOUT_PC,
286 "rect: %{public}s, startRect: %{public}s, velocity: %{public}s, throwSide: %{public}d",
287 rect.ToString().c_str(), startRect.ToString().c_str(),
288 velocity.ToString().c_str(), static_cast<int32_t>(throwSide));
289
290 ScreenSide startSide = CalculateScreenSide(startRect);
291 if (startSide == throwSide) {
292 return NeedDoThrowSlip(rect, velocity, throwSide);
293 }
294
295 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
296 WSRect easyThrowRect = rect;
297 int32_t midY = rect.posY_ + rect.height_ / 2; // 2: center
298 if (startSide == ScreenSide::FOLD_B) {
299 if (midY > virtualDisplayRect.posY_ + virtualDisplayRect.height_ / 2) { // 2: center
300 return false;
301 }
302 easyThrowRect.posY_ = foldCreaseRect.posY_ - easyThrowRect.height_ / 2; // 2: center
303 } else {
304 if (midY < defaultDisplayRect.posY_ + defaultDisplayRect.height_ / 2) { // 2: center
305 return false;
306 }
307 easyThrowRect.posY_ = foldCreaseRect.posY_ + foldCreaseRect.height_ - easyThrowRect.height_ / 2; // 2: center
308 }
309 return NeedDoThrowSlip(easyThrowRect, velocity, throwSide);
310 }
311
CheckVelocityOrientation(const WSRect & rect,const WSRectF & velocity)312 bool PcFoldScreenManager::CheckVelocityOrientation(const WSRect& rect, const WSRectF& velocity)
313 {
314 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
315 const int32_t centerX = rect.posX_ + rect.width_ / 2; // 2: center
316 const int32_t centerY = rect.posY_ + rect.height_ / 2; // 2: center
317 ScreenSide startSide = CalculateScreenSide(rect);
318 int32_t aimX = 0;
319 int32_t aimY = 0;
320 if (startSide == ScreenSide::FOLD_B) {
321 if (MathHelper::LessNotEqual(velocity.posX_, 0.0f)) {
322 aimX = defaultDisplayRect.posX_;
323 aimY = defaultDisplayRect.posY_ + defaultDisplayRect.height_;
324 } else {
325 aimX = defaultDisplayRect.posX_ + defaultDisplayRect.width_;
326 aimY = defaultDisplayRect.posY_ + defaultDisplayRect.height_;
327 }
328 return MathHelper::GreatNotEqual(velocity.posY_,
329 std::abs(static_cast<float>(aimY - centerY) /
330 MathHelper::NonZero(static_cast<float>(aimX - centerX)) * velocity.posX_));
331 }
332 if (startSide == ScreenSide::FOLD_C) {
333 if (MathHelper::LessNotEqual(velocity.posX_, 0.0f)) {
334 aimX = virtualDisplayRect.posX_;
335 aimY = virtualDisplayRect.posY_;
336 } else {
337 aimX = virtualDisplayRect.posX_ + virtualDisplayRect.width_;
338 aimY = virtualDisplayRect.posY_;
339 }
340 return MathHelper::LessNotEqual(velocity.posY_,
341 -std::abs(static_cast<float>(aimY - centerY) /
342 MathHelper::NonZero(static_cast<float>(aimX - centerX)) * velocity.posX_));
343 }
344
345 return false;
346 }
347
CalculateThrowBacktracingRect(const WSRect & rect,const WSRectF & velocity)348 WSRect PcFoldScreenManager::CalculateThrowBacktracingRect(const WSRect& rect, const WSRectF& velocity)
349 {
350 int32_t midPosY = rect.height_ / 2 + rect.posY_; // 2: center
351 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
352 const int32_t midScreenY = defaultDisplayRect.posY_ + defaultDisplayRect.height_;
353 bool isInUpperThreshold = midPosY < midScreenY && midPosY >= (midScreenY - THROW_BACKTRACING_THRESHOLD);
354 bool isInLowerThreshold = midPosY >= midScreenY && midPosY <= (midScreenY + THROW_BACKTRACING_THRESHOLD);
355 if ((!isInUpperThreshold && MathHelper::LessNotEqual(velocity.posY_, 0.0f)) ||
356 (!isInLowerThreshold && MathHelper::GreatNotEqual(velocity.posY_, 0.0f))) {
357 return rect;
358 }
359 return WSRect{static_cast<int32_t>(rect.posX_ - velocity.posX_ * THROW_BACKTRACING_DURATION),
360 static_cast<int32_t>(rect.posY_ - velocity.posY_ * THROW_BACKTRACING_DURATION),
361 rect.width_, rect.height_};
362 }
363
CalculateThrowEnd(const WSRect & rect,const WSRectF & velocity)364 WSRect PcFoldScreenManager::CalculateThrowEnd(const WSRect& rect, const WSRectF& velocity)
365 {
366 return WSRect{ static_cast<int32_t>(rect.posX_ + velocity.posX_ / THROW_SLIP_DECELERATION_RATE),
367 static_cast<int32_t>(rect.posY_ + velocity.posY_ / THROW_SLIP_DECELERATION_RATE),
368 rect.width_, rect.height_ };
369 }
370
371 /*
372 * move rect to other side
373 * @param rect: current side, moved to other side
374 * @param titleHeight: used in arrange rule to avoid title bar
375 */
ThrowSlipToOppositeSide(ScreenSide startSide,WSRect & rect,int32_t topAvoidHeight,int32_t botAvoidHeight,int32_t titleHeight)376 bool PcFoldScreenManager::ThrowSlipToOppositeSide(ScreenSide startSide, WSRect& rect,
377 int32_t topAvoidHeight, int32_t botAvoidHeight, int32_t titleHeight)
378 {
379 if (startSide != ScreenSide::FOLD_B && startSide != ScreenSide::FOLD_C) {
380 return false;
381 }
382
383 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
384 int32_t topLimit = 0;
385 int32_t botLimit = 0;
386 const WSRect defaultLimitRect = {
387 defaultDisplayRect.posX_, defaultDisplayRect.posY_ + topAvoidHeight,
388 defaultDisplayRect.width_, defaultDisplayRect.height_ - topAvoidHeight };
389 const WSRect virtualLimitRect = {
390 virtualDisplayRect.posX_, virtualDisplayRect.posY_,
391 virtualDisplayRect.width_, virtualDisplayRect.height_ - botAvoidHeight };
392 const WSRect& startLimitRect = startSide == ScreenSide::FOLD_B ? defaultLimitRect : virtualLimitRect;
393 const WSRect& endLimitRect = startSide == ScreenSide::FOLD_B ? virtualLimitRect : defaultLimitRect;
394 if (rect.height_ < startLimitRect.height_ && rect.height_ < endLimitRect.height_ &&
395 rect.posY_ > startLimitRect.posY_) {
396 float ratio = static_cast<float>(endLimitRect.height_ - rect.height_) /
397 static_cast<float>(startLimitRect.height_ - rect.height_);
398 rect.posY_ = MathHelper::Floor(ratio * static_cast<float>(rect.posY_ - startLimitRect.posY_)) +
399 endLimitRect.posY_;
400 } else {
401 rect.posY_ = rect.posY_ + endLimitRect.posY_ - startLimitRect.posY_;
402 }
403 // top limit first
404 rect.posY_ = std::max(std::min(rect.posY_, endLimitRect.posY_ + endLimitRect.height_ - rect.height_),
405 endLimitRect.posY_);
406 TLOGD(WmsLogTag::WMS_LAYOUT_PC, "end posY: %{public}d", rect.posY_);
407 return true;
408 }
409
MappingRectInScreenSide(ScreenSide side,WSRect & rect,int32_t topAvoidHeight,int32_t botAvoidHeight)410 void PcFoldScreenManager::MappingRectInScreenSide(ScreenSide side, WSRect& rect,
411 int32_t topAvoidHeight, int32_t botAvoidHeight)
412 {
413 TLOGD(WmsLogTag::WMS_LAYOUT, "side: %{public}d, rect: %{public}s, avoid heights: [%{public}d,%{public}d]",
414 static_cast<int32_t>(side), rect.ToString().c_str(), topAvoidHeight, botAvoidHeight);
415 WSRect topLeftLimit = RECT_ZERO;
416 WSRect botRightLimit = RECT_ZERO;
417 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
418 float vpr = GetVpr();
419 switch (side) {
420 case ScreenSide::FOLD_B:
421 topLeftLimit.posX_ = MathHelper::Ceil(RULE_TRANS_X * vpr) - rect.width_;
422 topLeftLimit.posY_ = topAvoidHeight;
423 botRightLimit.posX_ = std::max(0,
424 MathHelper::Floor(defaultDisplayRect.width_ - RULE_TRANS_X * vpr));
425 botRightLimit.posY_ = std::max(0, foldCreaseRect.posY_ - rect.height_);
426 botRightLimit.width_ = defaultDisplayRect.width_;
427 botRightLimit.height_ = std::max(0, foldCreaseRect.posY_ - topLeftLimit.posY_);
428 break;
429 case ScreenSide::FOLD_C:
430 topLeftLimit.posX_ = MathHelper::Ceil(RULE_TRANS_X * vpr) - rect.width_;
431 topLeftLimit.posY_ = foldCreaseRect.posY_ + foldCreaseRect.height_;
432 botRightLimit.posX_ = std::max(0,
433 MathHelper::Floor(virtualDisplayRect.width_ - RULE_TRANS_X * vpr));
434 botRightLimit.posY_ = std::max(foldCreaseRect.posY_ + foldCreaseRect.height_,
435 MathHelper::Floor(virtualDisplayRect.posY_ + virtualDisplayRect.height_ -
436 botAvoidHeight - MIN_DECOR_HEIGHT * vpr));
437 botRightLimit.width_ = virtualDisplayRect.width_;
438 botRightLimit.height_ = std::max(0,
439 virtualDisplayRect.posY_ + virtualDisplayRect.height_ - topLeftLimit.posY_ - botAvoidHeight);
440 break;
441 default:
442 TLOGW(WmsLogTag::WMS_LAYOUT, "invalid side: %{public}d", static_cast<int32_t>(side));
443 return;
444 }
445 rect.posX_ = std::max(rect.posX_, topLeftLimit.posX_);
446 rect.posY_ = std::max(rect.posY_, topLeftLimit.posY_);
447 rect.posX_ = std::min(rect.posX_, botRightLimit.posX_);
448 rect.posY_ = std::min(rect.posY_, botRightLimit.posY_);
449 rect.width_ = std::min(rect.width_, botRightLimit.width_);
450 rect.height_ = std::min(rect.height_, botRightLimit.height_);
451 TLOGD(WmsLogTag::WMS_LAYOUT, "limit rects: [%{public}s,%{public}s], mapped rect: %{public}s",
452 topLeftLimit.ToString().c_str(), botRightLimit.ToString().c_str(), rect.ToString().c_str());
453 }
454
MappingRectInScreenSideWithArrangeRule(ScreenSide side,WSRect & rect,int32_t topAvoidHeight,int32_t botAvoidHeight,int32_t titleHeight)455 void PcFoldScreenManager::MappingRectInScreenSideWithArrangeRule(ScreenSide side, WSRect& rect,
456 int32_t topAvoidHeight, int32_t botAvoidHeight, int32_t titleHeight)
457 {
458 TLOGD(WmsLogTag::WMS_LAYOUT, "side: %{public}d, rect: %{public}s",
459 static_cast<int32_t>(side), rect.ToString().c_str());
460 if (side != ScreenSide::FOLD_B && side != ScreenSide::FOLD_C) {
461 TLOGW(WmsLogTag::WMS_LAYOUT, "rule not avaliable, side %{public}d", static_cast<int32_t>(side));
462 return;
463 }
464
465 // calculate limit rect
466 const auto& [defaultDisplayRect, virtualDisplayRect, foldCreaseRect] = GetDisplayRects();
467 WSRect limitRect = RECT_ZERO;
468 if (side == ScreenSide::FOLD_B) {
469 limitRect.posX_ = defaultDisplayRect.posX_;
470 limitRect.posY_ = defaultDisplayRect.posY_ + topAvoidHeight;
471 limitRect.width_ = defaultDisplayRect.width_;
472 limitRect.height_ = foldCreaseRect.posY_ - limitRect.posY_;
473 } else { // FOLD_C
474 limitRect.posX_ = virtualDisplayRect.posX_;
475 limitRect.posY_ = foldCreaseRect.posY_ + foldCreaseRect.height_;
476 limitRect.width_ = virtualDisplayRect.width_;
477 limitRect.height_ = virtualDisplayRect.posY_ + virtualDisplayRect.height_ - botAvoidHeight - limitRect.posY_;
478 }
479
480 {
481 std::unique_lock<std::mutex> lock(arrangedRectsMutex_);
482 WSRect& lastArrangedRect = (side == ScreenSide::FOLD_B) ? defaultArrangedRect_ : virtualArrangedRect_;
483 if (lastArrangedRect.IsEmpty()) {
484 ApplyInitArrangeRule(rect, lastArrangedRect, limitRect, titleHeight);
485 TLOGD(WmsLogTag::WMS_LAYOUT, "init rule, limit: %{public}s, arranged: %{public}s, rect: %{public}s",
486 limitRect.ToString().c_str(), lastArrangedRect.ToString().c_str(), rect.ToString().c_str());
487 return;
488 }
489
490 ApplyArrangeRule(rect, lastArrangedRect, limitRect, titleHeight);
491 TLOGD(WmsLogTag::WMS_LAYOUT, "apply rule, limit: %{public}s, arranged: %{public}s, rect: %{public}s",
492 limitRect.ToString().c_str(), lastArrangedRect.ToString().c_str(), rect.ToString().c_str());
493 }
494 }
495
496 /*
497 * init rule: move rect to center of display
498 * @param titleHeight: in vp
499 */
ApplyInitArrangeRule(WSRect & rect,WSRect & lastArrangedRect,const WSRect & limitRect,int32_t titleHeight)500 void PcFoldScreenManager::ApplyInitArrangeRule(WSRect& rect, WSRect& lastArrangedRect,
501 const WSRect& limitRect, int32_t titleHeight)
502 {
503 rect.posX_ = std::max(limitRect.posX_, limitRect.posX_ + (limitRect.width_ - rect.width_) / 2); // 2: center align
504 rect.posY_ = std::max(limitRect.posY_, limitRect.posY_ + (limitRect.height_ - rect.height_) / 2); // 2: center align
505 float vpr = GetVpr();
506 lastArrangedRect = { rect.posX_, rect.posY_, RULE_TRANS_X * vpr, titleHeight * vpr };
507 }
508
509 /*
510 * init rule: move rect to bottom-right of last arranged position
511 * @param titleHeight: in vp
512 */
ApplyArrangeRule(WSRect & rect,WSRect & lastArrangedRect,const WSRect & limitRect,int32_t titleHeight)513 void PcFoldScreenManager::ApplyArrangeRule(WSRect& rect, WSRect& lastArrangedRect,
514 const WSRect& limitRect, int32_t titleHeight)
515 {
516 rect.posX_ = lastArrangedRect.posX_ + lastArrangedRect.width_;
517 rect.posY_ = lastArrangedRect.posY_ + lastArrangedRect.height_;
518 // new column
519 if (rect.posY_ + rect.height_ > limitRect.posY_ + limitRect.height_) {
520 rect.posY_ = limitRect.posY_;
521 }
522 // reset to top-left
523 if (rect.posX_ + rect.width_ > limitRect.posX_ + limitRect.width_) {
524 rect.posX_ = limitRect.posX_;
525 rect.posY_ = limitRect.posY_;
526 }
527 float vpr = GetVpr();
528 lastArrangedRect = { rect.posX_, rect.posY_, RULE_TRANS_X * vpr, titleHeight * vpr};
529 }
530
RegisterFoldScreenStatusChangeCallback(int32_t persistentId,const std::weak_ptr<FoldScreenStatusChangeCallback> & func)531 void PcFoldScreenManager::RegisterFoldScreenStatusChangeCallback(int32_t persistentId,
532 const std::weak_ptr<FoldScreenStatusChangeCallback>& func)
533 {
534 TLOGI(WmsLogTag::WMS_LAYOUT, "id: %{public}d", persistentId);
535 std::unique_lock<std::mutex> lock(callbackMutex_);
536 auto [_, result] = foldScreenStatusChangeCallbacks_.insert_or_assign(persistentId, func);
537 if (result) {
538 TLOGW(WmsLogTag::WMS_LAYOUT, "callback has registered");
539 }
540 }
541
UnregisterFoldScreenStatusChangeCallback(int32_t persistentId)542 void PcFoldScreenManager::UnregisterFoldScreenStatusChangeCallback(int32_t persistentId)
543 {
544 TLOGI(WmsLogTag::WMS_LAYOUT, "id: %{public}d", persistentId);
545 std::unique_lock<std::mutex> lock(callbackMutex_);
546 auto iter = foldScreenStatusChangeCallbacks_.find(persistentId);
547 if (iter == foldScreenStatusChangeCallbacks_.end()) {
548 TLOGW(WmsLogTag::WMS_LAYOUT, "callback not registered");
549 return;
550 }
551 foldScreenStatusChangeCallbacks_.erase(iter);
552 }
553
ExecuteFoldScreenStatusChangeCallbacks(DisplayId displayId,SuperFoldStatus status,SuperFoldStatus prevStatus)554 void PcFoldScreenManager::ExecuteFoldScreenStatusChangeCallbacks(DisplayId displayId,
555 SuperFoldStatus status, SuperFoldStatus prevStatus)
556 {
557 std::unique_lock<std::mutex> lock(callbackMutex_);
558 for (auto iter = foldScreenStatusChangeCallbacks_.begin(); iter != foldScreenStatusChangeCallbacks_.end();) {
559 auto callback = iter->second.lock();
560 if (callback == nullptr) {
561 TLOGW(WmsLogTag::WMS_LAYOUT, "callback invalid, id: %{public}d", iter->first);
562 iter = foldScreenStatusChangeCallbacks_.erase(iter);
563 continue;
564 }
565 (*callback)(displayId, status, prevStatus);
566 iter++;
567 }
568 }
569
RegisterSystemKeyboardStatusChangeCallback(int32_t persistentId,const std::weak_ptr<SystemKeyboardStatusChangeCallback> & func)570 void PcFoldScreenManager::RegisterSystemKeyboardStatusChangeCallback(int32_t persistentId,
571 const std::weak_ptr<SystemKeyboardStatusChangeCallback>& func)
572 {
573 TLOGI(WmsLogTag::WMS_LAYOUT_PC, "id: %{public}d", persistentId);
574 std::unique_lock<std::mutex> lock(callbackMutex_);
575 auto [_, result] = systemKeyboardStatusChangeCallbacks_.insert_or_assign(persistentId, func);
576 if (result) {
577 TLOGW(WmsLogTag::WMS_LAYOUT_PC, "callback has registered");
578 }
579 }
580
UnregisterSystemKeyboardStatusChangeCallback(int32_t persistentId)581 void PcFoldScreenManager::UnregisterSystemKeyboardStatusChangeCallback(int32_t persistentId)
582 {
583 TLOGI(WmsLogTag::WMS_LAYOUT_PC, "id: %{public}d", persistentId);
584 std::unique_lock<std::mutex> lock(callbackMutex_);
585 auto iter = systemKeyboardStatusChangeCallbacks_.find(persistentId);
586 if (iter == systemKeyboardStatusChangeCallbacks_.end()) {
587 TLOGW(WmsLogTag::WMS_LAYOUT_PC, "callback not registered");
588 return;
589 }
590 systemKeyboardStatusChangeCallbacks_.erase(iter);
591 }
592
ExecuteSystemKeyboardStatusChangeCallbacks(DisplayId displayId,bool hasSystemKeyboard)593 void PcFoldScreenManager::ExecuteSystemKeyboardStatusChangeCallbacks(DisplayId displayId, bool hasSystemKeyboard)
594 {
595 std::unique_lock<std::mutex> lock(callbackMutex_);
596 for (auto iter = systemKeyboardStatusChangeCallbacks_.begin();
597 iter != systemKeyboardStatusChangeCallbacks_.end();) {
598 auto callback = iter->second.lock();
599 if (callback == nullptr) {
600 TLOGW(WmsLogTag::WMS_LAYOUT_PC, "callback invalid, id: %{public}d", iter->first);
601 iter = systemKeyboardStatusChangeCallbacks_.erase(iter);
602 continue;
603 }
604 (*callback)(displayId, hasSystemKeyboard);
605 iter++;
606 }
607 }
608 } // namespace OHOS::Rosen
609