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 23namespace OHOS { 24namespace Rosen { 25namespace { 26constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "ScreenRotationController"}; 27} 28 29DisplayId ScreenRotationController::defaultDisplayId_ = 0; 30Rotation ScreenRotationController::currentDisplayRotation_; 31bool ScreenRotationController::isScreenRotationLocked_ = true; 32uint32_t ScreenRotationController::defaultDeviceRotationOffset_ = 0; 33Orientation ScreenRotationController::lastOrientationType_ = Orientation::UNSPECIFIED; 34Rotation ScreenRotationController::lastSensorDecidedRotation_; 35Rotation ScreenRotationController::rotationLockedRotation_; 36uint32_t ScreenRotationController::defaultDeviceRotation_ = 0; 37std::map<SensorRotation, DeviceRotation> ScreenRotationController::sensorToDeviceRotationMap_; 38std::map<DeviceRotation, Rotation> ScreenRotationController::deviceToDisplayRotationMap_; 39std::map<Rotation, DisplayOrientation> ScreenRotationController::displayToDisplayOrientationMap_; 40DeviceRotation ScreenRotationController::lastSensorRotationConverted_ = DeviceRotation::INVALID; 41 42void 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 54bool ScreenRotationController::IsScreenRotationLocked() 55{ 56 return isScreenRotationLocked_; 57} 58 59DMError 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 76void 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 85void 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 107Rotation 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 118Orientation 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 128Rotation 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 167Rotation ScreenRotationController::ProcessAutoRotationPortraitOrientation(DeviceRotation sensorRotationConverted) 168{ 169 if (IsDeviceRotationHorizontal(sensorRotationConverted)) { 170 return currentDisplayRotation_; 171 } 172 lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted); 173 return lastSensorDecidedRotation_; 174} 175 176Rotation ScreenRotationController::ProcessAutoRotationLandscapeOrientation(DeviceRotation sensorRotationConverted) 177{ 178 if (IsDeviceRotationVertical(sensorRotationConverted)) { 179 return currentDisplayRotation_; 180 } 181 lastSensorDecidedRotation_ = ConvertDeviceToDisplayRotation(sensorRotationConverted); 182 return lastSensorDecidedRotation_; 183} 184 185void 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 195DeviceRotation 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 218bool 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 227void 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 271void ScreenRotationController::ProcessSwitchToAutoRotation(DeviceRotation rotation) 272{ 273 if (rotation != DeviceRotation::INVALID) { 274 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation)); 275 } 276} 277 278void ScreenRotationController::ProcessSwitchToAutoRotationPortrait(DeviceRotation rotation) 279{ 280 if (IsDeviceRotationVertical(rotation)) { 281 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation)); 282 return; 283 } 284 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT)); 285} 286 287void ScreenRotationController::ProcessSwitchToAutoRotationLandscape(DeviceRotation rotation) 288{ 289 if (IsDeviceRotationHorizontal(rotation)) { 290 SetScreenRotation(ConvertDeviceToDisplayRotation(rotation)); 291 return; 292 } 293 SetScreenRotation(ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE)); 294} 295 296void 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 308void 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 320DeviceRotation ScreenRotationController::ConvertSensorToDeviceRotation(SensorRotation sensorRotation) 321{ 322 if (sensorToDeviceRotationMap_.empty()) { 323 ProcessRotationMapping(); 324 } 325 return sensorToDeviceRotationMap_.at(sensorRotation); 326} 327 328DisplayOrientation ScreenRotationController::ConvertRotationToDisplayOrientation(Rotation rotation) 329{ 330 if (displayToDisplayOrientationMap_.empty()) { 331 ProcessRotationMapping(); 332 } 333 return displayToDisplayOrientationMap_.at(rotation); 334} 335 336Rotation 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 347void 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 390bool ScreenRotationController::IsDeviceRotationVertical(DeviceRotation deviceRotation) 391{ 392 return (deviceRotation == DeviceRotation::ROTATION_PORTRAIT) || 393 (deviceRotation == DeviceRotation::ROTATION_PORTRAIT_INVERTED); 394} 395 396bool ScreenRotationController::IsDeviceRotationHorizontal(DeviceRotation deviceRotation) 397{ 398 return (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE) || 399 (deviceRotation == DeviceRotation::ROTATION_LANDSCAPE_INVERTED); 400} 401 402bool ScreenRotationController::IsCurrentDisplayVertical() 403{ 404 return IsDisplayRotationVertical(GetCurrentDisplayRotation()); 405} 406 407bool ScreenRotationController::IsCurrentDisplayHorizontal() 408{ 409 return IsDisplayRotationHorizontal(GetCurrentDisplayRotation()); 410} 411 412bool ScreenRotationController::IsDefaultDisplayRotationPortrait() 413{ 414 return Rotation::ROTATION_0 == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT); 415} 416 417bool ScreenRotationController::IsDisplayRotationVertical(Rotation rotation) 418{ 419 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT)) || 420 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_PORTRAIT_INVERTED)); 421} 422 423bool ScreenRotationController::IsDisplayRotationHorizontal(Rotation rotation) 424{ 425 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE)) || 426 (rotation == ConvertDeviceToDisplayRotation(DeviceRotation::ROTATION_LANDSCAPE_INVERTED)); 427} 428 429void 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 464void 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