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