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