Commit 59d3f873 authored by skuhne@chromium.org's avatar skuhne@chromium.org

Adding unit tests for maximize menu


BUG=141635
TEST=Unittest

Review URL: https://chromiumcodereview.appspot.com/10825327

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151485 0039d316-1c4b-4281-b951-d872f2087c98
parent 39a5061d
......@@ -12,6 +12,7 @@
namespace ash {
class FramePainter;
class FrameMaximizeButton;
}
namespace gfx {
class Font;
......@@ -40,7 +41,7 @@ class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView,
explicit TestApi(CustomFrameViewAsh* frame) : frame_(frame) {
}
views::ImageButton* maximize_button() const {
ash::FrameMaximizeButton* maximize_button() const {
return frame_->maximize_button_;
}
......@@ -81,7 +82,7 @@ class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView,
// Not owned.
views::Widget* frame_;
views::ImageButton* maximize_button_;
ash::FrameMaximizeButton* maximize_button_;
views::ImageButton* close_button_;
views::ImageButton* window_icon_;
......
......@@ -6,7 +6,9 @@
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/maximize_bubble_controller.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/aura_switches.h"
......@@ -255,5 +257,119 @@ TEST_F(CustomFrameViewAshTest, ResizeButtonDrag) {
widget->Close();
}
// 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 = custom_frame_view_ash(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 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 = custom_frame_view_ash(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) {
const int kGridSize = ash::Shell::GetInstance()->GetGridSize();
views::Widget* widget = CreateWidget();
aura::Window* window = widget->GetNativeWindow();
CustomFrameViewAsh* frame = custom_frame_view_ash(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, kGridSize);
EXPECT_EQ(sizer.target_bounds().ToString(), window->bounds().ToString());
}
} // namespace internal
} // namespace ash
......@@ -51,9 +51,6 @@ const int kLabelSpacing = 4;
const int kArrowHeight = 10;
const int kArrowWidth = 20;
// The delay of the bubble appearance.
const int kBubbleAppearanceDelayMS = 200;
// The animation offset in y for the bubble when appearing.
const int kBubbleAnimationOffsetY = 5;
......@@ -218,7 +215,7 @@ class BubbleMouseWatcherHost: public views::MouseWatcherHost {
class MaximizeBubbleController::Bubble : public views::BubbleDelegateView,
public views::MouseWatcherListener {
public:
explicit Bubble(MaximizeBubbleController* owner);
explicit Bubble(MaximizeBubbleController* owner, int appearance_delay_ms_);
virtual ~Bubble() {}
// The window of the menu under which the SnapSizer will get created.
......@@ -257,6 +254,10 @@ class MaximizeBubbleController::Bubble : public views::BubbleDelegateView,
// of an asynchronous shutdown.
MaximizeBubbleController* controller() const { return owner_; }
// Added for unit test: Retrieve the button for an action.
// |state| can be either SNAP_LEFT, SNAP_RIGHT or SNAP_MINIMIZE.
views::CustomButton* GetButtonForUnitTest(SnapType state);
private:
// True if the shut down has been initiated.
bool shutting_down_;
......@@ -279,6 +280,9 @@ class MaximizeBubbleController::Bubble : public views::BubbleDelegateView,
// The mouse watcher which takes care of out of window hover events.
scoped_ptr<views::MouseWatcher> mouse_watcher_;
// The fade delay - if 0 it will show / hide immediately.
const int appearance_delay_ms_;
DISALLOW_COPY_AND_ASSIGN(Bubble);
};
......@@ -296,6 +300,12 @@ class BubbleContentsButtonRow : public views::View,
// Called from BubbleDialogButton.
void ButtonHovered(BubbleDialogButton* sender);
// Added for unit test: Retrieve the button for an action.
// |state| can be either SNAP_LEFT, SNAP_RIGHT or SNAP_MINIMIZE.
views::CustomButton* GetButtonForUnitTest(SnapType state);
MaximizeBubbleController::Bubble* bubble() { return bubble_; }
private:
// The owning object which gets notifications.
MaximizeBubbleController::Bubble* bubble_;
......@@ -320,6 +330,12 @@ class BubbleContentsView : public views::View {
// through hover operations.
void SetSnapType(SnapType snap_type);
// Added for unit test: Retrieve the button for an action.
// |state| can be either SNAP_LEFT, SNAP_RIGHT or SNAP_MINIMIZE.
views::CustomButton* GetButtonForUnitTest(SnapType state) {
return buttons_view_->GetButtonForUnitTest(state);
}
private:
// The owning class.
MaximizeBubbleController::Bubble* bubble_;
......@@ -348,6 +364,7 @@ class BubbleDialogButton : public views::ImageButton {
virtual void OnMouseCaptureLost() OVERRIDE;
virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
private:
// The creating class which needs to get notified in case of a hover event.
......@@ -356,14 +373,17 @@ class BubbleDialogButton : public views::ImageButton {
DISALLOW_COPY_AND_ASSIGN(BubbleDialogButton);
};
MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner)
MaximizeBubbleController::Bubble::Bubble(
MaximizeBubbleController* owner,
int appearance_delay_ms)
: views::BubbleDelegateView(owner->frame_maximize_button(),
views::BubbleBorder::TOP_RIGHT),
shutting_down_(false),
owner_(owner),
bubble_widget_(NULL),
contents_view_(NULL),
bubble_border_(NULL) {
bubble_border_(NULL),
appearance_delay_ms_(appearance_delay_ms) {
set_margins(gfx::Insets());
// The window needs to be owned by the root so that the SnapSizer does not
......@@ -402,7 +422,10 @@ MaximizeBubbleController::Bubble::Bubble(MaximizeBubbleController* owner)
// Recalculate size with new border.
SizeToContents();
StartFade(true);
if (!appearance_delay_ms_)
Show();
else
StartFade(true);
mouse_watcher_.reset(new views::MouseWatcher(
new BubbleMouseWatcherHost(this),
......@@ -519,7 +542,10 @@ void MaximizeBubbleController::Bubble::ControllerRequestsCloseAndDelete() {
// Close the widget asynchronously after the hide animation is finished.
initial_position_ = bubble_widget_->GetNativeWindow()->bounds();
StartFade(false);
if (!appearance_delay_ms_)
bubble_widget_->Close();
else
StartFade(false);
}
void MaximizeBubbleController::Bubble::SetSnapType(SnapType snap_type) {
......@@ -527,6 +553,11 @@ void MaximizeBubbleController::Bubble::SetSnapType(SnapType snap_type) {
contents_view_->SetSnapType(snap_type);
}
views::CustomButton* MaximizeBubbleController::Bubble::GetButtonForUnitTest(
SnapType state) {
return contents_view_->GetButtonForUnitTest(state);
}
BubbleContentsButtonRow::BubbleContentsButtonRow(
MaximizeBubbleController::Bubble* bubble)
: bubble_(bubble),
......@@ -586,6 +617,21 @@ void BubbleContentsButtonRow::ButtonHovered(BubbleDialogButton* sender) {
bubble_->controller()->OnButtonHover(SNAP_NONE);
}
views::CustomButton* BubbleContentsButtonRow::GetButtonForUnitTest(
SnapType state) {
switch (state) {
case SNAP_LEFT:
return left_button_;
case SNAP_MINIMIZE:
return minimize_button_;
case SNAP_RIGHT:
return right_button_;
default:
NOTREACHED();
return NULL;
}
}
BubbleContentsView::BubbleContentsView(
MaximizeBubbleController::Bubble* bubble)
: bubble_(bubble),
......@@ -647,19 +693,25 @@ void BubbleContentsView::SetSnapType(SnapType snap_type) {
MaximizeBubbleController::MaximizeBubbleController(
FrameMaximizeButton* frame_maximize_button,
bool is_maximized)
bool is_maximized,
int appearance_delay_ms)
: frame_maximize_button_(frame_maximize_button),
bubble_(NULL),
is_maximized_(is_maximized) {
is_maximized_(is_maximized),
appearance_delay_ms_(appearance_delay_ms) {
// Create the task which will create the bubble delayed.
base::OneShotTimer<MaximizeBubbleController>* new_timer =
new base::OneShotTimer<MaximizeBubbleController>();
// Note: Even if there was no delay time given, we need to have a timer.
new_timer->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kBubbleAppearanceDelayMS),
base::TimeDelta::FromMilliseconds(
appearance_delay_ms_ ? appearance_delay_ms_ : 10),
this,
&MaximizeBubbleController::CreateBubble);
timer_.reset(new_timer);
if (!appearance_delay_ms_)
CreateBubble();
}
MaximizeBubbleController::~MaximizeBubbleController() {
......@@ -693,6 +745,11 @@ void MaximizeBubbleController::OnButtonHover(SnapType snap_type) {
frame_maximize_button_->SnapButtonHovered(snap_type);
}
views::CustomButton* MaximizeBubbleController::GetButtonForUnitTest(
SnapType state) {
return bubble_ ? bubble_->GetButtonForUnitTest(state) : NULL;
}
void MaximizeBubbleController::RequestDestructionThroughOwner() {
// Tell the parent to destroy us (if this didn't happen yet).
if (timer_.get()) {
......@@ -705,7 +762,7 @@ void MaximizeBubbleController::RequestDestructionThroughOwner() {
void MaximizeBubbleController::CreateBubble() {
if (!bubble_)
bubble_ = new Bubble(this);
bubble_ = new Bubble(this, appearance_delay_ms_);
timer_->Stop();
}
......@@ -740,4 +797,20 @@ void BubbleDialogButton::OnMouseExited(const ui::MouseEvent& event) {
views::ImageButton::OnMouseExited(event);
}
bool BubbleDialogButton::OnMouseDragged(const ui::MouseEvent& event) {
if (!button_row_->bubble()->controller())
return false;
// Remove the phantom window when we leave the button.
gfx::Point screen_location(event.location());
View::ConvertPointToScreen(this, &screen_location);
if (!GetBoundsInScreen().Contains(screen_location))
button_row_->ButtonHovered(NULL);
else
button_row_->ButtonHovered(this);
// Pass the event on to the normal handler.
return views::ImageButton::OnMouseDragged(event);
}
} // namespace ash
......@@ -9,12 +9,16 @@
#include "ash/wm/workspace/snap_types.h"
#include "base/memory/scoped_ptr.h"
namespace aura {
class Window;
}
namespace base {
class Timer;
}
namespace aura {
class Window;
namespace views {
class CustomButton;
}
namespace ash {
......@@ -27,7 +31,8 @@ class ASH_EXPORT MaximizeBubbleController {
class Bubble;
MaximizeBubbleController(FrameMaximizeButton* frame_maximize_button,
bool is_maximized);
bool is_maximized,
int appearance_delay_ms);
// Called from the outside to destroy the interface to the UI visuals.
// The visuals will then delete when possible (maybe asynchronously).
virtual ~MaximizeBubbleController();
......@@ -58,6 +63,10 @@ class ASH_EXPORT MaximizeBubbleController {
// The status of the associated window: Maximized or normal.
bool is_maximized() const { return is_maximized_; }
// A unit test function to return buttons of the sub menu. |state| can be
// either SNAP_LEFT, SNAP_RIGHT or SNAP_MINIMIZE.
views::CustomButton* GetButtonForUnitTest(SnapType state);
protected:
// Called from the the Bubble class to destroy itself: It tells the owning
// object that it will destroy itself asynchronously. The owner will then
......@@ -80,6 +89,9 @@ class ASH_EXPORT MaximizeBubbleController {
// The timer for the delayed creation of the menu.
scoped_ptr<base::Timer> timer_;
// The appearance delay in ms (delay and fade in & fade out delay).
const int appearance_delay_ms_;
DISALLOW_COPY_AND_ASSIGN(MaximizeBubbleController);
};
......
......@@ -32,6 +32,9 @@ namespace {
// Delay before forcing an update of the snap location.
const int kUpdateDelayMS = 400;
// The delay of the bubble appearance.
const int kBubbleAppearanceDelayMS = 200;
}
// EscapeEventFilter is installed on the RootWindow to track when the escape key
......@@ -107,7 +110,8 @@ FrameMaximizeButton::FrameMaximizeButton(views::ButtonListener* listener,
is_snap_enabled_(false),
exceeded_drag_threshold_(false),
window_(NULL),
snap_type_(SNAP_NONE) {
snap_type_(SNAP_NONE),
bubble_appearance_delay_ms_(kBubbleAppearanceDelayMS) {
// TODO(sky): nuke this. It's temporary while we don't have good images.
SetImageAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
}
......@@ -202,7 +206,8 @@ void FrameMaximizeButton::OnMouseEntered(const ui::MouseEvent& event) {
}
maximizer_.reset(new MaximizeBubbleController(
this,
frame_->GetWidget()->IsMaximized()));
frame_->GetWidget()->IsMaximized(),
bubble_appearance_delay_ms_));
}
}
......@@ -285,7 +290,8 @@ void FrameMaximizeButton::ProcessStartEvent(const ui::LocatedEvent& event) {
if (!maximizer_.get()) {
maximizer_.reset(new MaximizeBubbleController(
this,
frame_->GetWidget()->IsMaximized()));
frame_->GetWidget()->IsMaximized(),
bubble_appearance_delay_ms_));
} else {
// If the menu did not show up yet, we delay it even a bit more.
maximizer_->DelayCreation();
......
......@@ -63,6 +63,17 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton,
virtual ui::GestureStatus OnGestureEvent(
const views::GestureEvent& event) OVERRIDE;
// Unit test overwrite: Change the UI delay used for the bubble show up.
void set_bubble_appearance_delay_ms(int bubble_appearance_delay_ms) {
bubble_appearance_delay_ms_ = bubble_appearance_delay_ms;
}
// Unit test accessor for the maximize bubble.
MaximizeBubbleController* maximizer() { return maximizer_.get(); }
// Unit test to see if phantom window is open.
bool phantom_window_open() { return phantom_window_.get() != NULL; }
private:
class EscapeEventFilter;
......@@ -136,6 +147,9 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton,
scoped_ptr<MaximizeBubbleController> maximizer_;
// The delay of the bubble appearance.
int bubble_appearance_delay_ms_;
DISALLOW_COPY_AND_ASSIGN(FrameMaximizeButton);
};
......
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