• 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 "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     {
130         std::lock_guard<std::recursive_mutex> lock_mode(displayModeMutex_);
131         lastDisplayMode_ = displayMode;
132     }
133     ReportFoldDisplayModeChange(displayMode);
134     ChangeScreenDisplayModeProc(screenSession, displayMode);
135     {
136         std::lock_guard<std::recursive_mutex> lock_mode(displayModeMutex_);
137         currentDisplayMode_ = displayMode;
138     }
139     ScreenSessionManager::GetInstance().NotifyDisplayModeChanged(displayMode);
140     SetdisplayModeChangeStatus(false);
141 }
142 
ChangeScreenDisplayModeProc(sptr<ScreenSession> screenSession,FoldDisplayMode displayMode)143 void DualDisplayFoldPolicy::ChangeScreenDisplayModeProc(sptr<ScreenSession> screenSession,
144     FoldDisplayMode displayMode)
145 {
146     switch (displayMode) {
147         case FoldDisplayMode::SUB: {
148             ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_MAIN, SCREEN_ID_SUB);
149             break;
150         }
151         case FoldDisplayMode::MAIN: {
152             ChangeScreenDisplayModeInner(screenSession, SCREEN_ID_SUB, SCREEN_ID_MAIN);
153             break;
154         }
155         case FoldDisplayMode::COORDINATION: {
156             ChangeScreenDisplayModeToCoordination();
157             break;
158         }
159         default: {
160             break;
161         }
162     }
163 }
164 
SendSensorResult(FoldStatus foldStatus)165 void DualDisplayFoldPolicy::SendSensorResult(FoldStatus foldStatus)
166 {
167     TLOGI(WmsLogTag::DMS, "SendSensorResult FoldStatus: %{public}d", foldStatus);
168     FoldDisplayMode displayMode = GetModeMatchStatus();
169     bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
170     if (currentDisplayMode_ == FoldDisplayMode::COORDINATION && isScreenOn &&
171         displayMode == FoldDisplayMode::MAIN) {
172         TLOGI(WmsLogTag::DMS, "CurrentDisplayMode is coordination, HalfFold no need to change displaympde");
173         return;
174     }
175     ChangeScreenDisplayMode(displayMode);
176 }
177 
GetCurrentFoldCreaseRegion()178 sptr<FoldCreaseRegion> DualDisplayFoldPolicy::GetCurrentFoldCreaseRegion()
179 {
180     TLOGI(WmsLogTag::DMS, "GetCurrentFoldCreaseRegion");
181     return currentFoldCreaseRegion_;
182 }
183 
LockDisplayStatus(bool locked)184 void DualDisplayFoldPolicy::LockDisplayStatus(bool locked)
185 {
186     TLOGI(WmsLogTag::DMS, "LockDisplayStatus locked: %{public}d", locked);
187     lockDisplayStatus_ = locked;
188 }
189 
SetOnBootAnimation(bool onBootAnimation)190 void DualDisplayFoldPolicy::SetOnBootAnimation(bool onBootAnimation)
191 {
192     TLOGI(WmsLogTag::DMS, "SetOnBootAnimation onBootAnimation: %{public}d", onBootAnimation);
193     onBootAnimation_ = onBootAnimation;
194     if (!onBootAnimation_) {
195         TLOGI(WmsLogTag::DMS, "SetOnBootAnimation when boot animation finished, change display mode");
196         RecoverWhenBootAnimationExit();
197     }
198 }
199 
RecoverWhenBootAnimationExit()200 void DualDisplayFoldPolicy::RecoverWhenBootAnimationExit()
201 {
202     TLOGI(WmsLogTag::DMS, "RecoverWhenBootAnimationExit currentScreen(%{public}" PRIu64 ")", screenId_);
203     FoldDisplayMode displayMode = GetModeMatchStatus();
204     if (currentDisplayMode_ != displayMode) {
205         ChangeScreenDisplayMode(displayMode);
206         return;
207     }
208     ChangeScreenDisplayMode(displayMode);
209 }
210 
UpdateForPhyScreenPropertyChange()211 void DualDisplayFoldPolicy::UpdateForPhyScreenPropertyChange()
212 {
213     TLOGI(WmsLogTag::DMS, "UpdateForPhyScreenPropertyChange currentScreen(%{public}" PRIu64 ")", screenId_);
214     FoldDisplayMode displayMode = GetModeMatchStatus();
215     if (currentDisplayMode_ != displayMode) {
216         ChangeScreenDisplayMode(displayMode);
217     }
218 }
219 
GetModeMatchStatus()220 FoldDisplayMode DualDisplayFoldPolicy::GetModeMatchStatus()
221 {
222     FoldDisplayMode displayMode = FoldDisplayMode::UNKNOWN;
223     switch (currentFoldStatus_) {
224         case FoldStatus::EXPAND: {
225             displayMode = FoldDisplayMode::MAIN;
226             break;
227         }
228         case FoldStatus::FOLDED: {
229             displayMode = FoldDisplayMode::SUB;
230             break;
231         }
232         case FoldStatus::HALF_FOLD: {
233             displayMode = FoldDisplayMode::MAIN;
234             break;
235         }
236         default: {
237             TLOGI(WmsLogTag::DMS, "GetModeMatchStatus FoldStatus is invalid");
238         }
239     }
240     return displayMode;
241 }
242 
ReportFoldDisplayModeChange(FoldDisplayMode displayMode)243 void DualDisplayFoldPolicy::ReportFoldDisplayModeChange(FoldDisplayMode displayMode)
244 {
245     int32_t mode = static_cast<int32_t>(displayMode);
246     TLOGI(WmsLogTag::DMS, "ReportFoldDisplayModeChange displayMode: %{public}d", mode);
247     int32_t ret = HiSysEventWrite(
248         OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER,
249         "DISPLAY_MODE",
250         OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
251         "FOLD_DISPLAY_MODE", mode);
252     if (ret != 0) {
253         TLOGE(WmsLogTag::DMS, "ReportFoldDisplayModeChange Write HiSysEvent error, ret: %{public}d", ret);
254     }
255 }
256 
ReportFoldStatusChangeBegin(int32_t offScreen,int32_t onScreen)257 void DualDisplayFoldPolicy::ReportFoldStatusChangeBegin(int32_t offScreen, int32_t onScreen)
258 {
259     TLOGI(WmsLogTag::DMS, "ReportFoldStatusChangeBegin offScreen: %{public}d, onScreen: %{public}d",
260         offScreen, onScreen);
261     int32_t ret = HiSysEventWrite(
262         OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER,
263         "FOLD_STATE_CHANGE_BEGIN",
264         OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
265         "POWER_OFF_SCREEN", offScreen,
266         "POWER_ON_SCREEN", onScreen);
267     if (ret != 0) {
268         TLOGE(WmsLogTag::DMS, "ReportFoldStatusChangeBegin Write HiSysEvent error, ret: %{public}d", ret);
269     }
270 }
271 
ChangeScreenDisplayModeInner(sptr<ScreenSession> screenSession,ScreenId offScreenId,ScreenId onScreenId)272 void DualDisplayFoldPolicy::ChangeScreenDisplayModeInner(sptr<ScreenSession> screenSession, ScreenId offScreenId,
273     ScreenId onScreenId)
274 {
275     if (onBootAnimation_) {
276         ChangeScreenDisplayModeOnBootAnimation(screenSession, onScreenId);
277         return;
278     }
279     std::string tp = MAIN_TP;
280     if (onScreenId == SCREEN_ID_SUB) {
281         tp = SUB_TP;
282     }
283 #ifdef TP_FEATURE_ENABLE
284     RSInterfaces::GetInstance().SetTpFeatureConfig(TP_TYPE, tp.c_str());
285 #endif
286     ReportFoldStatusChangeBegin((int32_t)SCREEN_ID_MAIN, (int32_t)SCREEN_ID_SUB);
287     bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
288     TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeInner, isScreenOn= %{public}d", isScreenOn);
289     auto taskScreenOff = [=] {
290         TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayMode: off screenId: %{public}" PRIu64 "", offScreenId);
291         screenId_ = offScreenId;
292         ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
293         ScreenSessionManager::GetInstance().SetScreenPowerForFold(ScreenPowerStatus::POWER_STATUS_OFF);
294         SetdisplayModeChangeStatus(false);
295     };
296     screenPowerTaskScheduler_->PostAsyncTask(taskScreenOff, "screenOffTask");
297     AddOrRemoveDisplayNodeToTree(offScreenId, REMOVE_DISPLAY_NODE);
298 
299     auto taskScreenOn = [=] {
300         TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on screenId: %{public}" PRIu64 "", onScreenId);
301         screenId_ = onScreenId;
302         if (isScreenOn) {
303             ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
304             ScreenSessionManager::GetInstance().SetScreenPowerForFold(ScreenPowerStatus::POWER_STATUS_ON);
305         } else {
306             PowerMgr::PowerMgrClient::GetInstance().WakeupDeviceAsync();
307         }
308         SetdisplayModeChangeStatus(false);
309     };
310     screenPowerTaskScheduler_->PostAsyncTask(taskScreenOn, "screenOnTask");
311     AddOrRemoveDisplayNodeToTree(onScreenId, ADD_DISPLAY_NODE);
312 }
313 
ChangeScreenDisplayModeToCoordination()314 void DualDisplayFoldPolicy::ChangeScreenDisplayModeToCoordination()
315 {
316     TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToCoordination");
317     #ifdef TP_FEATURE_ENABLE
318     RSInterfaces::GetInstance().SetTpFeatureConfig(TP_TYPE, MAIN_TP.c_str());
319     #endif
320     bool isScreenOn = PowerMgr::PowerMgrClient::GetInstance().IsFoldScreenOn();
321     TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToCoordination, isScreenOn= %{public}d", isScreenOn);
322     // on main screen
323     auto taskScreenOnMain = [=] {
324         TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on main screen");
325         screenId_ = SCREEN_ID_MAIN;
326         if (isScreenOn) {
327             ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
328             ScreenSessionManager::GetInstance().SetScreenPower(ScreenPowerStatus::POWER_STATUS_ON,
329                 PowerStateChangeReason::STATE_CHANGE_REASON_DISPLAY_SWITCH);
330         } else {
331             PowerMgr::PowerMgrClient::GetInstance().WakeupDeviceAsync();
332         }
333         SetdisplayModeChangeStatus(false);
334     };
335     screenPowerTaskScheduler_->PostAsyncTask(taskScreenOnMain, "taskScreenOnMain");
336     // on sub screen
337     auto taskScreenOnSub = [=] {
338         TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayMode: on sub screen");
339         if (isScreenOn) {
340             ScreenSessionManager::GetInstance().SetKeyguardDrawnDoneFlag(false);
341             ScreenSessionManager::GetInstance().SetScreenPowerForFold(SCREEN_ID_SUB,
342                 ScreenPowerStatus::POWER_STATUS_ON);
343         }
344         SetdisplayModeChangeStatus(false);
345     };
346     screenPowerTaskScheduler_->PostAsyncTask(taskScreenOnSub, "taskScreenOnSub");
347     AddOrRemoveDisplayNodeToTree(SCREEN_ID_SUB, ADD_DISPLAY_NODE);
348 }
349 
ChangeScreenDisplayModeOnBootAnimation(sptr<ScreenSession> screenSession,ScreenId screenId)350 void DualDisplayFoldPolicy::ChangeScreenDisplayModeOnBootAnimation(sptr<ScreenSession> screenSession, ScreenId screenId)
351 {
352     TLOGI(WmsLogTag::DMS, "ChangeScreenDisplayModeToFullOnBootAnimation");
353     screenProperty_ = ScreenSessionManager::GetInstance().GetPhyScreenProperty(screenId);
354     ScreenPropertyChangeReason reason = ScreenPropertyChangeReason::FOLD_SCREEN_EXPAND;
355     if (screenId == SCREEN_ID_SUB) {
356         reason = ScreenPropertyChangeReason::FOLD_SCREEN_FOLDING;
357     }
358     screenSession->UpdatePropertyByFoldControl(screenProperty_);
359     screenSession->PropertyChange(screenSession->GetScreenProperty(), reason);
360     TLOGI(WmsLogTag::DMS, "screenBounds : width_= %{public}f, height_= %{public}f",
361         screenSession->GetScreenProperty().GetBounds().rect_.width_,
362         screenSession->GetScreenProperty().GetBounds().rect_.height_);
363     screenId_ = screenId;
364 }
365 
AddOrRemoveDisplayNodeToTree(ScreenId screenId,int32_t command)366 void DualDisplayFoldPolicy::AddOrRemoveDisplayNodeToTree(ScreenId screenId, int32_t command)
367 {
368     TLOGI(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, screenId: %{public}" PRIu64 ", command: %{public}d",
369         screenId, command);
370     sptr<ScreenSession> screenSession = ScreenSessionManager::GetInstance().GetScreenSession(screenId);
371     if (screenSession == nullptr) {
372         TLOGE(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, screenSession is null");
373         return;
374     }
375     std::shared_ptr<RSDisplayNode> displayNode = screenSession->GetDisplayNode();
376     if (displayNode == nullptr) {
377         TLOGE(WmsLogTag::DMS, "AddOrRemoveDisplayNodeToTree, displayNode is null");
378         return;
379     }
380     if (command == ADD_DISPLAY_NODE) {
381         displayNode->AddDisplayNodeToTree();
382     } else if (command == REMOVE_DISPLAY_NODE) {
383         displayNode->RemoveDisplayNodeFromTree();
384     }
385     auto transactionProxy = RSTransactionProxy::GetInstance();
386     if (transactionProxy != nullptr) {
387         TLOGI(WmsLogTag::DMS, "add or remove displayNode");
388         transactionProxy->FlushImplicitTransaction();
389     }
390 }
391 
ExitCoordination()392 void DualDisplayFoldPolicy::ExitCoordination()
393 {
394     ScreenSessionManager::GetInstance().SetScreenPowerForFold(SCREEN_ID_SUB,
395         ScreenPowerStatus::POWER_STATUS_OFF);
396     AddOrRemoveDisplayNodeToTree(SCREEN_ID_SUB, REMOVE_DISPLAY_NODE);
397     FoldDisplayMode displayMode = GetModeMatchStatus();
398     currentDisplayMode_ = displayMode;
399     lastDisplayMode_ = displayMode;
400     TLOGI(WmsLogTag::DMS, "CurrentDisplayMode:%{public}d", displayMode);
401     ScreenSessionManager::GetInstance().NotifyDisplayModeChanged(displayMode);
402 }
403 } // namespace OHOS::Rosen