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