| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/display/screen_orientation_controller.h" |
| |
| #include "ash/accelerometer/accelerometer_reader.h" |
| #include "ash/accelerometer/accelerometer_types.h" |
| #include "ash/public/cpp/app_types.h" |
| #include "ash/public/cpp/ash_switches.h" |
| #include "ash/shell.h" |
| #include "ash/wm/mru_window_tracker.h" |
| #include "ash/wm/tablet_mode/tablet_mode_controller.h" |
| #include "ash/wm/window_state.h" |
| #include "base/auto_reset.h" |
| #include "base/command_line.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/display/display.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/manager/managed_display_info.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/wm/public/activation_client.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // The angle which the screen has to be rotated past before the display will |
| // rotate to match it (i.e. 45.0f is no stickiness). |
| const float kDisplayRotationStickyAngleDegrees = 60.0f; |
| |
| // The minimum acceleration in m/s^2 in a direction required to trigger screen |
| // rotation. This prevents rapid toggling of rotation when the device is near |
| // flat and there is very little screen aligned force on it. The value is |
| // effectively the sine of the rise angle required times the acceleration due |
| // to gravity, with the current value requiring at least a 25 degree rise. |
| const float kMinimumAccelerationScreenRotation = 4.2f; |
| |
| OrientationLockType GetDisplayNaturalOrientation() { |
| if (!display::Display::HasInternalDisplay()) |
| return OrientationLockType::kLandscape; |
| |
| display::ManagedDisplayInfo info = |
| Shell::Get()->display_manager()->GetDisplayInfo( |
| display::Display::InternalDisplayId()); |
| gfx::Size size = info.bounds_in_native().size(); |
| return size.width() > size.height() ? OrientationLockType::kLandscape |
| : OrientationLockType::kPortrait; |
| } |
| |
| OrientationLockType RotationToOrientation(OrientationLockType natural, |
| display::Display::Rotation rotation) { |
| if (natural == OrientationLockType::kLandscape) { |
| // To be consistent with Android, the rgotation of the primary portrait |
| // on naturally landscape device is 270. |
| switch (rotation) { |
| case display::Display::ROTATE_0: |
| return OrientationLockType::kLandscapePrimary; |
| case display::Display::ROTATE_90: |
| return OrientationLockType::kPortraitSecondary; |
| case display::Display::ROTATE_180: |
| return OrientationLockType::kLandscapeSecondary; |
| case display::Display::ROTATE_270: |
| return OrientationLockType::kPortraitPrimary; |
| } |
| } else { // Natural portrait |
| switch (rotation) { |
| case display::Display::ROTATE_0: |
| return OrientationLockType::kPortraitPrimary; |
| case display::Display::ROTATE_90: |
| return OrientationLockType::kLandscapePrimary; |
| case display::Display::ROTATE_180: |
| return OrientationLockType::kPortraitSecondary; |
| case display::Display::ROTATE_270: |
| return OrientationLockType::kLandscapeSecondary; |
| } |
| } |
| NOTREACHED(); |
| return OrientationLockType::kAny; |
| } |
| |
| // Returns the rotation that matches the orientation type. |
| // Returns ROTATE_0 if the given orientation is ANY, which is used |
| // to indicate that user didn't lock orientation. |
| display::Display::Rotation OrientationToRotation( |
| OrientationLockType natural, |
| OrientationLockType orientation) { |
| if (orientation == OrientationLockType::kAny) |
| return display::Display::ROTATE_0; |
| |
| if (natural == OrientationLockType::kLandscape) { |
| // To be consistent with Android, the rotation of the primary portrait |
| // on naturally landscape device is 270. |
| switch (orientation) { |
| case OrientationLockType::kLandscapePrimary: |
| return display::Display::ROTATE_0; |
| case OrientationLockType::kPortraitPrimary: |
| return display::Display::ROTATE_270; |
| case OrientationLockType::kLandscapeSecondary: |
| return display::Display::ROTATE_180; |
| case OrientationLockType::kPortraitSecondary: |
| return display::Display::ROTATE_90; |
| default: |
| break; |
| } |
| } else { // Natural portrait |
| switch (orientation) { |
| case OrientationLockType::kPortraitPrimary: |
| return display::Display::ROTATE_0; |
| case OrientationLockType::kLandscapePrimary: |
| return display::Display::ROTATE_90; |
| case OrientationLockType::kPortraitSecondary: |
| return display::Display::ROTATE_180; |
| case OrientationLockType::kLandscapeSecondary: |
| return display::Display::ROTATE_270; |
| default: |
| break; |
| } |
| } |
| NOTREACHED() << static_cast<int>(orientation); |
| return display::Display::ROTATE_0; |
| } |
| |
| // Returns the locked orientation that matches the application |
| // requested orientation, or the application orientation itself |
| // if it didn't match. |
| OrientationLockType ResolveOrientationLock(OrientationLockType app_requested, |
| OrientationLockType lock) { |
| if (app_requested == OrientationLockType::kAny || |
| (app_requested == OrientationLockType::kLandscape && |
| (lock == OrientationLockType::kLandscapePrimary || |
| lock == OrientationLockType::kLandscapeSecondary)) || |
| (app_requested == OrientationLockType::kPortrait && |
| (lock == OrientationLockType::kPortraitPrimary || |
| lock == OrientationLockType::kPortraitSecondary))) { |
| return lock; |
| } |
| return app_requested; |
| } |
| |
| } // namespace |
| |
| bool IsPrimaryOrientation(OrientationLockType type) { |
| return type == OrientationLockType::kLandscapePrimary || |
| type == OrientationLockType::kPortraitPrimary; |
| } |
| |
| bool IsLandscapeOrientation(OrientationLockType type) { |
| return type == OrientationLockType::kLandscape || |
| type == OrientationLockType::kLandscapePrimary || |
| type == OrientationLockType::kLandscapeSecondary; |
| } |
| |
| bool IsPortraitOrientation(OrientationLockType type) { |
| return type == OrientationLockType::kPortrait || |
| type == OrientationLockType::kPortraitPrimary || |
| type == OrientationLockType::kPortraitSecondary; |
| } |
| |
| OrientationLockType GetCurrentScreenOrientation() { |
| // ScreenOrientationController might be nullptr during shutdown. |
| // TODO(xdai|sammiequon): See if we can reorder so that users of the function |
| // (split_view_controller) get shutddown before screen orientation controller. |
| if (!Shell::Get()->screen_orientation_controller()) |
| return OrientationLockType::kAny; |
| return Shell::Get()->screen_orientation_controller()->GetCurrentOrientation(); |
| } |
| |
| bool IsCurrentScreenOrientationLandscape() { |
| return IsLandscapeOrientation(GetCurrentScreenOrientation()); |
| } |
| |
| bool IsCurrentScreenOrientationPrimary() { |
| return IsPrimaryOrientation(GetCurrentScreenOrientation()); |
| } |
| |
| std::ostream& operator<<(std::ostream& out, const OrientationLockType& lock) { |
| switch (lock) { |
| case OrientationLockType::kAny: |
| out << "any"; |
| break; |
| case OrientationLockType::kNatural: |
| out << "natural"; |
| break; |
| case OrientationLockType::kCurrent: |
| out << "current"; |
| break; |
| case OrientationLockType::kPortrait: |
| out << "portrait"; |
| break; |
| case OrientationLockType::kLandscape: |
| out << "landscape"; |
| break; |
| case OrientationLockType::kPortraitPrimary: |
| out << "portrait-primary"; |
| break; |
| case OrientationLockType::kPortraitSecondary: |
| out << "portrait-secondary"; |
| break; |
| case OrientationLockType::kLandscapePrimary: |
| out << "landscape-primary"; |
| break; |
| case OrientationLockType::kLandscapeSecondary: |
| out << "landscape-secondary"; |
| break; |
| } |
| return out; |
| } |
| |
| ScreenOrientationController::ScreenOrientationController() |
| : natural_orientation_(GetDisplayNaturalOrientation()), |
| ignore_display_configuration_updates_(false), |
| rotation_locked_(false), |
| rotation_locked_orientation_(OrientationLockType::kAny), |
| user_rotation_(display::Display::ROTATE_0), |
| current_rotation_(display::Display::ROTATE_0) { |
| Shell::Get()->tablet_mode_controller()->AddObserver(this); |
| } |
| |
| ScreenOrientationController::~ScreenOrientationController() { |
| Shell::Get()->tablet_mode_controller()->RemoveObserver(this); |
| AccelerometerReader::GetInstance()->RemoveObserver(this); |
| Shell::Get()->window_tree_host_manager()->RemoveObserver(this); |
| Shell::Get()->activation_client()->RemoveObserver(this); |
| for (auto& windows : lock_info_map_) |
| windows.first->RemoveObserver(this); |
| } |
| |
| void ScreenOrientationController::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void ScreenOrientationController::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void ScreenOrientationController::LockOrientationForWindow( |
| aura::Window* requesting_window, |
| OrientationLockType orientation_lock) { |
| if (!requesting_window->HasObserver(this)) |
| requesting_window->AddObserver(this); |
| auto iter = lock_info_map_.find(requesting_window); |
| if (iter != lock_info_map_.end()) { |
| if (orientation_lock == OrientationLockType::kCurrent) { |
| // If the app previously requested an orientation, |
| // disable the sensor when that orientation is locked. |
| iter->second.lock_completion_behavior = |
| LockCompletionBehavior::DisableSensor; |
| } else { |
| iter->second.orientation_lock = orientation_lock; |
| iter->second.lock_completion_behavior = LockCompletionBehavior::None; |
| } |
| } else { |
| lock_info_map_.emplace(requesting_window, LockInfo(orientation_lock)); |
| } |
| |
| ApplyLockForActiveWindow(); |
| } |
| |
| void ScreenOrientationController::UnlockOrientationForWindow( |
| aura::Window* window) { |
| lock_info_map_.erase(window); |
| window->RemoveObserver(this); |
| ApplyLockForActiveWindow(); |
| } |
| |
| void ScreenOrientationController::UnlockAll() { |
| SetRotationLockedInternal(false); |
| if (user_rotation_ != current_rotation_) { |
| SetDisplayRotation(user_rotation_, |
| display::Display::RotationSource::ACCELEROMETER, |
| DisplayConfigurationController::ANIMATION_SYNC); |
| } |
| } |
| |
| bool ScreenOrientationController::ScreenOrientationProviderSupported() const { |
| return Shell::Get() |
| ->tablet_mode_controller() |
| ->IsTabletModeWindowManagerEnabled(); |
| } |
| |
| bool ScreenOrientationController::IsUserLockedOrientationPortrait() { |
| switch (user_locked_orientation_) { |
| case OrientationLockType::kPortraitPrimary: |
| case OrientationLockType::kPortraitSecondary: |
| case OrientationLockType::kPortrait: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| void ScreenOrientationController::ToggleUserRotationLock() { |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| |
| if (user_rotation_locked()) { |
| SetLockToOrientation(OrientationLockType::kAny); |
| } else { |
| display::Display::Rotation current_rotation = |
| Shell::Get() |
| ->display_manager() |
| ->GetDisplayInfo(display::Display::InternalDisplayId()) |
| .GetActiveRotation(); |
| SetLockToRotation(current_rotation); |
| } |
| } |
| |
| void ScreenOrientationController::SetLockToRotation( |
| display::Display::Rotation rotation) { |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| |
| SetLockToOrientation(RotationToOrientation(natural_orientation_, rotation)); |
| } |
| |
| OrientationLockType ScreenOrientationController::GetCurrentOrientation() const { |
| return RotationToOrientation(natural_orientation_, current_rotation_); |
| } |
| |
| void ScreenOrientationController::OnWindowActivated( |
| ::wm::ActivationChangeObserver::ActivationReason reason, |
| aura::Window* gained_active, |
| aura::Window* lost_active) { |
| ApplyLockForActiveWindow(); |
| } |
| |
| void ScreenOrientationController::OnWindowDestroying(aura::Window* window) { |
| UnlockOrientationForWindow(window); |
| } |
| |
| // Currently contents::WebContents will only be able to lock rotation while |
| // fullscreen. In this state a user cannot click on the tab strip to change. If |
| // this becomes supported for non-fullscreen tabs then the following interferes |
| // with TabDragController. OnWindowVisibilityChanged is called between a mouse |
| // down and mouse up. The rotation this triggers leads to a coordinate space |
| // change in the middle of an event. Causes the tab to separate from the tab |
| // strip. |
| void ScreenOrientationController::OnWindowVisibilityChanged( |
| aura::Window* window, |
| bool visible) { |
| if (lock_info_map_.find(window) == lock_info_map_.end()) |
| return; |
| ApplyLockForActiveWindow(); |
| } |
| |
| void ScreenOrientationController::OnAccelerometerUpdated( |
| scoped_refptr<const AccelerometerUpdate> update) { |
| if (rotation_locked_ && !CanRotateInLockedState()) |
| return; |
| if (!update->has(ACCELEROMETER_SOURCE_SCREEN)) |
| return; |
| // Ignore the reading if it appears unstable. The reading is considered |
| // unstable if it deviates too much from gravity |
| if (update->IsReadingStable(ACCELEROMETER_SOURCE_SCREEN)) |
| HandleScreenRotation(update->get(ACCELEROMETER_SOURCE_SCREEN)); |
| } |
| |
| void ScreenOrientationController::OnDisplayConfigurationChanged() { |
| if (ignore_display_configuration_updates_) |
| return; |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| if (!Shell::Get()->display_manager()->IsActiveDisplayId( |
| display::Display::InternalDisplayId())) { |
| return; |
| } |
| // TODO(oshima): remove current_rotation_ and always use the target rotation. |
| current_rotation_ = |
| Shell::Get()->display_configuration_controller()->GetTargetRotation( |
| display::Display::InternalDisplayId()); |
| } |
| |
| void ScreenOrientationController::OnTabletModeStarted() { |
| Shell* shell = Shell::Get(); |
| // Do not exit early, as the internal display can be determined after Maximize |
| // Mode has started. (chrome-os-partner:38796) |
| // Always start observing. |
| if (display::Display::HasInternalDisplay()) { |
| current_rotation_ = user_rotation_ = |
| shell->display_configuration_controller()->GetTargetRotation( |
| display::Display::InternalDisplayId()); |
| } |
| if (!rotation_locked_) |
| LoadDisplayRotationProperties(); |
| AccelerometerReader::GetInstance()->AddObserver(this); |
| shell->window_tree_host_manager()->AddObserver(this); |
| Shell::Get()->activation_client()->AddObserver(this); |
| |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| ApplyLockForActiveWindow(); |
| for (auto& observer : observers_) |
| observer.OnUserRotationLockChanged(); |
| } |
| |
| void ScreenOrientationController::OnTabletModeEnding() { |
| AccelerometerReader::GetInstance()->RemoveObserver(this); |
| Shell::Get()->window_tree_host_manager()->RemoveObserver(this); |
| Shell::Get()->activation_client()->RemoveObserver(this); |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| |
| // TODO(oshima): Remove if when current_rotation_ is removed. |
| if (current_rotation_ != user_rotation_) { |
| SetDisplayRotation(user_rotation_, |
| display::Display::RotationSource::ACCELEROMETER, |
| DisplayConfigurationController::ANIMATION_SYNC); |
| } |
| for (auto& observer : observers_) |
| observer.OnUserRotationLockChanged(); |
| } |
| |
| void ScreenOrientationController::OnTabletModeEnded() { |
| UnlockAll(); |
| } |
| |
| void ScreenOrientationController::SetDisplayRotation( |
| display::Display::Rotation rotation, |
| display::Display::RotationSource source, |
| DisplayConfigurationController::RotationAnimation mode) { |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| current_rotation_ = rotation; |
| base::AutoReset<bool> auto_ignore_display_configuration_updates( |
| &ignore_display_configuration_updates_, true); |
| |
| Shell::Get()->display_configuration_controller()->SetDisplayRotation( |
| display::Display::InternalDisplayId(), rotation, source, mode); |
| } |
| |
| void ScreenOrientationController::SetRotationLockedInternal( |
| bool rotation_locked) { |
| if (rotation_locked_ == rotation_locked) |
| return; |
| rotation_locked_ = rotation_locked; |
| if (!rotation_locked_) |
| rotation_locked_orientation_ = OrientationLockType::kAny; |
| } |
| |
| void ScreenOrientationController::SetLockToOrientation( |
| OrientationLockType orientation) { |
| user_locked_orientation_ = orientation; |
| base::AutoReset<bool> auto_ignore_display_configuration_updates( |
| &ignore_display_configuration_updates_, true); |
| Shell::Get()->display_manager()->RegisterDisplayRotationProperties( |
| user_rotation_locked(), |
| OrientationToRotation(natural_orientation_, user_locked_orientation_)); |
| |
| ApplyLockForActiveWindow(); |
| for (auto& observer : observers_) |
| observer.OnUserRotationLockChanged(); |
| } |
| |
| void ScreenOrientationController::LockRotation( |
| display::Display::Rotation rotation, |
| display::Display::RotationSource source) { |
| SetRotationLockedInternal(true); |
| SetDisplayRotation(rotation, source); |
| } |
| |
| void ScreenOrientationController::LockRotationToOrientation( |
| OrientationLockType lock_orientation) { |
| rotation_locked_orientation_ = lock_orientation; |
| switch (lock_orientation) { |
| case OrientationLockType::kAny: |
| SetRotationLockedInternal(false); |
| break; |
| case OrientationLockType::kLandscape: |
| case OrientationLockType::kPortrait: |
| LockToRotationMatchingOrientation(lock_orientation); |
| break; |
| |
| case OrientationLockType::kLandscapePrimary: |
| case OrientationLockType::kLandscapeSecondary: |
| case OrientationLockType::kPortraitPrimary: |
| case OrientationLockType::kPortraitSecondary: |
| LockRotation( |
| OrientationToRotation(natural_orientation_, lock_orientation), |
| display::Display::RotationSource::ACTIVE); |
| |
| break; |
| case OrientationLockType::kNatural: |
| LockRotation(display::Display::ROTATE_0, |
| display::Display::RotationSource::ACTIVE); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void ScreenOrientationController::LockToRotationMatchingOrientation( |
| OrientationLockType lock_orientation) { |
| if (!display::Display::HasInternalDisplay()) |
| return; |
| |
| display::Display::Rotation rotation = |
| Shell::Get() |
| ->display_manager() |
| ->GetDisplayInfo(display::Display::InternalDisplayId()) |
| .GetActiveRotation(); |
| if (natural_orientation_ == lock_orientation) { |
| if (rotation == display::Display::ROTATE_0 || |
| rotation == display::Display::ROTATE_180) { |
| SetRotationLockedInternal(true); |
| } else { |
| LockRotation(display::Display::ROTATE_0, |
| display::Display::RotationSource::ACTIVE); |
| } |
| } else { |
| if (rotation == display::Display::ROTATE_90 || |
| rotation == display::Display::ROTATE_270) { |
| SetRotationLockedInternal(true); |
| } else { |
| // Rotate to the default rotation of the requested orientation. |
| display::Display::Rotation default_rotation = |
| natural_orientation_ == OrientationLockType::kLandscape |
| ? display::Display::ROTATE_270 // portrait in landscape device. |
| : display::Display::ROTATE_90; // landscape in portrait device. |
| LockRotation(default_rotation, display::Display::RotationSource::ACTIVE); |
| } |
| } |
| } |
| |
| void ScreenOrientationController::HandleScreenRotation( |
| const AccelerometerReading& lid) { |
| gfx::Vector3dF lid_flattened(lid.x, lid.y, 0.0f); |
| float lid_flattened_length = lid_flattened.Length(); |
| // When the lid is close to being flat, don't change rotation as it is too |
| // sensitive to slight movements. |
| if (lid_flattened_length < kMinimumAccelerationScreenRotation) |
| return; |
| |
| // The reference vector is the angle of gravity when the device is rotated |
| // clockwise by 45 degrees. Computing the angle between this vector and |
| // gravity we can easily determine the expected display rotation. |
| static const gfx::Vector3dF rotation_reference(-1.0f, 1.0f, 0.0f); |
| |
| // Set the down vector to match the expected direction of gravity given the |
| // last configured rotation. This is used to enforce a stickiness that the |
| // user must overcome to rotate the display and prevents frequent rotations |
| // when holding the device near 45 degrees. |
| gfx::Vector3dF down(0.0f, 0.0f, 0.0f); |
| if (current_rotation_ == display::Display::ROTATE_0) |
| down.set_y(1.0f); |
| else if (current_rotation_ == display::Display::ROTATE_90) |
| down.set_x(1.0f); |
| else if (current_rotation_ == display::Display::ROTATE_180) |
| down.set_y(-1.0f); |
| else |
| down.set_x(-1.0f); |
| |
| // Don't rotate if the screen has not passed the threshold. |
| if (gfx::AngleBetweenVectorsInDegrees(down, lid_flattened) < |
| kDisplayRotationStickyAngleDegrees) { |
| return; |
| } |
| |
| float angle = gfx::ClockwiseAngleBetweenVectorsInDegrees( |
| rotation_reference, lid_flattened, gfx::Vector3dF(0.0f, 0.0f, 1.0f)); |
| |
| display::Display::Rotation new_rotation = display::Display::ROTATE_270; |
| if (angle < 90.0f) |
| new_rotation = display::Display::ROTATE_0; |
| else if (angle < 180.0f) |
| new_rotation = display::Display::ROTATE_90; |
| else if (angle < 270.0f) |
| new_rotation = display::Display::ROTATE_180; |
| |
| if (new_rotation != current_rotation_ && |
| IsRotationAllowedInLockedState(new_rotation)) { |
| SetDisplayRotation(new_rotation, |
| display::Display::RotationSource::ACCELEROMETER); |
| } |
| } |
| |
| void ScreenOrientationController::LoadDisplayRotationProperties() { |
| display::DisplayManager* display_manager = Shell::Get()->display_manager(); |
| if (!display_manager->registered_internal_display_rotation_lock()) |
| return; |
| user_locked_orientation_ = RotationToOrientation( |
| natural_orientation_, |
| display_manager->registered_internal_display_rotation()); |
| } |
| |
| void ScreenOrientationController::ApplyLockForActiveWindow() { |
| if (!ScreenOrientationProviderSupported()) |
| return; |
| |
| MruWindowTracker::WindowList mru_windows( |
| Shell::Get()->mru_window_tracker()->BuildMruWindowList()); |
| |
| for (auto* window : mru_windows) { |
| if (!window->TargetVisibility()) |
| continue; |
| for (auto& pair : lock_info_map_) { |
| if (pair.first->TargetVisibility() && window->Contains(pair.first)) { |
| if (pair.second.orientation_lock == OrientationLockType::kCurrent) { |
| // If the app requested "current" without previously |
| // specifying an orientation, use the current rotation. |
| pair.second.orientation_lock = |
| RotationToOrientation(natural_orientation_, current_rotation_); |
| LockRotationToOrientation(pair.second.orientation_lock); |
| } else { |
| const auto orientation_lock = ResolveOrientationLock( |
| pair.second.orientation_lock, user_locked_orientation_); |
| LockRotationToOrientation(orientation_lock); |
| if (pair.second.lock_completion_behavior == |
| LockCompletionBehavior::DisableSensor) { |
| pair.second.lock_completion_behavior = LockCompletionBehavior::None; |
| pair.second.orientation_lock = orientation_lock; |
| } |
| } |
| return; |
| } |
| } |
| // The default orientation for all chrome browser/apps windows is |
| // ANY, so use the user_locked_orientation_; |
| if (window->TargetVisibility() && |
| static_cast<AppType>(window->GetProperty(aura::client::kAppType)) != |
| AppType::OTHERS) { |
| LockRotationToOrientation(user_locked_orientation_); |
| return; |
| } |
| } |
| LockRotationToOrientation(user_locked_orientation_); |
| } |
| |
| bool ScreenOrientationController::IsRotationAllowedInLockedState( |
| display::Display::Rotation rotation) { |
| if (!rotation_locked_) |
| return true; |
| |
| if (!CanRotateInLockedState()) |
| return false; |
| |
| if (natural_orientation_ == rotation_locked_orientation_) { |
| return rotation == display::Display::ROTATE_0 || |
| rotation == display::Display::ROTATE_180; |
| } else { |
| return rotation == display::Display::ROTATE_90 || |
| rotation == display::Display::ROTATE_270; |
| } |
| return false; |
| } |
| |
| bool ScreenOrientationController::CanRotateInLockedState() { |
| return rotation_locked_orientation_ == OrientationLockType::kLandscape || |
| rotation_locked_orientation_ == OrientationLockType::kPortrait; |
| } |
| |
| void ScreenOrientationController::UpdateNaturalOrientationForTest() { |
| natural_orientation_ = GetDisplayNaturalOrientation(); |
| } |
| |
| } // namespace ash |