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 <hisysevent.h>
17 #include <hitrace_meter.h>
18 #include <transaction/rs_interfaces.h>
19 #include "dm_common.h"
20 #include "fold_screen_controller/dual_display_fold_policy.h"
21 #include "session/screen/include/screen_session.h"
22 #include "screen_session_manager.h"
23
24 #include "window_manager_hilog.h"
25 #include "parameters.h"
26
27 #ifdef POWER_MANAGER_ENABLE
28 #include <power_mgr_client.h>
29 #endif
30
31 namespace OHOS::Rosen {
32 namespace {
33 const ScreenId SCREEN_ID_MAIN = 0;
34 const ScreenId SCREEN_ID_SUB = 5;
35 const bool IS_COORDINATION_SUPPORT =
36 OHOS::system::GetBoolParameter("const.window.foldabledevice.is_coordination_support", false);
37 #ifdef TP_FEATURE_ENABLE
38 const int32_t TP_TYPE = 12;
39 #endif
40 const std::string MAIN_TP = "0";
41 const std::string SUB_TP = "1";
42 const int32_t REMOVE_DISPLAY_NODE = 0;
43 const int32_t ADD_DISPLAY_NODE = 1;
44 const uint32_t CHANGE_MODE_TASK_NUM = 3;
45 } // namespace
46
DualDisplayFoldPolicy(std::recursive_mutex & displayInfoMutex,std::shared_ptr<TaskScheduler> screenPowerTaskScheduler)47 DualDisplayFoldPolicy::DualDisplayFoldPolicy(std::recursive_mutex& displayInfoMutex,
48 std::shared_ptr<TaskScheduler> screenPowerTaskScheduler): screenPowerTaskScheduler_(screenPowerTaskScheduler)
49 {
50 TLOGI(WmsLogTag::DMS, "DualDisplayFoldPolicy created");
51
52 ScreenId screenIdMain = 0;
53 int32_t foldCreaseRegionPosX = 0;
54 int32_t foldCreaseRegionPosY = 1256;
55 int32_t foldCreaseRegionPosWidth = 1136;
56 int32_t foldCreaseRegionPosHeight = 184;
57
58 std::vector<DMRect> rect = {
59 {
60 foldCreaseRegionPosX, foldCreaseRegionPosY,
61 foldCreaseRegionPosWidth, foldCreaseRegionPosHeight
62 }
63 };
64 currentFoldCreaseRegion_ = new FoldCreaseRegion(screenIdMain, rect);
65 }
66
SetdisplayModeChangeStatus(bool status,bool isOnBootAnimation)67 void DualDisplayFoldPolicy::SetdisplayModeChangeStatus(bool status, bool isOnBootAnimation)
68 {
69 if (status) {
70 pengdingTask_ = CHANGE_MODE_TASK_NUM;
71 startTimePoint_ = std::chrono::steady_clock::now();
72 displayModeChangeRunning_ = status;
73 } else {
74 pengdingTask_ --;
75 if (pengdingTask_ != 0) {
76 return;
77 }
78 displayModeChangeRunning_ = false;
79 endTimePoint_ = std::chrono::steady_clock::now();
80 if (lastCachedisplayMode_.load() != GetScreenDisplayMode()) {
81 TLOGI(WmsLogTag::DMS, "start change displaymode to lastest mode");
82 ChangeScreenDisplayMode(lastCachedisplayMode_.load());
83 }
84 }
85 }
86
CheckDisplayMode(FoldDisplayMode displayMode)87 bool DualDisplayFoldPolicy::CheckDisplayMode(FoldDisplayMode displayMode)
88 {
89 if (displayMode == FoldDisplayMode::COORDINATION && !IS_COORDINATION_SUPPORT) {
90 TLOGI(WmsLogTag::DMS, "Current device is not support coordination");
91 return false;
92 }
93 if (currentDisplayMode_ == displayMode) {
94 TLOGW(WmsLogTag::DMS, "ChangeScreenDisplayMode already in displayMode %{public}d", displayMode);
95 return false;
96 }
97 return true;
98 }
99
GetScreenIdByDisplayMode(FoldDisplayMode displayMode)100 ScreenId DualDisplayFoldPolicy::GetScreenIdByDisplayMode(FoldDisplayMode displayMode)
101 {
102 ScreenId screenId = SCREEN_ID_MAIN;
103 if (displayMode == FoldDisplayMode::SUB) {
104 screenId = SCREEN_ID_SUB;
105 }
106 return screenId;
107 }
108
ChangeScreenDisplayMode(FoldDisplayMode displayMode,DisplayModeChangeReason reason)109 void DualDisplayFoldPolicy::ChangeScreenDisplayMode(FoldDisplayMode displayMode, DisplayModeChangeReason reason)
110 {
111 SetLastCacheDisplayMode(displayMode);
112 if (GetModeChangeRunningStatus()) {
113 TLOGW(WmsLogTag::DMS, "last process not complete, skip mode: %{public}d", displayMode);
114 return;
115 }
116 TLOGI(WmsLogTag::DMS, "start change displaymode: %{public}d, lastElapsedMs: %{public}" PRId64 "ms",
117 displayMode, getFoldingElapsedMs());
118 ScreenId screenId = GetScreenIdByDisplayMode(displayMode);
119 sptr<ScreenSession> screenSession = ScreenSessionManager::GetInstance().GetScreenSession(screenId);
120 if (screenSession == nullptr) {
121 TLOGE(WmsLogTag::DMS, "default screenSession is null");
122 return;
123 }
124 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "ssm:ChangeScreenDisplayMode(displayMode= %" PRIu64")", displayMode);
125 {
126 std::lock_guard<std::recursive_mutex> lock_mode(displayModeMutex_);
127 if (!CheckDisplayMode(displayMode)) {
128 return;
129 }
130 }
131 SetdisplayModeChangeStatus(true);
132 {
133 std::lock_guard<std::recursive_mutex> lock_mode(displayModeMutex_);
134 lastDisplayMode_ = displayMode;
135 }
136 ReportFoldDisplayModeChange(displayMode);
137 ScreenSessionManager::GetInstance().SwitchScrollParam(displayMode);
138 ChangeScreenDisplayModeProc(screenSession, displayMode);
139 {
140 std::lock_guard<std::recursive_mutex> lock_mode(displayModeMutex_);
141 currentDisplayMode_ = displayMode;
142 }
143 ScreenSessionManager::GetInstance().NotifyDisplayModeChanged(displayMode);
144 SetdisplayModeChangeStatus(false);
145 }
146
ChangeScreenDisplayModeProc(sptr<ScreenSession> screenSession,FoldDisplayMode displayMode)147 void DualDisplayFoldPolicy::ChangeScreenDisplayModeProc(sptr<ScreenSession> screenSession,
148 FoldDisplayMode displayMode)
149 {
150 switch (displayMode) {
151 case FoldDisplayMode::SUB: {
152 ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_MAIN, SCREEN_ID_SUB);
153 break;
154 }
155 case FoldDisplayMode::MAIN: {
156 ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_SUB, SCREEN_ID_MAIN);
157 break;
158 }
159 case FoldDisplayMode::COORDINATION: {
160 ChangeScreenDisplayModeToCoordination();
161 break;
162 }
163 default: {
164 break;
165 }
166 }
167 }
168
SendSensorResult(FoldStatus foldStatus)169 void DualDisplayFoldPolicy::SendSensorResult(FoldStatus foldStatus)
170 {
171 TLOGI(WmsLogTag::DMS, "SendSensorResult FoldStatus: %{public}d", foldStatus);
172 FoldDisplayMode displayMode = GetModeMatchStatus();
173 bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
174 if (currentDisplayMode_ == FoldDisplayMode::COORDINATION && isScreenOn &&
175 displayMode == FoldDisplayMode::MAIN) {
176 TLOGI(WmsLogTag::DMS, "CurrentDisplayMode is coordination, HalfFold no need to change displaympde");
177 return;
178 }
179 ChangeScreenDisplayMode(displayMode);
180 }
181
GetCurrentFoldCreaseRegion()182 sptr<FoldCreaseRegion> DualDisplayFoldPolicy::GetCurrentFoldCreaseRegion()
183 {
184 TLOGI(WmsLogTag::DMS, "GetCurrentFoldCreaseRegion");
185 return currentFoldCreaseRegion_;
186 }
187
LockDisplayStatus(bool locked)188 void DualDisplayFoldPolicy::LockDisplayStatus(bool locked)
189 {
190 TLOGI(WmsLogTag::DMS, "LockDisplayStatus locked: %{public}d", locked);
191 lockDisplayStatus_ = locked;
192 }
193
SetOnBootAnimation(bool onBootAnimation)194 void DualDisplayFoldPolicy::SetOnBootAnimation(bool onBootAnimation)
195 {
196 TLOGI(WmsLogTag::DMS, "SetOnBootAnimation onBootAnimation: %{public}d", onBootAnimation);
197 onBootAnimation_ = onBootAnimation;
198 if (!onBootAnimation_) {
199 TLOGI(WmsLogTag::DMS, "SetOnBootAnimation when boot animation finished, change display mode");
200 RecoverWhenBootAnimationExit();
201 }
202 }
203
RecoverWhenBootAnimationExit()204 void DualDisplayFoldPolicy::RecoverWhenBootAnimationExit()
205 {
206 TLOGI(WmsLogTag::DMS, "CurrentScreen(%{public}" PRIu64 ")", screenId_);
207 FoldDisplayMode displayMode = GetModeMatchStatus();
208 if (currentDisplayMode_ != displayMode) {
209 ChangeScreenDisplayMode(displayMode);
210 } else {
211 TriggerScreenDisplayModeUpdate(displayMode);
212 }
213 }
214
TriggerScreenDisplayModeUpdate(FoldDisplayMode displayMode)215 void DualDisplayFoldPolicy::TriggerScreenDisplayModeUpdate(FoldDisplayMode displayMode)
216 {
217 TLOGI(WmsLogTag::DMS, "TriggerScreenDisplayModeUpdate displayMode = %{public}d", displayMode);
218 sptr<ScreenSession> screenSession = nullptr;
219 if (displayMode == FoldDisplayMode::SUB) {
220 screenSession = ScreenSessionManager::GetInstance().GetScreenSession(SCREEN_ID_SUB);
221 } else {
222 screenSession = ScreenSessionManager::GetInstance().GetScreenSession(SCREEN_ID_MAIN);
223 }
224 if (screenSession == nullptr) {
225 TLOGE(WmsLogTag::DMS, "TriggerScreenDisplayModeUpdate default screenSession is null");
226 return;
227 }
228 switch (displayMode) {
229 case FoldDisplayMode::SUB: {
230 ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_MAIN, SCREEN_ID_SUB);
231 break;
232 }
233 case FoldDisplayMode::MAIN: {
234 ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_SUB, SCREEN_ID_MAIN);
235 break;
236 }
237 case FoldDisplayMode::UNKNOWN: {
238 TLOGI(WmsLogTag::DMS, "TriggerScreenDisplayModeUpdate displayMode is unknown");
239 break;
240 }
241 default: {
242 TLOGI(WmsLogTag::DMS, "TriggerScreenDisplayModeUpdate displayMode is invalid");
243 break;
244 }
245 }
246 }
247
UpdateForPhyScreenPropertyChange()248 void DualDisplayFoldPolicy::UpdateForPhyScreenPropertyChange()
249 {
250 TLOGI(WmsLogTag::DMS, "UpdateForPhyScreenPropertyChange currentScreen(%{public}" PRIu64 ")", screenId_);
251 FoldDisplayMode displayMode = GetModeMatchStatus();
252 if (currentDisplayMode_ != displayMode) {
253 ChangeScreenDisplayMode(displayMode);
254 }
255 }
256
GetModeMatchStatus()257 FoldDisplayMode DualDisplayFoldPolicy::GetModeMatchStatus()
258 {
259 FoldDisplayMode displayMode = FoldDisplayMode::UNKNOWN;
260 switch (currentFoldStatus_) {
261 case FoldStatus::EXPAND: {
262 displayMode = FoldDisplayMode::MAIN;
263 break;
264 }
265 case FoldStatus::FOLDED: {
266 displayMode = FoldDisplayMode::SUB;
267 break;
268 }
269 case FoldStatus::HALF_FOLD: {
270 displayMode = FoldDisplayMode::MAIN;
271 break;
272 }
273 default: {
274 TLOGI(WmsLogTag::DMS, "GetModeMatchStatus FoldStatus is invalid");
275 }
276 }
277 return displayMode;
278 }
279
ReportFoldDisplayModeChange(FoldDisplayMode displayMode)280 void DualDisplayFoldPolicy::ReportFoldDisplayModeChange(FoldDisplayMode displayMode)
281 {
282 int32_t mode = static_cast<int32_t>(displayMode);
283 TLOGI(WmsLogTag::DMS, "ReportFoldDisplayModeChange displayMode: %{public}d", mode);
284 int32_t ret = HiSysEventWrite(
285 OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER,
286 "DISPLAY_MODE",
287 OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
288 "FOLD_DISPLAY_MODE", mode);
289 if (ret != 0) {
290 TLOGE(WmsLogTag::DMS, "ReportFoldDisplayModeChange Write HiSysEvent error, ret: %{public}d", ret);
291 }
292 }
293
ReportFoldStatusChangeBegin(int32_t offScreen,int32_t onScreen)294 void DualDisplayFoldPolicy::ReportFoldStatusChangeBegin(int32_t offScreen, int32_t onScreen)
295 {
296 TLOGI(WmsLogTag::DMS, "ReportFoldStatusChangeBegin offScreen: %{public}d, onScreen: %{public}d",
297 offScreen, onScreen);
298 int32_t ret = HiSysEventWrite(
299 OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER,
300 "FOLD_STATE_CHANGE_BEGIN",
301 OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
302 "POWER_OFF_SCREEN", offScreen,
303 "POWER_ON_SCREEN", onScreen);
304 if (ret != 0) {
305 TLOGE(WmsLogTag::DMS, "ReportFoldStatusChangeBegin Write HiSysEvent error, ret: %{public}d", ret);
306 }
307 }
308
ChangeScreenDisplayModeInner(sptr<ScreenSession> screenSession,ScreenId offScreenId,ScreenId onScreenId)309 void DualDisplayFoldPolicy::ChangeScreenDisplayModeInner(sptr<ScreenSession> screenSession, ScreenId offScreenId,
310 ScreenId onScreenId)
311 {
312 if (onBootAnimation_) {
313 ChangeScreenDisplayModeOnBootAnimation(screenSession, onScreenId);
314 return;
315 }
316 std::string tp = MAIN_TP;
317 if (onScreenId == SCREEN_ID_SUB) {
318 tp = SUB_TP;
319 }
320 #ifdef TP_FEATURE_ENABLE
321 RSInterfaces::GetInstance().SetTpFeatureConfig(TP_TYPE, tp.c_str());
322 #endif
323 ReportFoldStatusChangeBegin((int32_t)SCREEN_ID_MAIN, (int32_t)SCREEN_ID_SUB);
324 bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
325 TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToCoordination, isScreenOn= %{public}d", isScreenOn);
326 auto taskScreenOff = [=] {
327 TLOGNI(WmsLogTag::DMS, "ChangeScreenDisplayMode: off screenId: %{public}" PRIu64 "", offScreenId);
328 screenId_ = offScreenId;
329 ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
330 ScreenSessionManager::GetInstance().SetScreenPowerForFold(ScreenPowerStatus::POWER_STATUS_OFF);
331 SetdisplayModeChangeStatus(false);
332 };
333 if (screenPowerTaskScheduler_ == nullptr) {
334 TLOGE(WmsLogTag::DMS, "screenPowerTaskScheduler_ is nullpter");
335 return;
336 }
337 screenPowerTaskScheduler_->PostAsyncTask(taskScreenOff, "screenOffTask");
338 AddOrRemoveDisplayNodeToTree(offScreenId, REMOVE_DISPLAY_NODE);
339
340 auto taskScreenOn = [=] {
341 TLOGNI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on screenId: %{public}" PRIu64 "", onScreenId);
342 screenId_ = onScreenId;
343 if (isScreenOn) {
344 ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
345 ScreenSessionManager::GetInstance().SetScreenPowerForFold(ScreenPowerStatus::POWER_STATUS_ON);
346 } else {
347 PowerMgr::PowerMgrClient::GetInstance().WakeupDeviceAsync();
348 }
349 SetdisplayModeChangeStatus(false);
350 };
351 screenPowerTaskScheduler_->PostAsyncTask(taskScreenOn, "screenOnTask");
352 AddOrRemoveDisplayNodeToTree(onScreenId, ADD_DISPLAY_NODE);
353 }
354
ChangeScreenDisplayModeToCoordination()355 void DualDisplayFoldPolicy::ChangeScreenDisplayModeToCoordination()
356 {
357 bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
358 TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToCoordination, isScreenOn= %{public}d", isScreenOn);
359 #ifdef TP_FEATURE_ENABLE
360 RSInterfaces::GetInstance().SetTpFeatureConfig(TP_TYPE, MAIN_TP.c_str());
361 #endif
362 // on main screen
363 auto taskScreenOnMain = [=] {
364 TLOGNI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on main screenId");
365 screenId_ = SCREEN_ID_MAIN;
366 if (isScreenOn) {
367 ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
368 ScreenSessionManager::GetInstance().SetScreenPower(ScreenPowerStatus::POWER_STATUS_ON,
369 PowerStateChangeReason::STATE_CHANGE_REASON_DISPLAY_SWITCH);
370 } else {
371 PowerMgr::PowerMgrClient::GetInstance().WakeupDeviceAsync();
372 }
373 SetdisplayModeChangeStatus(false);
374 };
375 if (screenPowerTaskScheduler_ == nullptr) {
376 TLOGE(WmsLogTag::DMS, "screenPowerTaskScheduler_ is nullpter");
377 return;
378 }
379 screenPowerTaskScheduler_->PostAsyncTask(taskScreenOnMain, "taskScreenOnMain");
380 // on sub screen
381 auto taskScreenOnSub = [=] {
382 TLOGNI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on sub screenId");
383 if (isScreenOn) {
384 ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
385 ScreenSessionManager::GetInstance().SetScreenPowerForFold(SCREEN_ID_SUB,
386 ScreenPowerStatus::POWER_STATUS_ON);
387 }
388 SetdisplayModeChangeStatus(false);
389 };
390 screenPowerTaskScheduler_->PostAsyncTask(taskScreenOnSub, "taskScreenOnSub");
391 AddOrRemoveDisplayNodeToTree(SCREEN_ID_SUB, ADD_DISPLAY_NODE);
392 }
393
ChangeScreenDisplayModeOnBootAnimation(sptr<ScreenSession> screenSession,ScreenId screenId)394 void DualDisplayFoldPolicy::ChangeScreenDisplayModeOnBootAnimation(sptr<ScreenSession> screenSession, ScreenId screenId)
395 {
396 TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToFullOnBootAnimation");
397 if (screenSession == nullptr) {
398 TLOGE(WmsLogTag::DMS, "ChangeScreenDisplayModeOnBootAnimation, ScreenSession is nullpter");
399 return;
400 }
401 screenProperty_ = ScreenSessionManager::GetInstance().GetPhyScreenProperty(screenId);
402 ScreenPropertyChangeReason reason = ScreenPropertyChangeReason::FOLD_SCREEN_EXPAND;
403 if (screenId == SCREEN_ID_SUB) {
404 reason = ScreenPropertyChangeReason::FOLD_SCREEN_FOLDING;
405 }
406 screenSession->UpdatePropertyByFoldControl(screenProperty_);
407 screenSession->PropertyChange(screenSession->GetScreenProperty(), reason);
408 TLOGI(WmsLogTag::DMS, "screenBounds : width_= %{public}f, height_= %{public}f",
409 screenSession->GetScreenProperty().GetBounds().rect_.width_,
410 screenSession->GetScreenProperty().GetBounds().rect_.height_);
411 screenId_ = screenId;
412 }
413
AddOrRemoveDisplayNodeToTree(ScreenId screenId,int32_t command)414 void DualDisplayFoldPolicy::AddOrRemoveDisplayNodeToTree(ScreenId screenId, int32_t command)
415 {
416 TLOGI(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, screenId: %{public}" PRIu64 ", command: %{public}d",
417 screenId, command);
418 sptr<ScreenSession> screenSession = ScreenSessionManager::GetInstance().GetScreenSession(screenId);
419 if (screenSession == nullptr) {
420 TLOGE(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, screenSession is null");
421 return;
422 }
423 std::shared_ptr<RSDisplayNode> displayNode = screenSession->GetDisplayNode();
424 if (displayNode == nullptr) {
425 TLOGE(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, displayNode is null");
426 return;
427 }
428 if (command == ADD_DISPLAY_NODE) {
429 displayNode->AddDisplayNodeToTree();
430 } else if (command == REMOVE_DISPLAY_NODE) {
431 displayNode->RemoveDisplayNodeFromTree();
432 }
433 auto transactionProxy = RSTransactionProxy::GetInstance();
434 if (transactionProxy != nullptr) {
435 TLOGI(WmsLogTag::DMS, "add or remove displayNode");
436 transactionProxy->FlushImplicitTransaction();
437 }
438 }
439
ExitCoordination()440 void DualDisplayFoldPolicy::ExitCoordination()
441 {
442 ScreenSessionManager::GetInstance().SetScreenPowerForFold(SCREEN_ID_SUB,
443 ScreenPowerStatus::POWER_STATUS_OFF);
444 AddOrRemoveDisplayNodeToTree(SCREEN_ID_SUB, REMOVE_DISPLAY_NODE);
445 FoldDisplayMode displayMode = GetModeMatchStatus();
446 currentDisplayMode_ = displayMode;
447 lastDisplayMode_ = displayMode;
448 TLOGI(WmsLogTag::DMS, "CurrentDisplayMode:%{public}d", displayMode);
449 ScreenSessionManager::GetInstance().NotifyDisplayModeChanged(displayMode);
450 }
451 } // namespace OHOS::Rosen