1 /*
2  * Copyright (c) 2022 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 "screen_rotation_controller.h"
17 
18 #include <chrono>
19 #include <securec.h>
20 
21 #include "display_manager_service_inner.h"
22 
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "ScreenRotationController"};
27 }
28 
29 DisplayId ScreenRotationController::defaultDisplayId_ = 0;
30 Rotation ScreenRotationController::currentDisplayRotation_;
31 bool ScreenRotationController::isScreenRotationLocked_ = true;
32 uint32_t ScreenRotationController::defaultDeviceRotationOffset_ = 0;
33 Orientation ScreenRotationController::lastOrientationType_ = Orientation::UNSPECIFIED;
34 Rotation ScreenRotationController::lastSensorDecidedRotation_;
35 Rotation ScreenRotationController::rotationLockedRotation_;
36 uint32_t ScreenRotationController::defaultDeviceRotation_ = 0;
37 std::map<SensorRotation, DeviceRotation> ScreenRotationController::sensorToDeviceRotationMap_;
38 std::map<DeviceRotation, Rotation> ScreenRotationController::deviceToDisplayRotationMap_;
39 std::map<Rotation, DisplayOrientation> ScreenRotationController::displayToDisplayOrientationMap_;
40 DeviceRotation ScreenRotationController::lastSensorRotationConverted_ = DeviceRotation::INVALID;
41 
Init()42 void ScreenRotationController::Init()
43 {
44     ProcessRotationMapping();
45     currentDisplayRotation_ = GetCurrentDisplayRotation();
46     defaultDisplayId_ = DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId();
47     if (defaultDisplayId_  == DISPLAY_ID_INVALID) {
48         WLOGFE("defaultDisplayId_ is invalid");
49     }
50     lastSensorDecidedRotation_ = currentDisplayRotation_;
51     rotationLockedRotation_ = currentDisplayRotation_;
52 }
53 
IsScreenRotationLocked()54 bool ScreenRotationController::IsScreenRotationLocked()
55 {
56     return isScreenRotationLocked_;
57 }
58 
SetScreenRotationLocked(bool isLocked)59 DMError ScreenRotationController::SetScreenRotationLocked(bool isLocked)
60 {
61     isScreenRotationLocked_ = isLocked;
62     if (isLocked) {
63         rotationLockedRotation_ = GetCurrentDisplayRotation();
64         return DMError::DM_OK;
65     }
66     if (GetCurrentDisplayRotation() == ConvertDeviceToDisplayRotation(lastSensorRotationConverted_)) {
67         return DMError::DM_OK;
68     }
69     Orientation currentOrientation = GetPreferredOrientation();
70     if (IsSensorRelatedOrientation(currentOrientation)) {
71         ProcessSwitchToSensorRelatedOrientation(currentOrientation, lastSensorRotationConverted_);
72     }
73     return DMError::DM_OK;
74 }
75 
SetDefaultDeviceRotationOffset(uint32_t defaultDeviceRotationOffset)76 void ScreenRotationController::SetDefaultDeviceRotationOffset(uint32_t defaultDeviceRotationOffset)
77 {
78     // Available options for defaultDeviceRotationOffset: {0, 90, 180, 270}
79     if (defaultDeviceRotationOffset < 0 || defaultDeviceRotationOffset > 270 || defaultDeviceRotationOffset % 90 != 0) {
80         return;
81     }
82     defaultDeviceRotationOffset_ = defaultDeviceRotationOffset;
83 }
84 
HandleSensorEventInput(DeviceRotation deviceRotation)85 void ScreenRotationController::HandleSensorEventInput(DeviceRotation deviceRotation)
86 {
87     if (deviceRotation == DeviceRotation::INVALID) {
88         WLOGFW("deviceRotation is invalid, return.");
89         return;
90     }
91     Orientation orientation = GetPreferredOrientation();
92     currentDisplayRotation_ = GetCurrentDisplayRotation();
93     lastSensorRotationConverted_ = deviceRotation;
94     if (!IsSensorRelatedOrientation(orientation)) {
95         WLOGFD("If the current preferred orientation is locked or sensor-independent, return.");
96         return;
97     }
98 
99     if (currentDisplayRotation_ == ConvertDeviceToDisplayRotation(deviceRotation)) {
100         WLOGFD("If the current display rotation is same to sensor rotation, return.");
101         return;
102     }
103     Rotation targetDisplayRotation = CalcTargetDisplayRotation(orientation, deviceRotation);
104     SetScreenRotation(targetDisplayRotation);
105 }
106 
GetCurrentDisplayRotation()107 Rotation ScreenRotationController::GetCurrentDisplayRotation()
108 {
109     sptr<DisplayInfo> defaultDisplayInfo = DisplayManagerServiceInner::GetInstance().GetDefaultDisplay();
110     if (defaultDisplayInfo == nullptr) {
111         WLOGFE("Cannot get default display info");
112         return defaultDeviceRotation_ == 0 ? ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT) :
113             ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE);
114     }
115     return defaultDisplayInfo->GetRotation();
116 }
117 
GetPreferredOrientation()118 Orientation ScreenRotationController::GetPreferredOrientation()
119 {
120     sptr<ScreenInfo> screenInfo = DisplayManagerServiceInner::GetInstance().GetScreenInfoByDisplayId(defaultDisplayId_);
121     if (screenInfo == nullptr) {
122         WLOGFE("Cannot get default screen info");
123         return Orientation::UNSPECIFIED;
124     }
125     return screenInfo->GetOrientation();
126 }
127 
CalcTargetDisplayRotation(Orientation requestedOrientation,DeviceRotation sensorRotationConverted)128 Rotation ScreenRotationController::CalcTargetDisplayRotation(
129     Orientation requestedOrientation, DeviceRotation sensorRotationConverted)
130 {
131     switch (requestedOrientation) {
132         case Orientation::SENSOR: {
133             lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted);
134             return lastSensorDecidedRotation_;
135         }
136         case Orientation::SENSOR_VERTICAL: {
137             return ProcessAutoRotationPortraitOrientation(sensorRotationConverted);
138         }
139         case Orientation::SENSOR_HORIZONTAL: {
140             return ProcessAutoRotationLandscapeOrientation(sensorRotationConverted);
141         }
142         case Orientation::AUTO_ROTATION_RESTRICTED: {
143             if (isScreenRotationLocked_) {
144                 return currentDisplayRotation_;
145             }
146             lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted);
147             return lastSensorDecidedRotation_;
148         }
149         case Orientation::AUTO_ROTATION_PORTRAIT_RESTRICTED: {
150             if (isScreenRotationLocked_) {
151                 return currentDisplayRotation_;
152             }
153             return ProcessAutoRotationPortraitOrientation(sensorRotationConverted);
154         }
155         case Orientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED: {
156             if (isScreenRotationLocked_) {
157                 return currentDisplayRotation_;
158             }
159             return ProcessAutoRotationLandscapeOrientation(sensorRotationConverted);
160         }
161         default: {
162             return currentDisplayRotation_;
163         }
164     }
165 }
166 
ProcessAutoRotationPortraitOrientation(DeviceRotation sensorRotationConverted)167 Rotation ScreenRotationController::ProcessAutoRotationPortraitOrientation(DeviceRotation sensorRotationConverted)
168 {
169     if (IsDeviceRotationHorizontal(sensorRotationConverted)) {
170         return currentDisplayRotation_;
171     }
172     lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted);
173     return lastSensorDecidedRotation_;
174 }
175 
ProcessAutoRotationLandscapeOrientation(DeviceRotation sensorRotationConverted)176 Rotation ScreenRotationController::ProcessAutoRotationLandscapeOrientation(DeviceRotation sensorRotationConverted)
177 {
178     if (IsDeviceRotationVertical(sensorRotationConverted)) {
179         return currentDisplayRotation_;
180     }
181     lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted);
182     return lastSensorDecidedRotation_;
183 }
184 
SetScreenRotation(Rotation targetRotation,bool withAnimation)185 void ScreenRotationController::SetScreenRotation(Rotation targetRotation, bool withAnimation)
186 {
187     if (targetRotation == GetCurrentDisplayRotation()) {
188         return;
189     }
190     DisplayManagerServiceInner::GetInstance().GetDefaultDisplay()->SetRotation(targetRotation);
191     DisplayManagerServiceInner::GetInstance().SetRotationFromWindow(defaultDisplayId_, targetRotation, withAnimation);
192     WLOGFI("dms: Set screen rotation: %{public}u withAnimation: %{public}u", targetRotation, withAnimation);
193 }
194 
CalcDeviceRotation(SensorRotation sensorRotation)195 DeviceRotation ScreenRotationController::CalcDeviceRotation(SensorRotation sensorRotation)
196 {
197     if (sensorRotation == SensorRotation::INVALID) {
198         return DeviceRotation::INVALID;
199     }
200     // offset(in degree) divided by 90 to get rotation bias
201     int32_t bias = static_cast<int32_t>(defaultDeviceRotationOffset_ / 90);
202     int32_t deviceRotationValue = static_cast<int32_t>(sensorRotation) - bias;
203     while (deviceRotationValue < 0) {
204         // +4 is used to normalize the values into the range 0~3, corresponding to the four rotations.
205         deviceRotationValue += 4;
206     }
207     if (defaultDeviceRotation_ == 1) {
208         deviceRotationValue += static_cast<int32_t>(defaultDeviceRotation_);
209         // %2 to determine whether the rotation is horizontal or vertical.
210         if (deviceRotationValue % 2 == 0) {
211             // if device's default rotation is landscape, use -2 to swap 0 and 90, 180 and 270.
212             deviceRotationValue -= 2;
213         }
214     }
215     return static_cast<DeviceRotation>(deviceRotationValue);
216 }
217 
IsSensorRelatedOrientation(Orientation orientation)218 bool ScreenRotationController::IsSensorRelatedOrientation(Orientation orientation)
219 {
220     if ((orientation >= Orientation::UNSPECIFIED && orientation <= Orientation::REVERSE_HORIZONTAL) ||
221         orientation == Orientation::LOCKED) {
222         return false;
223     }
224     return true;
225 }
226 
ProcessSwitchToSensorRelatedOrientation(Orientation orientation,DeviceRotation sensorRotationConverted)227 void ScreenRotationController::ProcessSwitchToSensorRelatedOrientation(
228     Orientation orientation, DeviceRotation sensorRotationConverted)
229 {
230     lastOrientationType_ = orientation;
231     switch (orientation) {
232         case Orientation::AUTO_ROTATION_RESTRICTED: {
233             if (isScreenRotationLocked_) {
234                 SetScreenRotation(rotationLockedRotation_);
235                 return;
236             }
237             [[fallthrough]];
238         }
239         case Orientation::SENSOR: {
240             ProcessSwitchToAutoRotation(sensorRotationConverted);
241             return;
242         }
243         case Orientation::AUTO_ROTATION_PORTRAIT_RESTRICTED: {
244             if (isScreenRotationLocked_) {
245                 ProcessSwitchToAutoRotationPortraitRestricted();
246                 return;
247             }
248             [[fallthrough]];
249         }
250         case Orientation::SENSOR_VERTICAL: {
251             ProcessSwitchToAutoRotationPortrait(sensorRotationConverted);
252             return;
253         }
254         case Orientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED: {
255             if (isScreenRotationLocked_) {
256                 ProcessSwitchToAutoRotationLandscapeRestricted();
257                 return;
258             }
259             [[fallthrough]];
260         }
261         case Orientation::SENSOR_HORIZONTAL: {
262             ProcessSwitchToAutoRotationLandscape(sensorRotationConverted);
263             return;
264         }
265         default: {
266             return;
267         }
268     }
269 }
270 
ProcessSwitchToAutoRotation(DeviceRotation rotation)271 void ScreenRotationController::ProcessSwitchToAutoRotation(DeviceRotation rotation)
272 {
273     if (rotation != DeviceRotation::INVALID) {
274         SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
275     }
276 }
277 
ProcessSwitchToAutoRotationPortrait(DeviceRotation rotation)278 void ScreenRotationController::ProcessSwitchToAutoRotationPortrait(DeviceRotation rotation)
279 {
280     if (IsDeviceRotationVertical(rotation)) {
281         SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
282         return;
283     }
284     SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT));
285 }
286 
ProcessSwitchToAutoRotationLandscape(DeviceRotation rotation)287 void ScreenRotationController::ProcessSwitchToAutoRotationLandscape(DeviceRotation rotation)
288 {
289     if (IsDeviceRotationHorizontal(rotation)) {
290         SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
291         return;
292     }
293     SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE));
294 }
295 
ProcessSwitchToAutoRotationPortraitRestricted()296 void ScreenRotationController::ProcessSwitchToAutoRotationPortraitRestricted()
297 {
298     if (IsCurrentDisplayVertical()) {
299         return;
300     }
301     if (IsDisplayRotationVertical(rotationLockedRotation_)) {
302         SetScreenRotation(rotationLockedRotation_);
303         return;
304     }
305     SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT));
306 }
307 
ProcessSwitchToAutoRotationLandscapeRestricted()308 void ScreenRotationController::ProcessSwitchToAutoRotationLandscapeRestricted()
309 {
310     if (IsCurrentDisplayHorizontal()) {
311         return;
312     }
313     if (IsDisplayRotationHorizontal(rotationLockedRotation_)) {
314         SetScreenRotation(rotationLockedRotation_);
315         return;
316     }
317     SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE));
318 }
319 
ConvertSensorToDeviceRotation(SensorRotation sensorRotation)320 DeviceRotation ScreenRotationController::ConvertSensorToDeviceRotation(SensorRotation sensorRotation)
321 {
322     if (sensorToDeviceRotationMap_.empty()) {
323         ProcessRotationMapping();
324     }
325     return sensorToDeviceRotationMap_.at(sensorRotation);
326 }
327 
ConvertRotationToDisplayOrientation(Rotation rotation)328 DisplayOrientation ScreenRotationController::ConvertRotationToDisplayOrientation(Rotation rotation)
329 {
330     if (displayToDisplayOrientationMap_.empty()) {
331         ProcessRotationMapping();
332     }
333     return displayToDisplayOrientationMap_.at(rotation);
334 }
335 
ConvertDeviceToDisplayRotation(DeviceRotation deviceRotation)336 Rotation ScreenRotationController::ConvertDeviceToDisplayRotation(DeviceRotation deviceRotation)
337 {
338     if (deviceRotation == DeviceRotation::INVALID) {
339         return GetCurrentDisplayRotation();
340     }
341     if (deviceToDisplayRotationMap_.empty()) {
342         ProcessRotationMapping();
343     }
344     return deviceToDisplayRotationMap_.at(deviceRotation);
345 }
346 
ProcessRotationMapping()347 void ScreenRotationController::ProcessRotationMapping()
348 {
349     sptr<SupportedScreenModes> modes =
350         DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(defaultDisplayId_);
351 
352     // 0 means PORTRAIT, 1 means LANDSCAPE.
353     defaultDeviceRotation_ = (modes == nullptr || modes->width_ < modes->height_) ? 0 : 1;
354 
355     if (deviceToDisplayRotationMap_.empty()) {
356         deviceToDisplayRotationMap_ = {
357             {DeviceRotation::ROTATION_PORTRAIT,
358                 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
359             {DeviceRotation::ROTATION_LANDSCAPE,
360                 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
361             {DeviceRotation::ROTATION_PORTRAIT_INVERTED,
362                 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
363             {DeviceRotation::ROTATION_LANDSCAPE_INVERTED,
364                 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
365         };
366     }
367     if (displayToDisplayOrientationMap_.empty()) {
368         displayToDisplayOrientationMap_ = {
369             {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
370                 DisplayOrientation::PORTRAIT},
371             {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
372                 DisplayOrientation::LANDSCAPE},
373             {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
374                 DisplayOrientation::PORTRAIT_INVERTED},
375             {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
376                 DisplayOrientation::LANDSCAPE_INVERTED},
377         };
378     }
379     if (sensorToDeviceRotationMap_.empty()) {
380         sensorToDeviceRotationMap_ = {
381             {SensorRotation::ROTATION_0, CalcDeviceRotation(SensorRotation::ROTATION_0)},
382             {SensorRotation::ROTATION_90, CalcDeviceRotation(SensorRotation::ROTATION_90)},
383             {SensorRotation::ROTATION_180, CalcDeviceRotation(SensorRotation::ROTATION_180)},
384             {SensorRotation::ROTATION_270, CalcDeviceRotation(SensorRotation::ROTATION_270)},
385             {SensorRotation::INVALID, DeviceRotation::INVALID},
386         };
387     }
388 }
389 
IsDeviceRotationVertical(DeviceRotation deviceRotation)390 bool ScreenRotationController::IsDeviceRotationVertical(DeviceRotation deviceRotation)
391 {
392     return (deviceRotation == DeviceRotation::ROTATION_PORTRAIT) ||
393         (deviceRotation == DeviceRotation::ROTATION_PORTRAIT_INVERTED);
394 }
395 
IsDeviceRotationHorizontal(DeviceRotation deviceRotation)396 bool ScreenRotationController::IsDeviceRotationHorizontal(DeviceRotation deviceRotation)
397 {
398     return (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE) ||
399         (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE_INVERTED);
400 }
401 
IsCurrentDisplayVertical()402 bool ScreenRotationController::IsCurrentDisplayVertical()
403 {
404     return IsDisplayRotationVertical(GetCurrentDisplayRotation());
405 }
406 
IsCurrentDisplayHorizontal()407 bool ScreenRotationController::IsCurrentDisplayHorizontal()
408 {
409     return IsDisplayRotationHorizontal(GetCurrentDisplayRotation());
410 }
411 
IsDefaultDisplayRotationPortrait()412 bool ScreenRotationController::IsDefaultDisplayRotationPortrait()
413 {
414     return Rotation::ROTATION_0 == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT);
415 }
416 
IsDisplayRotationVertical(Rotation rotation)417 bool ScreenRotationController::IsDisplayRotationVertical(Rotation rotation)
418 {
419     return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT)) ||
420         (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED));
421 }
422 
IsDisplayRotationHorizontal(Rotation rotation)423 bool ScreenRotationController::IsDisplayRotationHorizontal(Rotation rotation)
424 {
425     return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE)) ||
426         (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED));
427 }
428 
ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation,bool withAnimation)429 void ScreenRotationController::ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation, bool withAnimation)
430 {
431     if (lastOrientationType_ == orientation) {
432         return;
433     }
434     lastOrientationType_ = orientation;
435     switch (orientation) {
436         case Orientation::UNSPECIFIED: {
437             SetScreenRotation(Rotation::ROTATION_0, withAnimation);
438             break;
439         }
440         case Orientation::VERTICAL: {
441             SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT), withAnimation);
442             break;
443         }
444         case Orientation::REVERSE_VERTICAL: {
445             SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED),
446                 withAnimation);
447             break;
448         }
449         case Orientation::HORIZONTAL: {
450             SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE), withAnimation);
451             break;
452         }
453         case Orientation::REVERSE_HORIZONTAL: {
454             SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED),
455                 withAnimation);
456             break;
457         }
458         default: {
459             return;
460         }
461     }
462 }
463 
ProcessOrientationSwitch(Orientation orientation,bool withAnimation)464 void ScreenRotationController::ProcessOrientationSwitch(Orientation orientation, bool withAnimation)
465 {
466     if (!IsSensorRelatedOrientation(orientation)) {
467         ProcessSwitchToSensorUnrelatedOrientation(orientation, withAnimation);
468     } else {
469         ProcessSwitchToSensorRelatedOrientation(orientation, lastSensorRotationConverted_);
470     }
471 }
472 } // Rosen
473 } // OHOS