blob: dd166d354565df3dfdeda94c0cbc78f533996e12 [file] [log] [blame]
// 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 <unordered_map>
#include "ash/ash_export.h"
#include "ash/display/display_configuration_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/public/interfaces/ash_window_manager.mojom.h"
#include "ash/wm/tablet_mode/tablet_mode_observer.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "chromeos/accelerometer/accelerometer_reader.h"
#include "chromeos/accelerometer/accelerometer_types.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display.h"
#include "ui/wm/public/activation_change_observer.h"
namespace aura {
class Window;
namespace ash {
using OrientationLockType = mojom::OrientationLockType;
// Test if the orientation lock type is primary/landscape/portrait.
bool IsPrimaryOrientation(OrientationLockType type);
bool IsLandscapeOrientation(OrientationLockType type);
bool IsPortraitOrientation(OrientationLockType type);
ASH_EXPORT std::ostream& operator<<(std::ostream& out,
const OrientationLockType& lock);
// Implements ChromeOS specific functionality for ScreenOrientationProvider.
class ASH_EXPORT ScreenOrientationController
: public ::wm::ActivationChangeObserver,
public aura::WindowObserver,
public chromeos::AccelerometerReader::Observer,
public WindowTreeHostManager::Observer,
public TabletModeObserver {
// Observer that reports changes to the state of ScreenOrientationProvider's
// rotation lock.
class Observer {
// Invoked when rotation is locked or unlocked by a user.
virtual void OnUserRotationLockChanged() {}
virtual ~Observer() {}
// Controls the behavior after lock is applied to the window (when
// the window becomes 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 rotate between these two.
// |DisableSensor| will lock the orientation to the one of them
// after locked to disalow the sensor basd rotation.
enum class LockCompletionBehavior {
~ScreenOrientationController() override;
OrientationLockType 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,
OrientationLockType orientation_lock);
void UnlockOrientationForWindow(aura::Window* window);
// Unlock all and set the rotation back to the user specified rotation.
void UnlockAll();
bool ScreenOrientationProviderSupported() const;
// 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();
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_ != OrientationLockType::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.
OrientationLockType GetCurrentOrientation() const;
// wm::ActivationChangeObserver:
void OnWindowActivated(
::wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) override;
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
// chromeos::AccelerometerReader::Observer:
void OnAccelerometerUpdated(
scoped_refptr<const chromeos::AccelerometerUpdate> update) override;
// WindowTreeHostManager::Observer:
void OnDisplayConfigurationChanged() override;
// TabletModeObserver:
void OnTabletModeStarted() override;
void OnTabletModeEnding() override;
void OnTabletModeEnded() override;
friend class ScreenOrientationControllerTestApi;
struct LockInfo {
LockInfo() {}
LockInfo(OrientationLockType lock) : orientation_lock(lock) {}
OrientationLockType orientation_lock = OrientationLockType::kAny;
LockCompletionBehavior lock_completion_behavior =
// 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 =
void SetRotationLockedInternal(bool rotation_locked);
// A helper method that set locked to the given |orientation| and save it.
void SetLockToOrientation(OrientationLockType 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(OrientationLockType 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(OrientationLockType lock_orientation);
// Detect screen rotation from |lid| accelerometer and automatically rotate
// screen.
void HandleScreenRotation(const chromeos::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 currently active
// window, and applies it. If there is none, rotation lock will be removed.
void ApplyLockForActiveWindow();
// Both |OrientationLockType::kLandscape| and
// |OrientationLock::kPortrait| allow for rotation between the
// two angles of the same 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.
OrientationLockType 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_;
// The orientation to which the current |rotation_locked_| was applied.
OrientationLockType 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.
OrientationLockType user_locked_orientation_ = OrientationLockType::kAny;
// 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_;
} // namespace ash