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 <iservice_registry.h>
17 #include <parameters.h>
18 #include <refbase.h>
19 #include <map>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 #include <hisysevent.h>
24
25 #include "app_mgr_client.h"
26 #include "app_service_manager.h"
27 #include "app_mgr_constants.h"
28 #include "app_mgr_interface.h"
29 #include "app_state_data.h"
30 #include "ability_state_data.h"
31 #include "process_data.h"
32 #include "fold_screen_controller/fold_screen_policy.h"
33 #include "screen_setting_helper.h"
34
35 #include "fold_screen_controller/fold_screen_sensor_manager.h"
36 #include "fold_screen_controller/sensor_fold_state_manager/dual_display_sensor_fold_state_manager.h"
37 #include "fold_screen_controller/sensor_fold_state_manager/sensor_fold_state_manager.h"
38 #include "fold_screen_state_internel.h"
39 #include "session/screen/include/screen_session.h"
40 #include "screen_scene_config.h"
41 #include "singleton.h"
42 #include "singleton_container.h"
43
44 #include "iremote_object.h"
45 #include "window_manager_hilog.h"
46
47 #ifdef POWER_MANAGER_ENABLE
48 #include <power_mgr_client.h>
49 #endif
50
51 namespace OHOS::Rosen {
52 using OHOS::AppExecFwk::AppStateData;
53 using OHOS::AppExecFwk::ApplicationState;
54 namespace {
55 const float INWARD_FOLDED_THRESHOLD = static_cast<float>(system::GetIntParameter<int32_t>
56 ("const.fold.folded_threshold", 85));
57 const float INWARD_EXPAND_THRESHOLD = static_cast<float>(system::GetIntParameter<int32_t>
58 ("const.fold.expand_threshold", 145));
59 const float INWARD_HALF_FOLDED_MAX_THRESHOLD = static_cast<float>(system::GetIntParameter<int32_t>
60 ("const.half_folded_max_threshold", 135));
61 const float INWARD_HALF_FOLDED_MIN_THRESHOLD = static_cast<float>(system::GetIntParameter<int32_t>
62 ("const.fold.half_folded_min_threshold", 85));
63 constexpr int32_t HALL_THRESHOLD = 1;
64 constexpr int32_t HALL_FOLDED_THRESHOLD = 0;
65 constexpr float ANGLE_MIN_VAL = 0.0F;
66 constexpr float INWARD_FOLDED_LOWER_THRESHOLD = 10.0F;
67 constexpr float INWARD_FOLDED_UPPER_THRESHOLD = 20.0F;
68 constexpr float HALL_ZERO_INVALID_POSTURE = 170.0F;
69 constexpr float TENT_MODE_EXIT_MAX_THRESHOLD = 110.0F;
70 constexpr int32_t TENT_MODE_OFF = 0;
71 constexpr int32_t TENT_MODE_ON = 1;
72 constexpr uint32_t FULL_WAIT_TIMES = 300;
73 std::mutex foldStatusChangeMutex_;
74 std::condition_variable angleChangeCv_;
75 } // namespace
76
DualDisplaySensorFoldStateManager(const std::shared_ptr<TaskScheduler> & screenPowerTaskScheduler)77 DualDisplaySensorFoldStateManager::DualDisplaySensorFoldStateManager(
78 const std::shared_ptr<TaskScheduler>& screenPowerTaskScheduler)
79 :screenPowerTaskScheduler_(screenPowerTaskScheduler)
80 {
81 auto stringListConfig = ScreenSceneConfig::GetStringListConfig();
82 if (stringListConfig.count("hallSwitchApp") != 0) {
83 packageNames_ = stringListConfig["hallSwitchApp"];
84 }
85 }
86
~DualDisplaySensorFoldStateManager()87 DualDisplaySensorFoldStateManager::~DualDisplaySensorFoldStateManager() {}
88
UpdateHallSwitchAppInfo(FoldStatus foldStatus)89 void DualDisplaySensorFoldStateManager::UpdateHallSwitchAppInfo(FoldStatus foldStatus)
90 {
91 if (foldStatus == FoldStatus::EXPAND || foldStatus == FoldStatus::HALF_FOLD) {
92 isHallSwitchApp_ = true;
93 }
94 }
95
HandleAngleChange(float angle,int hall,sptr<FoldScreenPolicy> foldScreenPolicy)96 void DualDisplaySensorFoldStateManager::HandleAngleChange(float angle, int hall,
97 sptr<FoldScreenPolicy> foldScreenPolicy)
98 {
99 currentAngle_ = angle;
100 if (IsTentMode()) {
101 return TentModeHandleSensorChange(angle, hall, foldScreenPolicy);
102 }
103 if (!CheckUpdateAngle(angle, hall)) {
104 return;
105 }
106
107 {
108 std::unique_lock<std::mutex> lock(foldStatusChangeMutex_);
109 isInTask_.store(true);
110 }
111 angleChangeCv_.notify_one();
112 FoldStatus nextState = GetNextFoldState(angle, hall);
113 if (nextState != GetCurrentState()) {
114 TLOGI(WmsLogTag::DMS, "angle: %{public}f, hall: %{public}d.", angle, hall);
115 }
116 UpdateHallSwitchAppInfo(nextState);
117 HandleSensorChange(nextState, angle, foldScreenPolicy);
118 }
119
HandleHallChange(float angle,int hall,sptr<FoldScreenPolicy> foldScreenPolicy)120 void DualDisplaySensorFoldStateManager::HandleHallChange(float angle, int hall,
121 sptr<FoldScreenPolicy> foldScreenPolicy)
122 {
123 if (hall == HALL_THRESHOLD || angle < HALL_ZERO_INVALID_POSTURE) {
124 {
125 std::unique_lock<std::mutex> lock(foldStatusChangeMutex_);
126 isInTask_.store(true);
127 }
128 angleChangeCv_.notify_one();
129 TLOGI(WmsLogTag::DMS, "angle: %{public}f, hall: %{public}d. hall is threshold or sensor less than 170.",
130 angle, hall);
131 HandleHallChangeInner(angle, hall, foldScreenPolicy);
132 return;
133 }
134
135 auto taskDualChangeFoldStatus = [this, angle, hall, foldScreenPolicy] {
136 TLOGI(WmsLogTag::DMS, "prepare go into timer, angle: %{public}f, hall: %{public}d.", angle, hall);
137 std::unique_lock<std::mutex> lock(foldStatusChangeMutex_);
138 isInTask_.store(false);
139 auto condition = [this] {
140 return this->isInTask_.load();
141 };
142 if (!angleChangeCv_.wait_for(lock, std::chrono::milliseconds(FULL_WAIT_TIMES), condition)) {
143 SensorReportTimeOutPro(angle, hall, foldScreenPolicy);
144 return;
145 }
146
147 TLOGI(WmsLogTag::DMS, "taskDualChangeFoldStatus was notified and not change foldStatus by hall.");
148 };
149 screenPowerTaskScheduler_->PostAsyncTask(taskDualChangeFoldStatus, __func__);
150 }
151
SensorReportTimeOutPro(float angle,int hall,const sptr<FoldScreenPolicy> & foldScreenPolicy)152 void DualDisplaySensorFoldStateManager::SensorReportTimeOutPro(float angle, int hall,
153 const sptr<FoldScreenPolicy>& foldScreenPolicy)
154 {
155 uint16_t currentHall = FoldScreenSensorManager::GetInstance().GetGlobalHall();
156 float currentAngle = FoldScreenSensorManager::GetInstance().GetGlobalAngle();
157 TLOGI(WmsLogTag::DMS, "currentAngle: %{public}f, currentHall: %{public}d.", currentAngle, currentHall);
158 if (currentHall == HALL_THRESHOLD) {
159 HandleHallChangeInner(angle, hall, foldScreenPolicy);
160 isInTask_.store(true);
161 return;
162 }
163 // no new angle upload, continue the process
164 if (FoldScreenStateInternel::FloatEqualAbs(currentAngle, angle)) {
165 TLOGI(WmsLogTag::DMS,
166 "angle: %{public}f, hall: %{public}d. no continuous angle uploads, continue to change foldstatus.",
167 currentAngle, currentHall);
168 FoldScreenSensorManager::GetInstance().SetGlobalAngle(ANGLE_MIN_VAL);
169 HandleHallChangeInner(ANGLE_MIN_VAL, hall, foldScreenPolicy);
170 isInTask_.store(true);
171 return;
172 }
173 if (currentAngle < HALL_ZERO_INVALID_POSTURE) {
174 HandleAngleChangeInTask(currentAngle, currentHall, foldScreenPolicy);
175 isInTask_.store(true);
176 return;
177 }
178 isInTask_.store(true);
179 TLOGI(WmsLogTag::DMS, "taskDualChangeFoldStatus time out and exit.");
180 return;
181 }
182
HandleHallChangeInner(float angle,int hall,const sptr<FoldScreenPolicy> & foldScreenPolicy)183 void DualDisplaySensorFoldStateManager::HandleHallChangeInner(float angle, int hall,
184 const sptr<FoldScreenPolicy>& foldScreenPolicy)
185 {
186 TLOGI(WmsLogTag::DMS, "HandleHallChange angle: %{public}f, hall: %{public}d.", angle, hall);
187 currentHall_ = hall;
188 if (IsTentMode()) {
189 return TentModeHandleSensorChange(angle, hall, foldScreenPolicy);
190 }
191 if (applicationStateObserver_ != nullptr && hall == HALL_THRESHOLD &&
192 PowerMgr::PowerMgrClient::GetInstance().IsScreenOn()) {
193 if (std::count(packageNames_.begin(), packageNames_.end(),
194 applicationStateObserver_->GetForegroundApp())) {
195 isHallSwitchApp_ = false;
196 return;
197 }
198 }
199 if (hall == HALL_THRESHOLD) {
200 angle = INWARD_HALF_FOLDED_MIN_THRESHOLD + 1.0f;
201 }
202 FoldStatus nextState = GetNextFoldState(angle, hall);
203 if (nextState != GetCurrentState()) {
204 TLOGI(WmsLogTag::DMS, "angle: %{public}f, hall: %{public}d.", angle, hall);
205 }
206 UpdateHallSwitchAppInfo(nextState);
207 HandleSensorChange(nextState, angle, foldScreenPolicy);
208 }
209
CheckUpdateAngle(float & angle,int hall)210 bool DualDisplaySensorFoldStateManager::CheckUpdateAngle(float& angle, int hall)
211 {
212 if (std::islessequal(angle, INWARD_FOLDED_THRESHOLD) && hall == HALL_THRESHOLD) {
213 return false;
214 }
215 if (std::isgreaterequal(angle, HALL_ZERO_INVALID_POSTURE) && hall == HALL_FOLDED_THRESHOLD) {
216 return false;
217 }
218 if (std::isless(angle, ANGLE_MIN_VAL)) {
219 return false;
220 }
221 if (hall == HALL_FOLDED_THRESHOLD) {
222 angle = ANGLE_MIN_VAL;
223 }
224 return true;
225 }
226
HandleAngleChangeInTask(float angle,int hall,const sptr<FoldScreenPolicy> & foldScreenPolicy)227 void DualDisplaySensorFoldStateManager::HandleAngleChangeInTask(float angle, int hall,
228 const sptr<FoldScreenPolicy>& foldScreenPolicy)
229 {
230 if (!CheckUpdateAngle(angle, hall)) {
231 return;
232 }
233 FoldStatus nextState = GetNextFoldState(angle, hall);
234 if (nextState != GetCurrentState()) {
235 TLOGI(WmsLogTag::DMS, "angle: %{public}f, hall: %{public}d.", angle, hall);
236 }
237 UpdateHallSwitchAppInfo(nextState);
238 HandleSensorChange(nextState, angle, foldScreenPolicy);
239 }
240
GetNextFoldState(float angle,int hall)241 FoldStatus DualDisplaySensorFoldStateManager::GetNextFoldState(float angle, int hall)
242 {
243 FoldStatus state = GetCurrentState();
244 if (std::isgreaterequal(angle, INWARD_EXPAND_THRESHOLD)) {
245 state = FoldStatus::EXPAND;
246 }
247 if (std::islessequal(angle, INWARD_FOLDED_LOWER_THRESHOLD)) {
248 state = FoldStatus::FOLDED;
249 }
250 if (isHallSwitchApp_) {
251 if (std::isgreaterequal(angle, INWARD_FOLDED_UPPER_THRESHOLD)
252 && std::islessequal(angle, INWARD_HALF_FOLDED_MAX_THRESHOLD)) {
253 isHallSwitchApp_ = true;
254 return FoldStatus::HALF_FOLD;
255 }
256 } else {
257 if (std::isgreaterequal(angle, INWARD_HALF_FOLDED_MIN_THRESHOLD)
258 && std::islessequal(angle, INWARD_HALF_FOLDED_MAX_THRESHOLD)) {
259 return FoldStatus::HALF_FOLD;
260 }
261 }
262 return state;
263 }
264
RegisterApplicationStateObserver()265 void DualDisplaySensorFoldStateManager::RegisterApplicationStateObserver()
266 {
267 applicationStateObserver_ = new (std::nothrow) ApplicationStateObserver();
268 auto appMgrClient_ = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
269 if (appMgrClient_ == nullptr) {
270 TLOGE(WmsLogTag::DMS, "appMgrClient_ is nullptr.");
271 } else {
272 auto flag = static_cast<int32_t>(
273 appMgrClient_->RegisterApplicationStateObserver(applicationStateObserver_, packageNames_));
274 if (flag != ERR_OK) {
275 TLOGE(WmsLogTag::DMS, "Register app debug listener failed.");
276 } else {
277 TLOGI(WmsLogTag::DMS, "Register app debug listener success.");
278 }
279 }
280 }
281
ApplicationStateObserver()282 ApplicationStateObserver::ApplicationStateObserver() {}
283
OnForegroundApplicationChanged(const AppStateData & appStateData)284 void ApplicationStateObserver::OnForegroundApplicationChanged(const AppStateData &appStateData)
285 {
286 if (appStateData.state == static_cast<int32_t>(ApplicationState::APP_STATE_FOREGROUND)) {
287 foregroundBundleName_ = appStateData.bundleName;
288 }
289 if (appStateData.state == static_cast<int32_t>(ApplicationState::APP_STATE_BACKGROUND)
290 && foregroundBundleName_.compare(appStateData.bundleName) == 0) {
291 foregroundBundleName_ = "" ;
292 }
293 }
294
GetForegroundApp()295 std::string ApplicationStateObserver::GetForegroundApp()
296 {
297 return foregroundBundleName_;
298 }
299
HandleTentChange(int tentType,sptr<FoldScreenPolicy> foldScreenPolicy,int32_t hall)300 void DualDisplaySensorFoldStateManager::HandleTentChange(int tentType,
301 sptr<FoldScreenPolicy> foldScreenPolicy, int32_t hall)
302 {
303 // 1 open 0 close
304 uint32_t isopen = 0;
305 if (ScreenSettingHelper::GetSettingValue(isopen, "wallpaperAodDisplay")) {
306 TLOGI(WmsLogTag::DMS, "tent mode wallpaperAodDisplay %{public}u", isopen);
307 } else {
308 TLOGW(WmsLogTag::DMS, "tent mode read setting wallpaperAodDisplay failed ");
309 }
310 if (isopen == 0) {
311 TLOGI(WmsLogTag::DMS, "tent mode wallpaperAodDisplay close, return");
312 return;
313 }
314 if (tentType == tentModeType_) {
315 TLOGI(WmsLogTag::DMS, "Repeat reporting tent mode:%{public}d, no processing", tentModeType_);
316 return;
317 }
318 if (foldScreenPolicy == nullptr) {
319 TLOGE(WmsLogTag::DMS, "foldScreenPolicy is nullptr");
320 return;
321 }
322 SetTentMode(tentType);
323 if (tentType == TENT_MODE_ON) {
324 ReportTentStatusChange(ReportDualTentModeStatus::NORMAL_ENTER_TENT_MODE);
325 HandleSensorChange(FoldStatus::FOLDED, currentAngle_, foldScreenPolicy);
326 foldScreenPolicy->ChangeOnTentMode(FoldStatus::FOLDED);
327 } else if (tentType == TENT_MODE_OFF) {
328 if (hall == HALL_FOLDED_THRESHOLD) {
329 currentAngle_ = ANGLE_MIN_VAL;
330 }
331 FoldStatus nextState = FoldStatus::UNKNOWN;
332 if (hall == -1) {
333 nextState = GetNextFoldState(currentAngle_, currentHall_);
334 } else {
335 nextState = GetNextFoldState(currentAngle_, hall);
336 }
337 HandleSensorChange(nextState, currentAngle_, foldScreenPolicy);
338 ReportTentStatusChange(ReportDualTentModeStatus::NORMAL_EXIT_TENT_MODE);
339 foldScreenPolicy->ChangeOffTentMode();
340 }
341 }
342
TriggerTentExit(float angle,int hall)343 bool DualDisplaySensorFoldStateManager::TriggerTentExit(float angle, int hall)
344 {
345 if (hall == HALL_FOLDED_THRESHOLD) {
346 ReportTentStatusChange(ReportDualTentModeStatus::ABNORMAL_EXIT_TENT_MODE_DUE_TO_HALL);
347 TLOGI(WmsLogTag::DMS, "Exit tent mode due to hall sensor report folded");
348 return true;
349 }
350
351 if (std::isgreater(angle, TENT_MODE_EXIT_MAX_THRESHOLD)) {
352 ReportTentStatusChange(ReportDualTentModeStatus::ABNORMAL_EXIT_TENT_MODE_DUE_TO_ANGLE);
353 TLOGI(WmsLogTag::DMS, "Exit tent mode due to angle sensor report angle:%{public}f", angle);
354 return true;
355 }
356
357 return false;
358 }
359
TentModeHandleSensorChange(float angle,int hall,sptr<FoldScreenPolicy> foldScreenPolicy)360 void DualDisplaySensorFoldStateManager::TentModeHandleSensorChange(float angle, int hall,
361 sptr<FoldScreenPolicy> foldScreenPolicy)
362 {
363 if (TriggerTentExit(angle, hall)) {
364 FoldStatus nextState = GetNextFoldState(angle, hall);
365 HandleSensorChange(nextState, angle, foldScreenPolicy);
366 TLOGI(WmsLogTag::DMS, "exit tent mode. angle: %{public}f, hall: %{public}d", angle, hall);
367 SetTentMode(TENT_MODE_OFF);
368 ScreenRotationProperty::HandleHoverStatusEventInput(DeviceHoverStatus::TENT_STATUS_CANCEL,
369 hall == HALL_THRESHOLD ? false : true);
370 }
371 }
372
ReportTentStatusChange(ReportDualTentModeStatus tentStatus)373 void DualDisplaySensorFoldStateManager::ReportTentStatusChange(ReportDualTentModeStatus tentStatus)
374 {
375 int32_t status = static_cast<int32_t>(tentStatus);
376 TLOGI(WmsLogTag::DMS, "report tentStatus: %{public}d", status);
377 int32_t ret = HiSysEventWrite(
378 OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER,
379 "FOLD_TENT_MODE",
380 OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
381 "FOLD_TENT_STATUS", status);
382 if (ret != 0) {
383 TLOGE(WmsLogTag::DMS, "Write HiSysEvent error, ret: %{public}d", ret);
384 }
385 }
386 } // namespace OHOS::Rosen