• 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 <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