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