blob: c08704679b8d1a8aa51ab83c01c4fbd2858b3ea2 [file] [log] [blame]
// Copyright (c) 2012 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/custom_frame_view_ash.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/maximize_bubble_controller.h"
#include "ash/wm/property_util.h"
#include "ash/wm/window_util.h"
#include "ash/wm/workspace/frame_maximize_button.h"
#include "ash/wm/workspace/snap_sizer.h"
#include "base/command_line.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/events/event_utils.h"
#include "ui/base/gestures/gesture_configuration.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace ash {
namespace internal {
namespace {
class CancelCallbackHandler {
public:
CancelCallbackHandler(int update_events_before_cancel,
FrameMaximizeButton* maximize_button) :
update_events_before_cancel_(update_events_before_cancel),
maximize_button_(maximize_button) {}
virtual ~CancelCallbackHandler() {}
void CountedCancelCallback(ui::EventType event_type,
const gfx::Vector2dF& pos) {
if (event_type == ui::ET_GESTURE_SCROLL_UPDATE &&
!(--update_events_before_cancel_)) {
// Make sure that we are in the middle of a resizing operation, cancel it
// and then test that it is exited.
EXPECT_TRUE(maximize_button_->is_snap_enabled());
maximize_button_->DestroyMaximizeMenu();
EXPECT_FALSE(maximize_button_->is_snap_enabled());
}
}
private:
// When this counter reaches 0, the gesture maximize action gets cancelled.
int update_events_before_cancel_;
// The maximize button which needs to get informed of the gesture termination.
FrameMaximizeButton* maximize_button_;
DISALLOW_COPY_AND_ASSIGN(CancelCallbackHandler);
};
class ShellViewsDelegate : public views::TestViewsDelegate {
public:
ShellViewsDelegate() {}
virtual ~ShellViewsDelegate() {}
// Overridden from views::TestViewsDelegate:
virtual views::NonClientFrameView* CreateDefaultNonClientFrameView(
views::Widget* widget) OVERRIDE {
// Always test CustomFrameViewAsh, which may not be the ash::Shell default.
CustomFrameViewAsh* frame_view = new CustomFrameViewAsh;
frame_view->Init(widget);
return frame_view;
}
virtual bool UseTransparentWindows() const OVERRIDE {
// Ash uses transparent window frames.
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate);
};
class TestWidgetDelegate : public views::WidgetDelegateView {
public:
TestWidgetDelegate() {}
virtual ~TestWidgetDelegate() {}
// Overridden from views::WidgetDelegate:
virtual views::View* GetContentsView() OVERRIDE {
return this;
}
virtual bool CanResize() const OVERRIDE {
return true;
}
virtual bool CanMaximize() const OVERRIDE {
return true;
}
private:
DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate);
};
} // namespace
class CustomFrameViewAshTest : public ash::test::AshTestBase {
public:
CustomFrameViewAshTest() {}
virtual ~CustomFrameViewAshTest() {}
views::Widget* CreateWidget() {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
views::Widget* widget = new views::Widget;
params.context = CurrentContext();
params.delegate = new TestWidgetDelegate;
widget->Init(params);
widget->Show();
return widget;
}
CustomFrameViewAsh* GetCustomFrameViewAsh(views::Widget* widget) const {
return static_cast<CustomFrameViewAsh*>(widget->non_client_view()->
frame_view());
}
virtual void SetUp() OVERRIDE {
AshTestBase::SetUp();
if (!views::ViewsDelegate::views_delegate) {
views_delegate_.reset(new ShellViewsDelegate);
views::ViewsDelegate::views_delegate = views_delegate_.get();
}
}
virtual void TearDown() OVERRIDE {
if (views_delegate_) {
views::ViewsDelegate::views_delegate = NULL;
views_delegate_.reset();
}
AshTestBase::TearDown();
}
private:
scoped_ptr<views::ViewsDelegate> views_delegate_;
DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest);
};
// Tests that clicking on the resize-button toggles between maximize and normal
// state.
TEST_F(CustomFrameViewAshTest, ResizeButtonToggleMaximize) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
views::View* view = test.maximize_button();
gfx::Point center = view->GetBoundsInScreen().CenterPoint();
aura::test::EventGenerator generator(window->GetRootWindow(), center);
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
generator.ClickLeftButton();
RunAllPendingInMessageLoop();
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
center = view->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(center);
generator.ClickLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
generator.GestureTapAt(view->GetBoundsInScreen().CenterPoint());
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
generator.GestureTapAt(view->GetBoundsInScreen().CenterPoint());
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
generator.GestureTapDownAndUp(view->GetBoundsInScreen().CenterPoint());
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
generator.GestureTapDownAndUp(view->GetBoundsInScreen().CenterPoint());
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
widget->Close();
}
#if defined(OS_WIN)
// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
#define MAYBE_ResizeButtonDrag DISABLED_ResizeButtonDrag
#else
#define MAYBE_ResizeButtonDrag ResizeButtonDrag
#endif
// Tests that click+dragging on the resize-button tiles or minimizes the window.
TEST_F(CustomFrameViewAshTest, MAYBE_ResizeButtonDrag) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
views::View* view = test.maximize_button();
gfx::Point center = view->GetBoundsInScreen().CenterPoint();
aura::test::EventGenerator generator(window->GetRootWindow(), center);
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
// Snap right.
{
generator.PressLeftButton();
generator.MoveMouseBy(10, 0);
generator.ReleaseLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
internal::SnapSizer sizer(window, center,
internal::SnapSizer::RIGHT_EDGE,
internal::SnapSizer::OTHER_INPUT);
EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
}
// Snap left.
{
center = view->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(center);
generator.PressLeftButton();
generator.MoveMouseBy(-10, 0);
generator.ReleaseLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
internal::SnapSizer sizer(window, center,
internal::SnapSizer::LEFT_EDGE,
internal::SnapSizer::OTHER_INPUT);
EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
}
// Minimize.
{
center = view->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(center);
generator.PressLeftButton();
generator.MoveMouseBy(0, 10);
generator.ReleaseLeftButton();
RunAllPendingInMessageLoop();
EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
}
ash::wm::RestoreWindow(window);
// Now test the same behaviour for gesture events.
// Snap right.
{
center = view->GetBoundsInScreen().CenterPoint();
gfx::Point end = center;
end.Offset(40, 0);
generator.GestureScrollSequence(center, end,
base::TimeDelta::FromMilliseconds(100),
3);
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
// This is a short resizing distance and different touch behavior
// applies which leads in half of the screen being used.
EXPECT_EQ("400,0 400x552", window->bounds().ToString());
}
// Snap left.
{
center = view->GetBoundsInScreen().CenterPoint();
gfx::Point end = center;
end.Offset(-40, 0);
generator.GestureScrollSequence(center, end,
base::TimeDelta::FromMilliseconds(100),
3);
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
internal::SnapSizer sizer(window, center,
internal::SnapSizer::LEFT_EDGE,
internal::SnapSizer::OTHER_INPUT);
EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
}
// Minimize.
{
center = view->GetBoundsInScreen().CenterPoint();
gfx::Point end = center;
end.Offset(0, 40);
generator.GestureScrollSequence(center, end,
base::TimeDelta::FromMilliseconds(100),
3);
RunAllPendingInMessageLoop();
EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
}
// Test with gesture events.
widget->Close();
}
#if defined(OS_WIN)
// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
#define MAYBE_TouchDragResizeCloseToCornerDiffersFromMouse \
DISABLED_TouchDragResizeCloseToCornerDiffersFromMouse
#else
#define MAYBE_TouchDragResizeCloseToCornerDiffersFromMouse \
TouchDragResizeCloseToCornerDiffersFromMouse
#endif
// Tests Left/Right snapping with resize button touch dragging - which should
// trigger dependent on the available drag distance.
TEST_F(CustomFrameViewAshTest,
MAYBE_TouchDragResizeCloseToCornerDiffersFromMouse) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
views::View* view = test.maximize_button();
gfx::Rect work_area = widget->GetWorkAreaBoundsInScreen();
gfx::Rect bounds = window->bounds();
bounds.set_x(work_area.width() - bounds.width());
widget->SetBounds(bounds);
gfx::Point start_point = view->GetBoundsInScreen().CenterPoint();
// We want to move all the way to the right (the few pixels we have).
gfx::Point end_point = gfx::Point(work_area.width(), start_point.y());
aura::test::EventGenerator generator(window->GetRootWindow(), start_point);
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
// Snap right with a touch drag.
generator.GestureScrollSequence(start_point,
end_point,
base::TimeDelta::FromMilliseconds(100),
10);
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
gfx::Rect touch_result = window->bounds();
EXPECT_NE(bounds.ToString(), touch_result.ToString());
// Set the position back to where it was before and re-try with a mouse.
widget->SetBounds(bounds);
generator.MoveMouseTo(start_point);
generator.PressLeftButton();
generator.MoveMouseTo(end_point, 10);
generator.ReleaseLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
gfx::Rect mouse_result = window->bounds();
// The difference between the two operations should be that the mouse
// operation should have just started to resize and the touch operation is
// already all the way down to the smallest possible size.
EXPECT_NE(mouse_result.ToString(), touch_result.ToString());
EXPECT_GT(mouse_result.width(), touch_result.width());
}
// Test that closing the (browser) window with an opened balloon does not
// crash the system. In other words: Make sure that shutting down the frame
// destroys the opened balloon in an orderly fashion.
TEST_F(CustomFrameViewAshTest, MaximizeButtonExternalShutDown) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
// Move the mouse cursor over the button to bring up the maximizer bubble.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// Even though the widget is closing the bubble menu should not crash upon
// its delayed destruction.
widget->CloseNow();
}
// Test that maximizing the browser after hovering in does not crash the system
// when the observer gets removed in the bubble destruction process.
TEST_F(CustomFrameViewAshTest, MaximizeOnHoverThenClick) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
// Move the mouse cursor over the button to bring up the maximizer bubble.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
generator.ClickLeftButton();
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
}
// Test that hovering over a button in the balloon dialog will show the phantom
// window. Moving then away from the button will hide it again. Then check that
// pressing and dragging the button itself off the button will also release the
// phantom window.
TEST_F(CustomFrameViewAshTest, MaximizeLeftButtonDragOut) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
EXPECT_FALSE(maximize_button->phantom_window_open());
// Move the mouse cursor over the button to bring up the maximizer bubble.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// Move the mouse over the left maximize button.
gfx::Point left_max_pos = maximize_button->maximizer()->
GetButtonForUnitTest(SNAP_LEFT)->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(left_max_pos);
// Expect the phantom window to be open.
EXPECT_TRUE(maximize_button->phantom_window_open());
// Move away to see the window being destroyed.
generator.MoveMouseTo(off_pos);
EXPECT_FALSE(maximize_button->phantom_window_open());
// Move back over the button.
generator.MoveMouseTo(button_pos);
generator.MoveMouseTo(left_max_pos);
EXPECT_TRUE(maximize_button->phantom_window_open());
// Press button and drag out of dialog.
generator.PressLeftButton();
generator.MoveMouseTo(off_pos);
generator.ReleaseLeftButton();
// Check that the phantom window is also gone.
EXPECT_FALSE(maximize_button->phantom_window_open());
}
// Test that clicking a button in the maximizer bubble (in this case the
// maximize left button) will do the requested action.
TEST_F(CustomFrameViewAshTest, MaximizeLeftByButton) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
EXPECT_FALSE(maximize_button->phantom_window_open());
// Move the mouse cursor over the button to bring up the maximizer bubble.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// Move the mouse over the left maximize button.
gfx::Point left_max_pos = maximize_button->maximizer()->
GetButtonForUnitTest(SNAP_LEFT)->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(left_max_pos);
EXPECT_TRUE(maximize_button->phantom_window_open());
generator.ClickLeftButton();
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_FALSE(maximize_button->phantom_window_open());
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
internal::SnapSizer sizer(window, button_pos,
internal::SnapSizer::LEFT_EDGE,
internal::SnapSizer::OTHER_INPUT);
sizer.SelectDefaultSizeAndDisableResize();
EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
}
// Test that the activation focus does not change when the bubble gets shown.
TEST_F(CustomFrameViewAshTest, MaximizeKeepFocus) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
aura::Window* active =
aura::client::GetFocusClient(window)->GetFocusedWindow();
// Move the mouse cursor over the button to bring up the maximizer bubble.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// Check that the focused window is still the same.
EXPECT_EQ(active, aura::client::GetFocusClient(window)->GetFocusedWindow());
}
TEST_F(CustomFrameViewAshTest, MaximizeTap) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
aura::RootWindow* root_window = window->GetRootWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
const int touch_default_radius =
ui::GestureConfiguration::default_radius();
ui::GestureConfiguration::set_default_radius(0);
const int kTouchId = 2;
ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
button_pos,
kTouchId,
ui::EventTimeForNow());
root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
button_pos.Offset(9, 8);
ui::TouchEvent release(
ui::ET_TOUCH_RELEASED,
button_pos,
kTouchId,
press.time_stamp() + base::TimeDelta::FromMilliseconds(50));
root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&release);
ui::GestureConfiguration::set_default_radius(touch_default_radius);
}
// Test that only the left button will activate the maximize button.
TEST_F(CustomFrameViewAshTest, OnlyLeftButtonMaximizes) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_TRUE(ash::wm::IsWindowNormal(window));
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
// Move the mouse cursor over the button.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
EXPECT_FALSE(maximize_button->phantom_window_open());
// After pressing the left button the button should get triggered.
generator.PressLeftButton();
RunAllPendingInMessageLoop();
EXPECT_TRUE(maximize_button->is_snap_enabled());
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
// Pressing the right button then should cancel the operation.
generator.PressRightButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(maximize_button->maximizer());
// After releasing the second button the window shouldn't be maximized.
generator.ReleaseRightButton();
generator.ReleaseLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
// Second experiment: Starting with right should also not trigger.
generator.MoveMouseTo(off_pos);
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// Pressing first the right button should not activate.
generator.PressRightButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(maximize_button->is_snap_enabled());
// Pressing then additionally the left button shouldn't activate either.
generator.PressLeftButton();
RunAllPendingInMessageLoop();
EXPECT_FALSE(maximize_button->is_snap_enabled());
generator.ReleaseRightButton();
generator.ReleaseLeftButton();
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
}
// Click a button of window maximize functionality.
// If |snap_type| is SNAP_NONE the FrameMaximizeButton gets clicked, otherwise
// the associated snap button.
// |Window| is the window which owns the maximize button.
// |maximize_button| is the FrameMaximizeButton which controls the window.
void ClickMaxButton(
ash::FrameMaximizeButton* maximize_button,
aura::Window* window,
SnapType snap_type) {
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
generator.MoveMouseTo(off_pos);
EXPECT_FALSE(maximize_button->maximizer());
EXPECT_FALSE(maximize_button->phantom_window_open());
// Move the mouse cursor over the button.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
EXPECT_FALSE(maximize_button->phantom_window_open());
if (snap_type != SNAP_NONE) {
gfx::Point left_max_pos = maximize_button->maximizer()->
GetButtonForUnitTest(snap_type)->GetBoundsInScreen().CenterPoint();
generator.MoveMouseTo(left_max_pos);
EXPECT_TRUE(maximize_button->phantom_window_open());
}
// After pressing the left button the button should get triggered.
generator.ClickLeftButton();
EXPECT_FALSE(maximize_button->maximizer());
}
// Test that the restore from left/right maximize is properly done.
TEST_F(CustomFrameViewAshTest, MaximizeLeftRestore) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
ClickMaxButton(maximize_button, window, SNAP_LEFT);
// The window should not be maximized.
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
// But the bounds should be different.
gfx::Rect new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(0, new_bounds.x());
EXPECT_EQ(0, new_bounds.y());
// Now click the same button again to see that it restores.
ClickMaxButton(maximize_button, window, SNAP_LEFT);
// But the bounds should be restored.
new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(new_bounds.x(), initial_bounds.x());
EXPECT_EQ(new_bounds.y(), initial_bounds.x());
EXPECT_EQ(new_bounds.width(), initial_bounds.width());
EXPECT_EQ(new_bounds.height(), initial_bounds.height());
// Make sure that there is no restore rectangle left.
EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window));
}
// Maximize, left/right maximize and then restore should works.
TEST_F(CustomFrameViewAshTest, MaximizeMaximizeLeftRestore) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
ClickMaxButton(maximize_button, window, SNAP_NONE);
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
ClickMaxButton(maximize_button, window, SNAP_LEFT);
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
gfx::Rect new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(0, new_bounds.x());
EXPECT_EQ(0, new_bounds.y());
// Now click the same button again to see that it restores.
ClickMaxButton(maximize_button, window, SNAP_LEFT);
RunAllPendingInMessageLoop();
// But the bounds should be restored.
new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(new_bounds.x(), initial_bounds.x());
EXPECT_EQ(new_bounds.y(), initial_bounds.x());
EXPECT_EQ(new_bounds.width(), initial_bounds.width());
EXPECT_EQ(new_bounds.height(), initial_bounds.height());
// Make sure that there is no restore rectangle left.
EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window));
}
// Left/right maximize, maximize and then restore should work.
TEST_F(CustomFrameViewAshTest, MaximizeLeftMaximizeRestore) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
ClickMaxButton(maximize_button, window, SNAP_LEFT);
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
ClickMaxButton(maximize_button, window, SNAP_NONE);
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
ClickMaxButton(maximize_button, window, SNAP_NONE);
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
gfx::Rect new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(new_bounds.x(), initial_bounds.x());
EXPECT_EQ(new_bounds.y(), initial_bounds.x());
EXPECT_EQ(new_bounds.width(), initial_bounds.width());
EXPECT_EQ(new_bounds.height(), initial_bounds.height());
// Make sure that there is no restore rectangle left.
EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window));
}
// Starting with a window which has no restore bounds, maximize then left/right
// maximize should not be centered but left/right maximized.
TEST_F(CustomFrameViewAshTest, MaximizeThenLeftMaximize) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
gfx::Rect initial_bounds = widget->GetWindowBoundsInScreen();
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
maximize_button->set_bubble_appearance_delay_ms(0);
// Make sure that there is no restore rectangle.
EXPECT_EQ(NULL, GetRestoreBoundsInScreen(window));
ClickMaxButton(maximize_button, window, SNAP_NONE);
EXPECT_TRUE(ash::wm::IsWindowMaximized(window));
ClickMaxButton(maximize_button, window, SNAP_LEFT);
EXPECT_FALSE(ash::wm::IsWindowMaximized(window));
gfx::Rect new_bounds = widget->GetWindowBoundsInScreen();
EXPECT_EQ(new_bounds.x(), 0);
EXPECT_EQ(new_bounds.y(), 0);
// Make sure that the restore rectangle is the original rectangle.
EXPECT_EQ(initial_bounds.ToString(),
GetRestoreBoundsInScreen(window)->ToString());
}
// Test that minimizing the window per keyboard closes the maximize bubble.
TEST_F(CustomFrameViewAshTest, MinimizePerKeyClosesBubble) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
ash::FrameMaximizeButton* maximize_button = test.maximize_button();
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() + 100, button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow(), off_pos);
generator.MoveMouseTo(off_pos);
EXPECT_FALSE(maximize_button->maximizer());
// Move the mouse cursor over the maximize button.
generator.MoveMouseTo(button_pos);
EXPECT_TRUE(maximize_button->maximizer());
// We simulate the keystroke by calling minimizeWindow directly.
wm::MinimizeWindow(window);
EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
EXPECT_FALSE(maximize_button->maximizer());
}
// Tests that dragging down on the maximize button minimizes the window.
TEST_F(CustomFrameViewAshTest, MaximizeButtonDragDownMinimizes) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
widget->SetBounds(gfx::Rect(10, 10, 100, 100));
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
FrameMaximizeButton* maximize_button = test.maximize_button();
// Drag down on a maximized window.
wm::MaximizeWindow(window);
EXPECT_TRUE(wm::IsWindowMaximized(window));
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x(), button_pos.y() + 100);
aura::test::EventGenerator generator(window->GetRootWindow());
generator.GestureScrollSequence(button_pos, off_pos,
base::TimeDelta::FromMilliseconds(0), 1);
EXPECT_TRUE(wm::IsWindowMinimized(window));
EXPECT_FALSE(maximize_button->maximizer());
// Drag down on a restored window.
wm::RestoreWindow(window);
button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
off_pos = gfx::Point(button_pos.x(), button_pos.y() + 200);
generator.GestureScrollSequence(button_pos, off_pos,
base::TimeDelta::FromMilliseconds(10), 1);
EXPECT_TRUE(wm::IsWindowMinimized(window));
EXPECT_FALSE(maximize_button->maximizer());
}
// Tests that dragging Left and pressing ESC does properly abort.
TEST_F(CustomFrameViewAshTest, MaximizeButtonDragLeftEscapeExits) {
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
gfx::Rect window_position = gfx::Rect(10, 10, 100, 100);
widget->SetBounds(window_position);
CustomFrameViewAsh* frame = GetCustomFrameViewAsh(widget);
CustomFrameViewAsh::TestApi test(frame);
FrameMaximizeButton* maximize_button = test.maximize_button();
gfx::Point button_pos = maximize_button->GetBoundsInScreen().CenterPoint();
gfx::Point off_pos(button_pos.x() - button_pos.x() / 2, button_pos.y());
const int kGestureSteps = 10;
CancelCallbackHandler cancel_handler(kGestureSteps / 2, maximize_button);
aura::test::EventGenerator generator(window->GetRootWindow());
generator.GestureScrollSequenceWithCallback(
button_pos,
off_pos,
base::TimeDelta::FromMilliseconds(0),
kGestureSteps,
base::Bind(&CancelCallbackHandler::CountedCancelCallback,
base::Unretained(&cancel_handler)));
// Check that there was no size change.
EXPECT_EQ(widget->GetWindowBoundsInScreen().size().ToString(),
window_position.size().ToString());
// Check that there is no phantom window left open.
EXPECT_FALSE(maximize_button->phantom_window_open());
}
} // namespace internal
} // namespace ash