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