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 if (deviceToDisplayRotationMap_.empty()) {
352 deviceToDisplayRotationMap_ = {
353 {DeviceRotation::ROTATION_PORTRAIT,
354 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
355 {DeviceRotation::ROTATION_LANDSCAPE,
356 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
357 {DeviceRotation::ROTATION_PORTRAIT_INVERTED,
358 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
359 {DeviceRotation::ROTATION_LANDSCAPE_INVERTED,
360 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
361 };
362 }
363 if (displayToDisplayOrientationMap_.empty()) {
364 displayToDisplayOrientationMap_ = {
365 {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
366 DisplayOrientation::PORTRAIT},
367 {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
368 DisplayOrientation::LANDSCAPE},
369 {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
370 DisplayOrientation::PORTRAIT_INVERTED},
371 {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
372 DisplayOrientation::LANDSCAPE_INVERTED},
373 };
374 }
375 if (sensorToDeviceRotationMap_.empty()) {
376 sensorToDeviceRotationMap_ = {
377 {SensorRotation::ROTATION_0, CalcDeviceRotation(SensorRotation::ROTATION_0)},
378 {SensorRotation::ROTATION_90, CalcDeviceRotation(SensorRotation::ROTATION_90)},
379 {SensorRotation::ROTATION_180, CalcDeviceRotation(SensorRotation::ROTATION_180)},
380 {SensorRotation::ROTATION_270, CalcDeviceRotation(SensorRotation::ROTATION_270)},
381 {SensorRotation::INVALID, DeviceRotation::INVALID},
382 };
383 }
384 }
385
IsDeviceRotationVertical(DeviceRotation deviceRotation)386 bool ScreenRotationController::IsDeviceRotationVertical(DeviceRotation deviceRotation)
387 {
388 return (deviceRotation == DeviceRotation::ROTATION_PORTRAIT) ||
389 (deviceRotation == DeviceRotation::ROTATION_PORTRAIT_INVERTED);
390 }
391
IsDeviceRotationHorizontal(DeviceRotation deviceRotation)392 bool ScreenRotationController::IsDeviceRotationHorizontal(DeviceRotation deviceRotation)
393 {
394 return (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE) ||
395 (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE_INVERTED);
396 }
397
IsCurrentDisplayVertical()398 bool ScreenRotationController::IsCurrentDisplayVertical()
399 {
400 return IsDisplayRotationVertical(GetCurrentDisplayRotation());
401 }
402
IsCurrentDisplayHorizontal()403 bool ScreenRotationController::IsCurrentDisplayHorizontal()
404 {
405 return IsDisplayRotationHorizontal(GetCurrentDisplayRotation());
406 }
407
IsDefaultDisplayRotationPortrait()408 bool ScreenRotationController::IsDefaultDisplayRotationPortrait()
409 {
410 return Rotation::ROTATION_0 == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT);
411 }
412
IsDisplayRotationVertical(Rotation rotation)413 bool ScreenRotationController::IsDisplayRotationVertical(Rotation rotation)
414 {
415 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT)) ||
416 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED));
417 }
418
IsDisplayRotationHorizontal(Rotation rotation)419 bool ScreenRotationController::IsDisplayRotationHorizontal(Rotation rotation)
420 {
421 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE)) ||
422 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED));
423 }
424
ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation,bool withAnimation)425 void ScreenRotationController::ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation, bool withAnimation)
426 {
427 if (lastOrientationType_ == orientation) {
428 return;
429 }
430 lastOrientationType_ = orientation;
431 switch (orientation) {
432 case Orientation::UNSPECIFIED: {
433 SetScreenRotation(Rotation::ROTATION_0, withAnimation);
434 break;
435 }
436 case Orientation::VERTICAL: {
437 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT), withAnimation);
438 break;
439 }
440 case Orientation::REVERSE_VERTICAL: {
441 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED),
442 withAnimation);
443 break;
444 }
445 case Orientation::HORIZONTAL: {
446 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE), withAnimation);
447 break;
448 }
449 case Orientation::REVERSE_HORIZONTAL: {
450 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED),
451 withAnimation);
452 break;
453 }
454 default: {
455 return;
456 }
457 }
458 }
459
ProcessOrientationSwitch(Orientation orientation,bool withAnimation)460 void ScreenRotationController::ProcessOrientationSwitch(Orientation orientation, bool withAnimation)
461 {
462 if (!IsSensorRelatedOrientation(orientation)) {
463 ProcessSwitchToSensorUnrelatedOrientation(orientation, withAnimation);
464 } else {
465 ProcessSwitchToSensorRelatedOrientation(orientation, lastSensorRotationConverted_);
466 }
467 }
468 } // Rosen
469 } // OHOS