| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_ |
| #define ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_ |
| |
| #include <unordered_map> |
| |
| #include "ash/accelerometer/accelerometer_reader.h" |
| #include "ash/accelerometer/accelerometer_types.h" |
| #include "ash/ash_export.h" |
| #include "ash/display/display_configuration_controller.h" |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/public/cpp/tablet_mode_observer.h" |
| #include "ash/wm/splitview/split_view_controller.h" |
| #include "ash/wm/splitview/split_view_observer.h" |
| #include "base/observer_list.h" |
| #include "chromeos/ui/base/display_util.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/display/display.h" |
| #include "ui/display/display_observer.h" |
| #include "ui/wm/public/activation_change_observer.h" |
| |
| namespace aura { |
| class Window; |
| } |
| |
| namespace ash { |
| |
| ASH_EXPORT chromeos::OrientationType GetCurrentScreenOrientation(); |
| ASH_EXPORT bool IsCurrentScreenOrientationLandscape(); |
| ASH_EXPORT bool IsCurrentScreenOrientationPrimary(); |
| |
| ASH_EXPORT std::ostream& operator<<(std::ostream& out, |
| const chromeos::OrientationType& lock); |
| |
| // Implements ChromeOS specific functionality for ScreenOrientationProvider. |
| class ASH_EXPORT ScreenOrientationController |
| : public ::wm::ActivationChangeObserver, |
| public aura::WindowObserver, |
| public AccelerometerReader::Observer, |
| public WindowTreeHostManager::Observer, |
| public TabletModeObserver, |
| public SplitViewObserver, |
| public display::DisplayObserver { |
| public: |
| // Observer that reports changes to the state of ScreenOrientationProvider's |
| // rotation lock. |
| class Observer { |
| public: |
| // Invoked when rotation is locked or unlocked by a user. |
| virtual void OnUserRotationLockChanged() {} |
| |
| protected: |
| virtual ~Observer() = default; |
| }; |
| |
| // Controls the behavior after lock is applied to the window (when the window |
| // becomes the active window). |DisableSensor| disables the sensor-based |
| // rotation and locks to the specific orientation. For example, PORTRAIT may |
| // rotate to PORTRAIT_PRIMARY or PORTRAIT_SECONDARY, and will allow rotation |
| // between these two. |DisableSensor| disallows the sensor-based rotation by |
| // locking the rotation to whichever specific orientation is applied. |
| enum class LockCompletionBehavior { |
| None, |
| DisableSensor, |
| }; |
| |
| ScreenOrientationController(); |
| |
| ScreenOrientationController(const ScreenOrientationController&) = delete; |
| ScreenOrientationController& operator=(const ScreenOrientationController&) = |
| delete; |
| |
| ~ScreenOrientationController() override; |
| |
| chromeos::OrientationType natural_orientation() const { |
| return natural_orientation_; |
| } |
| |
| // Add/Remove observers. |
| void AddObserver(Observer* observer); |
| void RemoveObserver(Observer* observer); |
| |
| // Allows/unallows a window to lock the screen orientation. |
| void LockOrientationForWindow(aura::Window* requesting_window, |
| chromeos::OrientationType orientation_lock); |
| |
| void UnlockOrientationForWindow(aura::Window* window); |
| |
| // Unlock all and set the rotation back to the user specified rotation. |
| void UnlockAll(); |
| |
| // Returns true if the user has locked the orientation to portrait, false if |
| // the user has locked the orientation to landscape or not locked the |
| // orientation. |
| bool IsUserLockedOrientationPortrait(); |
| |
| // Returns the chromeos::OrientationType that is applied on based on whether a |
| // rotation lock was requested for an app window, and whether the current |
| // system state allows it to lock the rotation (e.g. being in tablet mode, on |
| // the internal display, and splitview is inactive). |
| chromeos::OrientationType GetCurrentAppRequestedOrientationLock() const; |
| |
| bool ignore_display_configuration_updates() const { |
| return ignore_display_configuration_updates_; |
| } |
| |
| // True if |rotation_lock_| has been set and accelerometer updates should not |
| // rotate the display. |
| bool rotation_locked() const { return rotation_locked_; } |
| |
| bool user_rotation_locked() const { |
| return user_locked_orientation_ != chromeos::OrientationType::kAny; |
| } |
| |
| // Trun on/off the user rotation lock. When turned on, it will lock |
| // the orientation to the current orientation. |
| // |user_rotation_locked()| method returns the current state of the |
| // user rotation lock. |
| void ToggleUserRotationLock(); |
| |
| // Set locked to the given |rotation| and save it. |
| void SetLockToRotation(display::Display::Rotation rotation); |
| |
| // Gets current screen orientation type. |
| chromeos::OrientationType GetCurrentOrientation() const; |
| |
| // Returns true if auto-rotation is allowed. It happens when the device is in |
| // a physical tablet state or kSupportsClamshellAutoRotation is set. |
| bool IsAutoRotationAllowed() const; |
| |
| // wm::ActivationChangeObserver: |
| void OnWindowActivated( |
| ::wm::ActivationChangeObserver::ActivationReason reason, |
| aura::Window* gained_active, |
| aura::Window* lost_active) override; |
| |
| // aura::WindowObserver: |
| void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; |
| void OnWindowDestroying(aura::Window* window) override; |
| void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; |
| |
| // AccelerometerReader::Observer: |
| void OnECLidAngleDriverStatusChanged(bool is_supported) override {} |
| void OnAccelerometerUpdated(const AccelerometerUpdate& update) override; |
| |
| // WindowTreeHostManager::Observer: |
| void OnDisplayConfigurationChanged() override; |
| |
| // TabletModeObserver: |
| void OnTabletModeStarted() override; |
| void OnTabletModeEnded() override; |
| void OnTabletPhysicalStateChanged() override; |
| |
| // SplitViewObserver: |
| void OnSplitViewStateChanged(SplitViewController::State previous_state, |
| SplitViewController::State state) override; |
| |
| // display::DisplayObserver: |
| void OnWillProcessDisplayChanges() override; |
| void OnDidProcessDisplayChanges() override; |
| |
| private: |
| friend class ScreenOrientationControllerTestApi; |
| |
| struct LockInfo { |
| LockInfo(chromeos::OrientationType lock, aura::Window* root) |
| : orientation_lock(lock), root_window(root) {} |
| chromeos::OrientationType orientation_lock = |
| chromeos::OrientationType::kAny; |
| // Tracks the requesting window's root window and is updated whenever it |
| // changes. |
| aura::Window* root_window = nullptr; |
| LockCompletionBehavior lock_completion_behavior = |
| LockCompletionBehavior::None; |
| }; |
| |
| // Sets the display rotation for the given |source|. The new |rotation| will |
| // also become active. Display changed notifications are suppressed for this |
| // change. |
| void SetDisplayRotation( |
| display::Display::Rotation rotation, |
| display::Display::RotationSource source, |
| DisplayConfigurationController::RotationAnimation mode = |
| DisplayConfigurationController::ANIMATION_ASYNC); |
| |
| void SetRotationLockedInternal(bool rotation_locked); |
| |
| // A helper method that set locked to the given |orientation| and save it. |
| void SetLockToOrientation(chromeos::OrientationType orientation); |
| |
| // Sets the display rotation to |rotation|. Future accelerometer updates |
| // should not be used to change the rotation. SetRotationLocked(false) removes |
| // the rotation lock. |
| void LockRotation(display::Display::Rotation rotation, |
| display::Display::RotationSource source); |
| |
| // Sets the display rotation based on |lock_orientation|. Future accelerometer |
| // updates should not be used to change the rotation. SetRotationLocked(false) |
| // removes the rotation lock. |
| void LockRotationToOrientation(chromeos::OrientationType lock_orientation); |
| |
| // For orientations that do not specify primary or secondary, locks to the |
| // current rotation if it matches |lock_orientation|. Otherwise locks to a |
| // matching rotation. |
| void LockToRotationMatchingOrientation( |
| chromeos::OrientationType lock_orientation); |
| |
| // Detect screen rotation from |lid| accelerometer and automatically rotate |
| // screen. |
| void HandleScreenRotation(const AccelerometerReading& lid); |
| |
| // Checks DisplayManager for registered rotation lock, and rotation, |
| // preferences. These are then applied. |
| void LoadDisplayRotationProperties(); |
| |
| // Determines the rotation lock, and orientation, for the top-most window on |
| // the internal display, and applies it. If there is none, rotation lock will |
| // be removed. |
| // TODO(oshima|afakhry): This behavior needs to be revised when Android |
| // implements multi-display support. |
| void ApplyLockForTopMostWindowOnInternalDisplay(); |
| |
| // If there is a rotation lock that can be applied to window, applies it and |
| // returns true. Otherwise returns false. |
| bool ApplyLockForWindowIfPossible(const aura::Window* window); |
| |
| // Both |chromeos::OrientationType::kLandscape| and |
| // |OrientationLock::kPortrait| allow for rotation between the |
| // two angles of the same screen orientation |
| // (http://www.w3.org/TR/screen-orientation/). Returns true if |rotation| is |
| // supported for the current |rotation_locked_orientation_|. |
| bool IsRotationAllowedInLockedState(display::Display::Rotation rotation); |
| |
| // Certain orientation locks allow for rotation between the two angles of the |
| // same screen orientation. Returns true if |rotation_locked_orientation_| |
| // allows rotation. |
| bool CanRotateInLockedState(); |
| |
| void UpdateNaturalOrientationForTest(); |
| |
| // The orientation of the display when at a rotation of 0. |
| chromeos::OrientationType natural_orientation_; |
| |
| // True when changes being applied cause OnDisplayConfigurationChanged() to be |
| // called, and for which these changes should be ignored. |
| bool ignore_display_configuration_updates_; |
| |
| // When true then accelerometer updates should not rotate the display. |
| bool rotation_locked_; |
| |
| // True while the displays are being updated by the display manager, so that |
| // we don't set the display rotation while this operation is in progress. |
| bool suspend_orientation_lock_refreshes_ = false; |
| |
| // True if there was a request to refresh the orientation lock while the |
| // display manager is in the process of updating the displays. When the |
| // display manager is done, we check this value to see if we need to refresh |
| // the orientation lock. |
| bool is_orientation_lock_refresh_pending_ = false; |
| |
| // The orientation to which the current |rotation_locked_| was applied. |
| chromeos::OrientationType rotation_locked_orientation_; |
| |
| // The rotation of the display set by the user. This rotation will be |
| // restored upon exiting tablet mode. |
| display::Display::Rotation user_rotation_; |
| |
| // The orientation of the device locked by the user. |
| chromeos::OrientationType user_locked_orientation_ = |
| chromeos::OrientationType::kAny; |
| |
| // The currently applied orientation lock that was requested by an app if any. |
| absl::optional<chromeos::OrientationType> |
| current_app_requested_orientation_lock_ = absl::nullopt; |
| |
| // The current rotation set by ScreenOrientationController for the internal |
| // display. |
| display::Display::Rotation current_rotation_; |
| |
| // Rotation Lock observers. |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| // Tracks all windows that have requested a lock, as well as the requested |
| // orientation. |
| std::unordered_map<aura::Window*, LockInfo> lock_info_map_; |
| |
| // Register for DisplayObserver callbacks. |
| display::ScopedDisplayObserver display_observer_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_ |