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
26 DisplayId ScreenRotationController::defaultDisplayId_ = 0;
27 Rotation ScreenRotationController::currentDisplayRotation_;
28 bool ScreenRotationController::isScreenRotationLocked_ = true;
29 uint32_t ScreenRotationController::defaultDeviceRotationOffset_ = 0;
30 Orientation ScreenRotationController::lastOrientationType_ = Orientation::UNSPECIFIED;
31 Rotation ScreenRotationController::lastSensorDecidedRotation_;
32 Rotation ScreenRotationController::rotationLockedRotation_;
33 uint32_t ScreenRotationController::defaultDeviceRotation_ = 0;
34 std::map<SensorRotation, DeviceRotation> ScreenRotationController::sensorToDeviceRotationMap_;
35 std::map<DeviceRotation, Rotation> ScreenRotationController::deviceToDisplayRotationMap_;
36 std::map<Rotation, DisplayOrientation> ScreenRotationController::displayToDisplayOrientationMap_;
37 DeviceRotation ScreenRotationController::lastSensorRotationConverted_ = DeviceRotation::INVALID;
38
Init()39 void ScreenRotationController::Init()
40 {
41 ProcessRotationMapping();
42 currentDisplayRotation_ = GetCurrentDisplayRotation();
43 defaultDisplayId_ = DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId();
44 if (defaultDisplayId_ == DISPLAY_ID_INVALID) {
45 TLOGE(WmsLogTag::DMS, "defaultDisplayId_ is invalid");
46 }
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 TLOGW(WmsLogTag::DMS, "deviceRotation is invalid, return.");
86 return;
87 }
88 Orientation orientation = GetPreferredOrientation();
89 currentDisplayRotation_ = GetCurrentDisplayRotation();
90 lastSensorRotationConverted_ = deviceRotation;
91 if (!IsSensorRelatedOrientation(orientation)) {
92 TLOGD(WmsLogTag::DMS, "If the current preferred orientation is locked or sensor-independent, return.");
93 return;
94 }
95
96 if (currentDisplayRotation_ == ConvertDeviceToDisplayRotation(deviceRotation)) {
97 TLOGD(WmsLogTag::DMS, "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 TLOGE(WmsLogTag::DMS, "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 TLOGE(WmsLogTag::DMS, "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 TLOGI(WmsLogTag::DMS, "dms: Set screen rotation: %{public}u withAnimation: %{public}u", targetRotation,
190 withAnimation);
191 }
192
CalcDeviceRotation(SensorRotation sensorRotation)193 DeviceRotation ScreenRotationController::CalcDeviceRotation(SensorRotation sensorRotation)
194 {
195 if (sensorRotation == SensorRotation::INVALID) {
196 return DeviceRotation::INVALID;
197 }
198 // offset(in degree) divided by 90 to get rotation bias
199 int32_t bias = static_cast<int32_t>(defaultDeviceRotationOffset_ / 90);
200 int32_t deviceRotationValue = static_cast<int32_t>(sensorRotation) - bias;
201 while (deviceRotationValue < 0) {
202 // +4 is used to normalize the values into the range 0~3, corresponding to the four rotations.
203 deviceRotationValue += 4;
204 }
205 if (defaultDeviceRotation_ == 1) {
206 deviceRotationValue += static_cast<int32_t>(defaultDeviceRotation_);
207 // %2 to determine whether the rotation is horizontal or vertical.
208 if (deviceRotationValue % 2 == 0) {
209 // if device's default rotation is landscape, use -2 to swap 0 and 90, 180 and 270.
210 deviceRotationValue -= 2;
211 }
212 }
213 return static_cast<DeviceRotation>(deviceRotationValue);
214 }
215
IsSensorRelatedOrientation(Orientation orientation)216 bool ScreenRotationController::IsSensorRelatedOrientation(Orientation orientation)
217 {
218 if ((orientation >= Orientation::UNSPECIFIED && orientation <= Orientation::REVERSE_HORIZONTAL) ||
219 orientation == Orientation::LOCKED) {
220 return false;
221 }
222 return true;
223 }
224
ProcessSwitchToSensorRelatedOrientation(Orientation orientation,DeviceRotation sensorRotationConverted)225 void ScreenRotationController::ProcessSwitchToSensorRelatedOrientation(
226 Orientation orientation, DeviceRotation sensorRotationConverted)
227 {
228 lastOrientationType_ = orientation;
229 switch (orientation) {
230 case Orientation::AUTO_ROTATION_RESTRICTED: {
231 if (isScreenRotationLocked_) {
232 SetScreenRotation(rotationLockedRotation_);
233 return;
234 }
235 [[fallthrough]];
236 }
237 case Orientation::SENSOR: {
238 ProcessSwitchToAutoRotation(sensorRotationConverted);
239 return;
240 }
241 case Orientation::AUTO_ROTATION_PORTRAIT_RESTRICTED: {
242 if (isScreenRotationLocked_) {
243 ProcessSwitchToAutoRotationPortraitRestricted();
244 return;
245 }
246 [[fallthrough]];
247 }
248 case Orientation::SENSOR_VERTICAL: {
249 ProcessSwitchToAutoRotationPortrait(sensorRotationConverted);
250 return;
251 }
252 case Orientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED: {
253 if (isScreenRotationLocked_) {
254 ProcessSwitchToAutoRotationLandscapeRestricted();
255 return;
256 }
257 [[fallthrough]];
258 }
259 case Orientation::SENSOR_HORIZONTAL: {
260 ProcessSwitchToAutoRotationLandscape(sensorRotationConverted);
261 return;
262 }
263 default: {
264 return;
265 }
266 }
267 }
268
ProcessSwitchToAutoRotation(DeviceRotation rotation)269 void ScreenRotationController::ProcessSwitchToAutoRotation(DeviceRotation rotation)
270 {
271 if (rotation != DeviceRotation::INVALID) {
272 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
273 }
274 }
275
ProcessSwitchToAutoRotationPortrait(DeviceRotation rotation)276 void ScreenRotationController::ProcessSwitchToAutoRotationPortrait(DeviceRotation rotation)
277 {
278 if (IsDeviceRotationVertical(rotation)) {
279 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
280 return;
281 }
282 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT));
283 }
284
ProcessSwitchToAutoRotationLandscape(DeviceRotation rotation)285 void ScreenRotationController::ProcessSwitchToAutoRotationLandscape(DeviceRotation rotation)
286 {
287 if (IsDeviceRotationHorizontal(rotation)) {
288 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation));
289 return;
290 }
291 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE));
292 }
293
ProcessSwitchToAutoRotationPortraitRestricted()294 void ScreenRotationController::ProcessSwitchToAutoRotationPortraitRestricted()
295 {
296 if (IsCurrentDisplayVertical()) {
297 return;
298 }
299 if (IsDisplayRotationVertical(rotationLockedRotation_)) {
300 SetScreenRotation(rotationLockedRotation_);
301 return;
302 }
303 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT));
304 }
305
ProcessSwitchToAutoRotationLandscapeRestricted()306 void ScreenRotationController::ProcessSwitchToAutoRotationLandscapeRestricted()
307 {
308 if (IsCurrentDisplayHorizontal()) {
309 return;
310 }
311 if (IsDisplayRotationHorizontal(rotationLockedRotation_)) {
312 SetScreenRotation(rotationLockedRotation_);
313 return;
314 }
315 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE));
316 }
317
ConvertSensorToDeviceRotation(SensorRotation sensorRotation)318 DeviceRotation ScreenRotationController::ConvertSensorToDeviceRotation(SensorRotation sensorRotation)
319 {
320 if (sensorToDeviceRotationMap_.empty()) {
321 ProcessRotationMapping();
322 }
323 return sensorToDeviceRotationMap_.at(sensorRotation);
324 }
325
ConvertRotationToDisplayOrientation(Rotation rotation)326 DisplayOrientation ScreenRotationController::ConvertRotationToDisplayOrientation(Rotation rotation)
327 {
328 if (displayToDisplayOrientationMap_.empty()) {
329 ProcessRotationMapping();
330 }
331 return displayToDisplayOrientationMap_.at(rotation);
332 }
333
ConvertDeviceToDisplayRotation(DeviceRotation deviceRotation)334 Rotation ScreenRotationController::ConvertDeviceToDisplayRotation(DeviceRotation deviceRotation)
335 {
336 if (deviceRotation == DeviceRotation::INVALID) {
337 return GetCurrentDisplayRotation();
338 }
339 if (deviceToDisplayRotationMap_.empty()) {
340 ProcessRotationMapping();
341 }
342 return deviceToDisplayRotationMap_.at(deviceRotation);
343 }
344
ProcessRotationMapping()345 void ScreenRotationController::ProcessRotationMapping()
346 {
347 sptr<SupportedScreenModes> modes =
348 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(defaultDisplayId_);
349
350 // 0 means PORTRAIT, 1 means LANDSCAPE.
351 defaultDeviceRotation_ = (modes == nullptr || modes->width_ < modes->height_) ? 0 : 1;
352
353 if (deviceToDisplayRotationMap_.empty()) {
354 deviceToDisplayRotationMap_ = {
355 {DeviceRotation::ROTATION_PORTRAIT,
356 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
357 {DeviceRotation::ROTATION_LANDSCAPE,
358 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
359 {DeviceRotation::ROTATION_PORTRAIT_INVERTED,
360 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
361 {DeviceRotation::ROTATION_LANDSCAPE_INVERTED,
362 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
363 };
364 }
365 if (displayToDisplayOrientationMap_.empty()) {
366 displayToDisplayOrientationMap_ = {
367 {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
368 DisplayOrientation::PORTRAIT},
369 {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90,
370 DisplayOrientation::LANDSCAPE},
371 {defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
372 DisplayOrientation::PORTRAIT_INVERTED},
373 {defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270,
374 DisplayOrientation::LANDSCAPE_INVERTED},
375 };
376 }
377 if (sensorToDeviceRotationMap_.empty()) {
378 sensorToDeviceRotationMap_ = {
379 {SensorRotation::ROTATION_0, CalcDeviceRotation(SensorRotation::ROTATION_0)},
380 {SensorRotation::ROTATION_90, CalcDeviceRotation(SensorRotation::ROTATION_90)},
381 {SensorRotation::ROTATION_180, CalcDeviceRotation(SensorRotation::ROTATION_180)},
382 {SensorRotation::ROTATION_270, CalcDeviceRotation(SensorRotation::ROTATION_270)},
383 {SensorRotation::INVALID, DeviceRotation::INVALID},
384 };
385 }
386 }
387
IsDeviceRotationVertical(DeviceRotation deviceRotation)388 bool ScreenRotationController::IsDeviceRotationVertical(DeviceRotation deviceRotation)
389 {
390 return (deviceRotation == DeviceRotation::ROTATION_PORTRAIT) ||
391 (deviceRotation == DeviceRotation::ROTATION_PORTRAIT_INVERTED);
392 }
393
IsDeviceRotationHorizontal(DeviceRotation deviceRotation)394 bool ScreenRotationController::IsDeviceRotationHorizontal(DeviceRotation deviceRotation)
395 {
396 return (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE) ||
397 (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE_INVERTED);
398 }
399
IsCurrentDisplayVertical()400 bool ScreenRotationController::IsCurrentDisplayVertical()
401 {
402 return IsDisplayRotationVertical(GetCurrentDisplayRotation());
403 }
404
IsCurrentDisplayHorizontal()405 bool ScreenRotationController::IsCurrentDisplayHorizontal()
406 {
407 return IsDisplayRotationHorizontal(GetCurrentDisplayRotation());
408 }
409
IsDefaultDisplayRotationPortrait()410 bool ScreenRotationController::IsDefaultDisplayRotationPortrait()
411 {
412 return Rotation::ROTATION_0 == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT);
413 }
414
IsDisplayRotationVertical(Rotation rotation)415 bool ScreenRotationController::IsDisplayRotationVertical(Rotation rotation)
416 {
417 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT)) ||
418 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED));
419 }
420
IsDisplayRotationHorizontal(Rotation rotation)421 bool ScreenRotationController::IsDisplayRotationHorizontal(Rotation rotation)
422 {
423 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE)) ||
424 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED));
425 }
426
ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation,bool withAnimation)427 void ScreenRotationController::ProcessSwitchToSensorUnrelatedOrientation(Orientation orientation, bool withAnimation)
428 {
429 if (lastOrientationType_ == orientation) {
430 return;
431 }
432 lastOrientationType_ = orientation;
433 switch (orientation) {
434 case Orientation::UNSPECIFIED: {
435 SetScreenRotation(Rotation::ROTATION_0, withAnimation);
436 break;
437 }
438 case Orientation::VERTICAL: {
439 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT), withAnimation);
440 break;
441 }
442 case Orientation::REVERSE_VERTICAL: {
443 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED),
444 withAnimation);
445 break;
446 }
447 case Orientation::HORIZONTAL: {
448 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE), withAnimation);
449 break;
450 }
451 case Orientation::REVERSE_HORIZONTAL: {
452 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED),
453 withAnimation);
454 break;
455 }
456 default: {
457 return;
458 }
459 }
460 }
461
ProcessOrientationSwitch(Orientation orientation,bool withAnimation)462 void ScreenRotationController::ProcessOrientationSwitch(Orientation orientation, bool withAnimation)
463 {
464 if (!IsSensorRelatedOrientation(orientation)) {
465 ProcessSwitchToSensorUnrelatedOrientation(orientation, withAnimation);
466 } else {
467 ProcessSwitchToSensorRelatedOrientation(orientation, lastSensorRotationConverted_);
468 }
469 }
470 } // Rosen
471 } // OHOS