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