Commit 1b830e9c authored by jonross@chromium.org's avatar jonross@chromium.org

Lock Rotation on user settings changes

While in MaximizeMode if the rotation of the internal display is changed by a source other than MaximizeModeController rotation lock will be set. Thereby blocking future accelerometer rotations until the user toggles the lock.

The rotation lock tray will listen for these changes and update its visuals.

TEST=MaximizeModeControllerTest
BUG=371426, 369505

Review URL: https://codereview.chromium.org/303723003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276699 0039d316-1c4b-4281-b951-d872f2087c98
parent 6cd63bac
...@@ -56,16 +56,9 @@ RotationLockDefaultView::~RotationLockDefaultView() { ...@@ -56,16 +56,9 @@ RotationLockDefaultView::~RotationLockDefaultView() {
bool RotationLockDefaultView::PerformAction(const ui::Event& event) { bool RotationLockDefaultView::PerformAction(const ui::Event& event) {
MaximizeModeController* maximize_mode_controller = Shell::GetInstance()-> MaximizeModeController* maximize_mode_controller = Shell::GetInstance()->
maximize_mode_controller(); maximize_mode_controller();
bool rotation_locked = !maximize_mode_controller->rotation_locked(); maximize_mode_controller->SetRotationLocked(
maximize_mode_controller->set_rotation_locked(rotation_locked); !maximize_mode_controller->rotation_locked());
UpdateImage(); UpdateImage();
// RotationLockDefaultView can only be created by a TrayRotationLock. The
// owner needs to be told of the action so that it can update its visibility.
static_cast<TrayRotationLock*>(owner())->tray_view()->
SetVisible(rotation_locked);
return true; return true;
} }
...@@ -116,6 +109,10 @@ TrayRotationLock::~TrayRotationLock() { ...@@ -116,6 +109,10 @@ TrayRotationLock::~TrayRotationLock() {
Shell::GetInstance()->RemoveShellObserver(this); Shell::GetInstance()->RemoveShellObserver(this);
} }
void TrayRotationLock::OnRotationLockChanged(bool rotation_locked) {
tray_view()->SetVisible(ShouldBeVisible());
}
views::View* TrayRotationLock::CreateDefaultView(user::LoginStatus status) { views::View* TrayRotationLock::CreateDefaultView(user::LoginStatus status) {
if (on_primary_display_) if (on_primary_display_)
return new tray::RotationLockDefaultView(this); return new tray::RotationLockDefaultView(this);
...@@ -125,13 +122,19 @@ views::View* TrayRotationLock::CreateDefaultView(user::LoginStatus status) { ...@@ -125,13 +122,19 @@ views::View* TrayRotationLock::CreateDefaultView(user::LoginStatus status) {
void TrayRotationLock::OnMaximizeModeStarted() { void TrayRotationLock::OnMaximizeModeStarted() {
tray_view()->SetVisible( tray_view()->SetVisible(
Shell::GetInstance()->maximize_mode_controller()->rotation_locked()); Shell::GetInstance()->maximize_mode_controller()->rotation_locked());
Shell::GetInstance()->maximize_mode_controller()->AddObserver(this);
} }
void TrayRotationLock::OnMaximizeModeEnded() { void TrayRotationLock::OnMaximizeModeEnded() {
tray_view()->SetVisible(false); tray_view()->SetVisible(false);
Shell::GetInstance()->maximize_mode_controller()->RemoveObserver(this);
} }
bool TrayRotationLock::GetInitialVisibility() { bool TrayRotationLock::GetInitialVisibility() {
return ShouldBeVisible();
}
bool TrayRotationLock::ShouldBeVisible() {
MaximizeModeController* controller = Shell::GetInstance()-> MaximizeModeController* controller = Shell::GetInstance()->
maximize_mode_controller(); maximize_mode_controller();
return on_primary_display_ && return on_primary_display_ &&
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "ash/shell_observer.h" #include "ash/shell_observer.h"
#include "ash/system/tray/tray_image_item.h" #include "ash/system/tray/tray_image_item.h"
#include "ash/wm/maximize_mode/maximize_mode_controller.h"
namespace ash { namespace ash {
...@@ -20,11 +21,15 @@ class RotationLockDefaultView; ...@@ -20,11 +21,15 @@ class RotationLockDefaultView;
// be interacted with, it toggles the state of the rotation lock. // be interacted with, it toggles the state of the rotation lock.
// TrayRotationLock is only available on the primary display. // TrayRotationLock is only available on the primary display.
class ASH_EXPORT TrayRotationLock : public TrayImageItem, class ASH_EXPORT TrayRotationLock : public TrayImageItem,
public MaximizeModeController::Observer,
public ShellObserver { public ShellObserver {
public: public:
explicit TrayRotationLock(SystemTray* system_tray); explicit TrayRotationLock(SystemTray* system_tray);
virtual ~TrayRotationLock(); virtual ~TrayRotationLock();
// MaximizeModeController::Observer:
virtual void OnRotationLockChanged(bool rotation_locked) OVERRIDE;
// SystemTrayItem: // SystemTrayItem:
virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE; virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
...@@ -39,6 +44,10 @@ class ASH_EXPORT TrayRotationLock : public TrayImageItem, ...@@ -39,6 +44,10 @@ class ASH_EXPORT TrayRotationLock : public TrayImageItem,
private: private:
friend class TrayRotationLockTest; friend class TrayRotationLockTest;
// True if |on_primary_display_|, maximize mode is enabled, and rotation is
// locked.
bool ShouldBeVisible();
// True if this has been created by a SystemTray on the primary display. // True if this has been created by a SystemTray on the primary display.
bool on_primary_display_; bool on_primary_display_;
......
...@@ -118,21 +118,21 @@ TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeModeAndRotationLock) { ...@@ -118,21 +118,21 @@ TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeModeAndRotationLock) {
TearDownViews(); TearDownViews();
Shell::GetInstance()->maximize_mode_controller()-> Shell::GetInstance()->maximize_mode_controller()->
EnableMaximizeModeWindowManager(true); EnableMaximizeModeWindowManager(true);
Shell::GetInstance()-> maximize_mode_controller()->set_rotation_locked(true); Shell::GetInstance()-> maximize_mode_controller()->SetRotationLocked(true);
SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget());
EXPECT_TRUE(tray_view()->visible()); EXPECT_TRUE(tray_view()->visible());
Shell::GetInstance()->maximize_mode_controller()-> Shell::GetInstance()->maximize_mode_controller()->
EnableMaximizeModeWindowManager(false); EnableMaximizeModeWindowManager(false);
EXPECT_FALSE(tray_view()->visible());
} }
// Tests that the enabling of MaximizeMode affects a previously created tray // Tests that the enabling of MaximizeMode affects a previously created tray
// view, changing the visibility. // view, changing the visibility.
TEST_F(TrayRotationLockTest, TrayViewVisibilityChangesDuringMaximizeMode) { TEST_F(TrayRotationLockTest, TrayViewVisibilityChangesDuringMaximizeMode) {
TearDownViews(); ASSERT_FALSE(tray_view()->visible());
Shell::GetInstance()->maximize_mode_controller()-> Shell::GetInstance()->maximize_mode_controller()->
EnableMaximizeModeWindowManager(true); EnableMaximizeModeWindowManager(true);
Shell::GetInstance()-> maximize_mode_controller()->set_rotation_locked(true); Shell::GetInstance()->maximize_mode_controller()->SetRotationLocked(true);
SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget());
EXPECT_TRUE(tray_view()->visible()); EXPECT_TRUE(tray_view()->visible());
Shell::GetInstance()->maximize_mode_controller()-> Shell::GetInstance()->maximize_mode_controller()->
EnableMaximizeModeWindowManager(false); EnableMaximizeModeWindowManager(false);
......
...@@ -146,6 +146,22 @@ MaximizeModeController::~MaximizeModeController() { ...@@ -146,6 +146,22 @@ MaximizeModeController::~MaximizeModeController() {
Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this); Shell::GetInstance()->accelerometer_controller()->RemoveObserver(this);
} }
void MaximizeModeController::SetRotationLocked(bool rotation_locked) {
if (rotation_locked_ == rotation_locked)
return;
rotation_locked_ = rotation_locked;
FOR_EACH_OBSERVER(Observer, observers_,
OnRotationLockChanged(rotation_locked_));
}
void MaximizeModeController::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void MaximizeModeController::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool MaximizeModeController::CanEnterMaximizeMode() { bool MaximizeModeController::CanEnterMaximizeMode() {
// If we have ever seen accelerometer data, then HandleHingeRotation may // If we have ever seen accelerometer data, then HandleHingeRotation may
// trigger maximize mode at some point in the future. // trigger maximize mode at some point in the future.
...@@ -199,6 +215,22 @@ void MaximizeModeController::OnAccelerometerUpdated( ...@@ -199,6 +215,22 @@ void MaximizeModeController::OnAccelerometerUpdated(
HandleScreenRotation(lid); HandleScreenRotation(lid);
} }
void MaximizeModeController::OnDisplayConfigurationChanged() {
if (in_set_screen_rotation_)
return;
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::Rotation user_rotation = display_manager->
GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
if (user_rotation != current_rotation_) {
// A user may change other display configuration settings. When the user
// does change the rotation setting, then lock rotation to prevent the
// accelerometer from erasing their change.
SetRotationLocked(true);
user_rotation_ = user_rotation;
current_rotation_ = user_rotation;
}
}
void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base, void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) { const gfx::Vector3dF& lid) {
static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f); static const gfx::Vector3dF hinge_vector(0.0f, 1.0f, 0.0f);
...@@ -239,6 +271,9 @@ void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base, ...@@ -239,6 +271,9 @@ void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) { void MaximizeModeController::HandleScreenRotation(const gfx::Vector3dF& lid) {
bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled(); bool maximize_mode_engaged = IsMaximizeModeWindowManagerEnabled();
// TODO(jonross): track the updated rotation angle even when locked. So that
// when rotation lock is removed the accelerometer rotation can be applied
// without waiting for the next update.
if (!maximize_mode_engaged || rotation_locked_) if (!maximize_mode_engaged || rotation_locked_)
return; return;
...@@ -301,35 +336,34 @@ void MaximizeModeController::SetDisplayRotation( ...@@ -301,35 +336,34 @@ void MaximizeModeController::SetDisplayRotation(
gfx::Display::Rotation rotation) { gfx::Display::Rotation rotation) {
base::AutoReset<bool> auto_in_set_screen_rotation( base::AutoReset<bool> auto_in_set_screen_rotation(
&in_set_screen_rotation_, true); &in_set_screen_rotation_, true);
current_rotation_ = rotation;
display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
rotation); rotation);
} }
void MaximizeModeController::EnterMaximizeMode() { void MaximizeModeController::EnterMaximizeMode() {
// TODO(jonross): Listen for display configuration changes. If the user
// causes a rotation change a rotation lock should be applied.
// https://crbug.com/369505
DisplayManager* display_manager = Shell::GetInstance()->display_manager(); DisplayManager* display_manager = Shell::GetInstance()->display_manager();
user_rotation_ = display_manager-> current_rotation_ = user_rotation_ = display_manager->
GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
EnableMaximizeModeWindowManager(true); EnableMaximizeModeWindowManager(true);
event_blocker_.reset(new MaximizeModeEventBlocker); event_blocker_.reset(new MaximizeModeEventBlocker);
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
event_handler_.reset(new ScreenshotActionHandler); event_handler_.reset(new ScreenshotActionHandler);
#endif #endif
Shell::GetInstance()->display_controller()->AddObserver(this);
} }
void MaximizeModeController::LeaveMaximizeMode() { void MaximizeModeController::LeaveMaximizeMode() {
DisplayManager* display_manager = Shell::GetInstance()->display_manager(); DisplayManager* display_manager = Shell::GetInstance()->display_manager();
DisplayInfo info = display_manager-> gfx::Display::Rotation current_rotation = display_manager->
GetDisplayInfo(gfx::Display::InternalDisplayId()); GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation();
gfx::Display::Rotation current_rotation = info.rotation();
if (current_rotation != user_rotation_) if (current_rotation != user_rotation_)
SetDisplayRotation(display_manager, user_rotation_); SetDisplayRotation(display_manager, user_rotation_);
rotation_locked_ = false; rotation_locked_ = false;
EnableMaximizeModeWindowManager(false); EnableMaximizeModeWindowManager(false);
event_blocker_.reset(); event_blocker_.reset();
event_handler_.reset(); event_handler_.reset();
Shell::GetInstance()->display_controller()->RemoveObserver(this);
} }
} // namespace ash } // namespace ash
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
#include "ash/accelerometer/accelerometer_observer.h" #include "ash/accelerometer/accelerometer_observer.h"
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/display/display_controller.h"
#include "ash/display/display_manager.h" #include "ash/display/display_manager.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "ui/gfx/display.h" #include "ui/gfx/display.h"
namespace ui { namespace ui {
...@@ -26,8 +28,20 @@ class MaximizeModeWindowManagerTest; ...@@ -26,8 +28,20 @@ class MaximizeModeWindowManagerTest;
// MaximizeModeController listens to accelerometer events and automatically // MaximizeModeController listens to accelerometer events and automatically
// enters and exits maximize mode when the lid is opened beyond the triggering // enters and exits maximize mode when the lid is opened beyond the triggering
// angle and rotates the display to match the device when in maximize mode. // angle and rotates the display to match the device when in maximize mode.
class ASH_EXPORT MaximizeModeController : public AccelerometerObserver { class ASH_EXPORT MaximizeModeController : public AccelerometerObserver,
public DisplayController::Observer {
public: public:
// Observer that reports changes to the state of MaximizeModeController's
// rotation lock.
class Observer {
public:
// Invoked whenever |rotation_locked_| is changed.
virtual void OnRotationLockChanged(bool rotation_locked) {}
protected:
virtual ~Observer() {}
};
MaximizeModeController(); MaximizeModeController();
virtual ~MaximizeModeController(); virtual ~MaximizeModeController();
...@@ -43,9 +57,11 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver { ...@@ -43,9 +57,11 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver {
// If |rotation_locked| future calls to OnAccelerometerUpdated will not // If |rotation_locked| future calls to OnAccelerometerUpdated will not
// change the display rotation. // change the display rotation.
void set_rotation_locked(bool rotation_locked) { void SetRotationLocked(bool rotation_locked);
rotation_locked_ = rotation_locked;
} // Add/Remove observers.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// True if it is possible to enter maximize mode in the current // True if it is possible to enter maximize mode in the current
// configuration. If this returns false, it should never be the case that // configuration. If this returns false, it should never be the case that
...@@ -73,6 +89,9 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver { ...@@ -73,6 +89,9 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver {
virtual void OnAccelerometerUpdated(const gfx::Vector3dF& base, virtual void OnAccelerometerUpdated(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) OVERRIDE; const gfx::Vector3dF& lid) OVERRIDE;
// DisplayController::Observer:
virtual void OnDisplayConfigurationChanged() OVERRIDE;
private: private:
friend class MaximizeModeControllerTest; friend class MaximizeModeControllerTest;
friend class MaximizeModeWindowManagerTest; friend class MaximizeModeWindowManagerTest;
...@@ -121,6 +140,14 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver { ...@@ -121,6 +140,14 @@ class ASH_EXPORT MaximizeModeController : public AccelerometerObserver {
// restored upon exiting maximize mode. // restored upon exiting maximize mode.
gfx::Display::Rotation user_rotation_; gfx::Display::Rotation user_rotation_;
// The current rotation set by MaximizeModeController for the internal
// display. Compared in OnDisplayConfigurationChanged to determine user
// display setting changes.
gfx::Display::Rotation current_rotation_;
// Rotation Lock observers.
ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(MaximizeModeController); DISALLOW_COPY_AND_ASSIGN(MaximizeModeController);
}; };
......
...@@ -526,7 +526,7 @@ TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) { ...@@ -526,7 +526,7 @@ TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) {
gfx::Vector3dF gravity(-1.0f, 0.0f, 0.0f); gfx::Vector3dF gravity(-1.0f, 0.0f, 0.0f);
maximize_mode_controller()->set_rotation_locked(true); maximize_mode_controller()->SetRotationLocked(true);
// Turn past the threshold for rotation. // Turn past the threshold for rotation.
float degrees = 90.0; float degrees = 90.0;
...@@ -535,7 +535,7 @@ TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) { ...@@ -535,7 +535,7 @@ TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) {
TriggerAccelerometerUpdate(gravity, gravity); TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation()); EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
maximize_mode_controller()->set_rotation_locked(false); maximize_mode_controller()->SetRotationLocked(false);
TriggerAccelerometerUpdate(gravity, gravity); TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation()); EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
} }
...@@ -551,7 +551,7 @@ TEST_F(MaximizeModeControllerTest, ExitingMaximizeModeClearRotationLock) { ...@@ -551,7 +551,7 @@ TEST_F(MaximizeModeControllerTest, ExitingMaximizeModeClearRotationLock) {
gfx::Vector3dF(-1.0f, 0.0f, 0.0f)); gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted()); ASSERT_TRUE(IsMaximizeModeStarted());
maximize_mode_controller()->set_rotation_locked(true); maximize_mode_controller()->SetRotationLocked(true);
// Open 90 degrees. // Open 90 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f)); TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
...@@ -602,6 +602,7 @@ TEST_F(MaximizeModeControllerTest, BlockRotationNotifications) { ...@@ -602,6 +602,7 @@ TEST_F(MaximizeModeControllerTest, BlockRotationNotifications) {
// adjusting the screen rotation directly when in maximize mode // adjusting the screen rotation directly when in maximize mode
ASSERT_NE(gfx::Display::ROTATE_270, GetInternalDisplayRotation()); ASSERT_NE(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
SetInternalDisplayRotation(gfx::Display::ROTATE_270); SetInternalDisplayRotation(gfx::Display::ROTATE_270);
maximize_mode_controller()->SetRotationLocked(false);
EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation()); EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
EXPECT_EQ(1u, message_center->NotificationCount()); EXPECT_EQ(1u, message_center->NotificationCount());
EXPECT_TRUE(message_center->HasPopupNotifications()); EXPECT_TRUE(message_center->HasPopupNotifications());
...@@ -646,4 +647,33 @@ TEST_F(MaximizeModeControllerTest, ResetUserRotationUponExit) { ...@@ -646,4 +647,33 @@ TEST_F(MaximizeModeControllerTest, ResetUserRotationUponExit) {
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation()); EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
} }
// Tests that if a user sets a display rotation that accelerometer rotation
// becomes locked.
TEST_F(MaximizeModeControllerTest,
NonAccelerometerRotationChangesLockRotation) {
// Trigger maximize mode by opening to 270.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
ASSERT_FALSE(maximize_mode_controller()->rotation_locked());
SetInternalDisplayRotation(gfx::Display::ROTATE_270);
EXPECT_TRUE(maximize_mode_controller()->rotation_locked());
}
// Tests that if a user changes the display rotation, while rotation is locked,
// that the updates are recorded. Upon exiting maximize mode the latest user
// rotation should be applied.
TEST_F(MaximizeModeControllerTest, UpdateUserRotationWhileRotationLocked) {
// Trigger maximize mode by opening to 270.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
SetInternalDisplayRotation(gfx::Display::ROTATE_270);
// User sets rotation to the same rotation that the display was at when
// maximize mode was activated.
SetInternalDisplayRotation(gfx::Display::ROTATE_0);
// Exit maximize mode
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
}
} // namespace ash } // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment