blob: 8afb9e380c41f6c55270f94f089324aa12d36737 [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 "ash/wm/maximize_mode/maximize_mode_controller.h"
#include "ash/accelerometer/accelerometer_controller.h"
#include "ash/display/display_manager.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/display_manager_test_api.h"
#include "ash/test/test_lock_state_controller_delegate.h"
#include "ash/test/test_screenshot_delegate.h"
#include "ash/test/test_system_tray_delegate.h"
#include "ash/test/test_volume_control_delegate.h"
#include "ash/wm/maximize_mode/internal_input_device_list.h"
#include "ash/wm/maximize_mode/maximize_mode_event_blocker.h"
#include "ui/aura/test/event_generator.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/vector3d_f.h"
#include "ui/message_center/message_center.h"
#if defined(USE_X11)
#include "ui/events/test/events_test_utils_x11.h"
#endif
namespace ash {
namespace {
const float kDegreesToRadians = 3.14159265f / 180.0f;
// Filter to count the number of events seen.
class EventCounter : public ui::EventHandler {
public:
EventCounter();
virtual ~EventCounter();
// Overridden from ui::EventHandler:
virtual void OnEvent(ui::Event* event) OVERRIDE;
void reset() {
event_count_ = 0;
}
size_t event_count() const { return event_count_; }
private:
size_t event_count_;
DISALLOW_COPY_AND_ASSIGN(EventCounter);
};
EventCounter::EventCounter() : event_count_(0) {
Shell::GetInstance()->AddPreTargetHandler(this);
}
EventCounter::~EventCounter() {
Shell::GetInstance()->RemovePreTargetHandler(this);
}
void EventCounter::OnEvent(ui::Event* event) {
event_count_++;
}
// A test internal input device list which pretends that all events are from
// internal devices to allow verifying that the event blocking works.
class TestInternalInputDeviceList : public InternalInputDeviceList {
public:
TestInternalInputDeviceList() {}
virtual ~TestInternalInputDeviceList() {}
virtual bool IsEventFromInternalDevice(const ui::Event* event) OVERRIDE {
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestInternalInputDeviceList);
};
} // namespace
// Test accelerometer data taken with the lid at less than 180 degrees while
// shaking the device around. The data is to be interpreted in groups of 6 where
// each 6 values corresponds to the X, Y, and Z readings from the base and lid
// accelerometers in this order.
extern const float kAccelerometerLaptopModeTestData[];
extern const size_t kAccelerometerLaptopModeTestDataLength;
// Test accelerometer data taken with the lid open 360 degrees while
// shaking the device around. The data is to be interpreted in groups of 6 where
// each 6 values corresponds to the X, Y, and Z readings from the base and lid
// accelerometers in this order.
extern const float kAccelerometerFullyOpenTestData[];
extern const size_t kAccelerometerFullyOpenTestDataLength;
class MaximizeModeControllerTest : public test::AshTestBase {
public:
MaximizeModeControllerTest() {}
virtual ~MaximizeModeControllerTest() {}
virtual void SetUp() OVERRIDE {
test::AshTestBase::SetUp();
Shell::GetInstance()->accelerometer_controller()->RemoveObserver(
maximize_mode_controller());
// Set the first display to be the internal display for the accelerometer
// screen rotation tests.
test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
SetFirstDisplayAsInternalDisplay();
}
virtual void TearDown() OVERRIDE {
Shell::GetInstance()->accelerometer_controller()->AddObserver(
maximize_mode_controller());
test::AshTestBase::TearDown();
}
MaximizeModeController* maximize_mode_controller() {
return Shell::GetInstance()->maximize_mode_controller();
}
void TriggerAccelerometerUpdate(const gfx::Vector3dF& base,
const gfx::Vector3dF& lid) {
maximize_mode_controller()->OnAccelerometerUpdated(base, lid);
}
bool IsMaximizeModeStarted() {
return maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled();
}
// Overrides the internal input device list for the current event targeters
// with one which always returns true.
void InstallTestInternalDeviceList() {
maximize_mode_controller()->event_blocker_->internal_devices_.reset(
new TestInternalInputDeviceList);
}
gfx::Display::Rotation GetInternalDisplayRotation() const {
return Shell::GetInstance()->display_manager()->GetDisplayInfo(
gfx::Display::InternalDisplayId()).rotation();
}
void SetInternalDisplayRotation(gfx::Display::Rotation rotation) const {
Shell::GetInstance()->display_manager()->
SetDisplayRotation(gfx::Display::InternalDisplayId(), rotation);
}
private:
DISALLOW_COPY_AND_ASSIGN(MaximizeModeControllerTest);
};
// Tests that opening the lid beyond 180 will enter touchview, and that it will
// exit when the lid comes back from 180. Also tests the thresholds, i.e. it
// will stick to the current mode.
TEST_F(MaximizeModeControllerTest, EnterExitThresholds) {
// For the simple test the base remains steady.
gfx::Vector3dF base(0.0f, 0.0f, 1.0f);
// Lid open 90 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Open just past 180.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(0.05f, 0.0f, -1.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Open up 270 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(1.0f, 0.0f, 0.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
// Open up 360 degrees and appearing to be slightly past it (i.e. as if almost
// closed).
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-0.05f, 0.0f, 1.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
// Open just before 180.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-0.05f, 0.0f, -1.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
// Open 90 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
}
// Tests that when the hinge is nearly vertically aligned, the current state
// persists as the computed angle is highly inaccurate in this orientation.
TEST_F(MaximizeModeControllerTest, HingeAligned) {
// Laptop in normal orientation lid open 90 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Completely vertical.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -1.0f, 0.0f),
gfx::Vector3dF(0.0f, -1.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Close to vertical but with hinge appearing to be open 270 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -1.0f, 0.01f),
gfx::Vector3dF(0.01f, -1.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Flat and open 270 degrees should start maximize mode.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
// Normal 90 degree orientation but near vertical should stay in maximize
// mode.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -1.0f, 0.01f),
gfx::Vector3dF(-0.01f, -1.0f, 0.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
}
// Tests that accelerometer readings in each of the screen angles will trigger
// a rotation of the internal display.
TEST_F(MaximizeModeControllerTest, DisplayRotation) {
// 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_TRUE(IsMaximizeModeStarted());
// Now test rotating in all directions.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 1.0f, 0.0f),
gfx::Vector3dF(0.0f, 1.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(1.0f, 0.0f, 0.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -1.0f, 0.0f),
gfx::Vector3dF(0.0f, -1.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(-1.0f, 0.0f, 0.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
}
// Tests that low angles are ignored by the accelerometer (i.e. when the device
// is almost laying flat).
TEST_F(MaximizeModeControllerTest, RotationIgnoresLowAngles) {
// 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_TRUE(IsMaximizeModeStarted());
TriggerAccelerometerUpdate(gfx::Vector3dF(-1.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, -1.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.2f, -1.0f),
gfx::Vector3dF(0.0f, 0.2f, -1.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(0.2f, 0.0f, -1.0f),
gfx::Vector3dF(0.2f, 0.0f, -1.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -0.2f, -1.0f),
gfx::Vector3dF(0.0f, -0.2f, -1.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(-0.2f, 0.0f, -1.0f),
gfx::Vector3dF(-0.2f, 0.0f, -1.0f));
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
}
// Tests that the display will stick to the current orientation beyond the
// halfway point, preventing frequent updates back and forth.
TEST_F(MaximizeModeControllerTest, RotationSticky) {
// 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_TRUE(IsMaximizeModeStarted());
gfx::Vector3dF gravity(-1.0f, 0.0f, 0.0f);
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
// Turn past half-way point to next direction and rotation should remain
// the same.
float degrees = 50.0;
gravity.set_x(-cos(degrees * kDegreesToRadians));
gravity.set_y(sin(degrees * kDegreesToRadians));
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
// Turn more and the screen should rotate.
degrees = 70.0;
gravity.set_x(-cos(degrees * kDegreesToRadians));
gravity.set_y(sin(degrees * kDegreesToRadians));
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
// Turn back just beyond the half-way point and the new rotation should
// still be in effect.
degrees = 40.0;
gravity.set_x(-cos(degrees * kDegreesToRadians));
gravity.set_y(sin(degrees * kDegreesToRadians));
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
}
// Tests that the screen only rotates when maximize mode is engaged, and will
// return to the standard orientation on exiting maximize mode.
TEST_F(MaximizeModeControllerTest, RotationOnlyInMaximizeMode) {
// Rotate on side with lid only open 90 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.95f, 0.35f),
gfx::Vector3dF(-0.35f, 0.95f, 0.0f));
ASSERT_FALSE(IsMaximizeModeStarted());
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
// Open lid, screen should now rotate to match orientation.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.95f, -0.35f),
gfx::Vector3dF(-0.35f, 0.95f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
// Close lid back to 90, screen should rotate back.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.95f, 0.35f),
gfx::Vector3dF(-0.35f, 0.95f, 0.0f));
ASSERT_FALSE(IsMaximizeModeStarted());
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
}
// Tests that maximize mode blocks keyboard and mouse events but not touch
// events.
TEST_F(MaximizeModeControllerTest, BlocksKeyboardAndMouse) {
aura::Window* root = Shell::GetPrimaryRootWindow();
aura::test::EventGenerator event_generator(root, root);
EventCounter counter;
event_generator.PressKey(ui::VKEY_ESCAPE, 0);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
event_generator.ClickLeftButton();
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
event_generator.ScrollSequence(
gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, 100, 5, 2);
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
event_generator.MoveMouseWheel(0, 10);
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
event_generator.PressTouch();
event_generator.ReleaseTouch();
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
// Open up 270 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
InstallTestInternalDeviceList();
event_generator.PressKey(ui::VKEY_ESCAPE, 0);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
EXPECT_EQ(0u, counter.event_count());
counter.reset();
event_generator.ClickLeftButton();
EXPECT_EQ(0u, counter.event_count());
counter.reset();
event_generator.ScrollSequence(
gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, 100, 5, 2);
EXPECT_EQ(0u, counter.event_count());
counter.reset();
event_generator.MoveMouseWheel(0, 10);
EXPECT_EQ(0u, counter.event_count());
counter.reset();
// Touch should not be blocked.
event_generator.PressTouch();
event_generator.ReleaseTouch();
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
gfx::Vector3dF base;
// Lid open 90 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
event_generator.PressKey(ui::VKEY_ESCAPE, 0);
event_generator.ReleaseKey(ui::VKEY_ESCAPE, 0);
EXPECT_GT(counter.event_count(), 0u);
counter.reset();
}
#if defined(OS_CHROMEOS)
// Tests that a screenshot can be taken in maximize mode by holding volume down
// and pressing power.
TEST_F(MaximizeModeControllerTest, Screenshot) {
Shell::GetInstance()->lock_state_controller()->SetDelegate(
new test::TestLockStateControllerDelegate);
aura::Window* root = Shell::GetPrimaryRootWindow();
aura::test::EventGenerator event_generator(root, root);
test::TestScreenshotDelegate* delegate = GetScreenshotDelegate();
delegate->set_can_take_screenshot(true);
// Open up 270 degrees.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
// Pressing power alone does not take a screenshot.
event_generator.PressKey(ui::VKEY_POWER, 0);
event_generator.ReleaseKey(ui::VKEY_POWER, 0);
EXPECT_EQ(0, delegate->handle_take_screenshot_count());
// Holding volume down and pressing power takes a screenshot.
event_generator.PressKey(ui::VKEY_VOLUME_DOWN, 0);
event_generator.PressKey(ui::VKEY_POWER, 0);
event_generator.ReleaseKey(ui::VKEY_POWER, 0);
EXPECT_EQ(1, delegate->handle_take_screenshot_count());
event_generator.ReleaseKey(ui::VKEY_VOLUME_DOWN, 0);
}
#endif // OS_CHROMEOS
#if defined(USE_X11)
// Tests that maximize mode allows volume up/down events originating
// from dedicated buttons versus remapped keyboard buttons.
TEST_F(MaximizeModeControllerTest, AllowsVolumeControl) {
aura::Window* root = Shell::GetPrimaryRootWindow();
aura::test::EventGenerator event_generator(root, root);
TestVolumeControlDelegate* volume_delegate =
new TestVolumeControlDelegate(true);
ash::Shell::GetInstance()->system_tray_delegate()->SetVolumeControlDelegate(
scoped_ptr<VolumeControlDelegate>(volume_delegate).Pass());
// Trigger maximize mode by opening to 270 to begin the test in maximize mode.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
ui::ScopedXI2Event xevent;
// Verify F9 button event is blocked
ASSERT_EQ(0, volume_delegate->handle_volume_down_count());
xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_DOWN, ui::EF_NONE);
ui::KeyEvent press_f9(xevent, false /* is_char */);
press_f9.set_flags(ui::EF_FUNCTION_KEY);
event_generator.Dispatch(&press_f9);
EXPECT_EQ(0, volume_delegate->handle_volume_down_count());
// Verify F10 button event is blocked
ASSERT_EQ(0, volume_delegate->handle_volume_up_count());
xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_UP, ui::EF_NONE);
ui::KeyEvent press_f10(xevent, false /* is_char */);
press_f10.set_flags(ui::EF_FUNCTION_KEY);
event_generator.Dispatch(&press_f10);
EXPECT_EQ(0, volume_delegate->handle_volume_up_count());
// Verify volume down button event is not blocked
ASSERT_EQ(0, volume_delegate->handle_volume_down_count());
xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_DOWN, ui::EF_NONE);
ui::KeyEvent press_vol_down(xevent, false /* is_char */);
event_generator.Dispatch(&press_vol_down);
EXPECT_EQ(1, volume_delegate->handle_volume_down_count());
// Verify volume up event is not blocked
ASSERT_EQ(0, volume_delegate->handle_volume_up_count());
xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_VOLUME_UP, ui::EF_NONE);
ui::KeyEvent press_vol_up(xevent, false /* is_char */);
event_generator.Dispatch(&press_vol_up);
EXPECT_EQ(1, volume_delegate->handle_volume_up_count());
}
#endif // defined(USE_X11)
TEST_F(MaximizeModeControllerTest, LaptopTest) {
// Feeds in sample accelerometer data and verifies that there are no
// transitions into touchview / maximize mode while shaking the device around
// with the hinge at less than 180 degrees.
ASSERT_EQ(0u, kAccelerometerLaptopModeTestDataLength % 6);
for (size_t i = 0; i < kAccelerometerLaptopModeTestDataLength / 6; ++i) {
gfx::Vector3dF base(kAccelerometerLaptopModeTestData[i * 6],
kAccelerometerLaptopModeTestData[i * 6 + 1],
kAccelerometerLaptopModeTestData[i * 6 + 2]);
gfx::Vector3dF lid(kAccelerometerLaptopModeTestData[i * 6 + 3],
kAccelerometerLaptopModeTestData[i * 6 + 4],
kAccelerometerLaptopModeTestData[i * 6 + 5]);
TriggerAccelerometerUpdate(base, lid);
// There are a lot of samples, so ASSERT rather than EXPECT to only generate
// one failure rather than potentially hundreds.
ASSERT_FALSE(IsMaximizeModeStarted());
}
}
TEST_F(MaximizeModeControllerTest, MaximizeModeTest) {
// Trigger maximize mode by opening to 270 to begin the test in maximize mode.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
// Feeds in sample accelerometer data and verifies that there are no
// transitions out of touchview / maximize mode while shaking the device
// around.
ASSERT_EQ(0u, kAccelerometerFullyOpenTestDataLength % 6);
for (size_t i = 0; i < kAccelerometerFullyOpenTestDataLength / 6; ++i) {
gfx::Vector3dF base(kAccelerometerFullyOpenTestData[i * 6],
kAccelerometerFullyOpenTestData[i * 6 + 1],
kAccelerometerFullyOpenTestData[i * 6 + 2]);
gfx::Vector3dF lid(kAccelerometerFullyOpenTestData[i * 6 + 3],
kAccelerometerFullyOpenTestData[i * 6 + 4],
kAccelerometerFullyOpenTestData[i * 6 + 5]);
TriggerAccelerometerUpdate(base, lid);
// There are a lot of samples, so ASSERT rather than EXPECT to only generate
// one failure rather than potentially hundreds.
ASSERT_TRUE(IsMaximizeModeStarted());
}
}
// Tests that the display will stick to its current orientation when the
// rotation lock has been set.
TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) {
// 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_TRUE(IsMaximizeModeStarted());
gfx::Vector3dF gravity(-1.0f, 0.0f, 0.0f);
maximize_mode_controller()->SetRotationLocked(true);
// Turn past the threshold for rotation.
float degrees = 90.0;
gravity.set_x(-cos(degrees * kDegreesToRadians));
gravity.set_y(sin(degrees * kDegreesToRadians));
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
maximize_mode_controller()->SetRotationLocked(false);
TriggerAccelerometerUpdate(gravity, gravity);
EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
}
// Tests that when MaximizeModeController turns off MaximizeMode that on the
// next accelerometer update the rotation lock is cleared.
TEST_F(MaximizeModeControllerTest, ExitingMaximizeModeClearRotationLock) {
// The base remains steady.
gfx::Vector3dF base(0.0f, 0.0f, 1.0f);
// 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_TRUE(IsMaximizeModeStarted());
maximize_mode_controller()->SetRotationLocked(true);
// Open 90 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
// Send an update that would not relaunch MaximizeMode. 90 degrees.
TriggerAccelerometerUpdate(base, gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(maximize_mode_controller()->rotation_locked());
}
// The TrayDisplay class that is responsible for adding/updating MessageCenter
// notifications is only added to the SystemTray on ChromeOS.
#if defined(OS_CHROMEOS)
// Tests that the screen rotation notifications are suppressed when
// triggered by the accelerometer.
TEST_F(MaximizeModeControllerTest, BlockRotationNotifications) {
test::TestSystemTrayDelegate* tray_delegate =
static_cast<test::TestSystemTrayDelegate*>(
Shell::GetInstance()->system_tray_delegate());
tray_delegate->set_should_show_display_notification(true);
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
// Make sure notifications are still displayed when
// adjusting the screen rotation directly when not in maximize mode
ASSERT_FALSE(IsMaximizeModeStarted());
ASSERT_NE(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
ASSERT_EQ(0u, message_center->NotificationCount());
ASSERT_FALSE(message_center->HasPopupNotifications());
SetInternalDisplayRotation(gfx::Display::ROTATE_180);
EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
EXPECT_EQ(1u, message_center->NotificationCount());
EXPECT_TRUE(message_center->HasPopupNotifications());
// Reset the screen rotation.
SetInternalDisplayRotation(gfx::Display::ROTATE_0);
// Clear all notifications
message_center->RemoveAllNotifications(false);
// Trigger maximize mode by opening to 270.
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_TRUE(IsMaximizeModeStarted());
EXPECT_EQ(0u, message_center->NotificationCount());
EXPECT_FALSE(message_center->HasPopupNotifications());
// Make sure notifications are still displayed when
// adjusting the screen rotation directly when in maximize mode
ASSERT_NE(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
SetInternalDisplayRotation(gfx::Display::ROTATE_270);
maximize_mode_controller()->SetRotationLocked(false);
EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
EXPECT_EQ(1u, message_center->NotificationCount());
EXPECT_TRUE(message_center->HasPopupNotifications());
// Clear all notifications
message_center->RemoveAllNotifications(false);
EXPECT_EQ(0u, message_center->NotificationCount());
EXPECT_FALSE(message_center->HasPopupNotifications());
// Make sure notifications are blocked when adjusting the screen rotation
// via the accelerometer while in maximize mode
// Rotate the screen 90 degrees
ASSERT_NE(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 1.0f, 0.0f),
gfx::Vector3dF(0.0f, 1.0f, 0.0f));
ASSERT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
EXPECT_EQ(0u, message_center->NotificationCount());
EXPECT_FALSE(message_center->HasPopupNotifications());
}
#endif
// Tests that if a user has set a display rotation that it is restored upon
// exiting maximize mode.
TEST_F(MaximizeModeControllerTest, ResetUserRotationUponExit) {
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
gfx::Display::ROTATE_90);
// Trigger maximize mode
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
ASSERT_TRUE(IsMaximizeModeStarted());
TriggerAccelerometerUpdate(gfx::Vector3dF(1.0f, 0.0f, 0.0f),
gfx::Vector3dF(1.0f, 0.0f, 0.0f));
EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
// Exit maximize mode
TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, 1.0f),
gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
EXPECT_FALSE(IsMaximizeModeStarted());
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