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