// 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. #ifndef ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_ #define ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_ #include #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 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::Unchecked observers_; // Tracks all windows that have requested a lock, as well as the requested // orientation. std::unordered_map lock_info_map_; // Register for DisplayObserver callbacks. display::ScopedDisplayObserver display_observer_{this}; }; } // namespace ash #endif // ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_H_