// 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/shelf/shelf_layout_manager.h"
#include "ash/accelerators/accelerator_controller.h"
#include "ash/accelerators/accelerator_table.h"
#include "ash/ash_switches.h"
#include "ash/display/display_manager.h"
#include "ash/focus_cycler.h"
#include "ash/launcher/launcher.h"
#include "ash/root_window_controller.h"
#include "ash/screen_ash.h"
#include "ash/session_state_delegate.h"
#include "ash/shelf/shelf_layout_manager_observer.h"
#include "ash/shelf/shelf_view.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/system/status_area_widget.h"
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/launcher_test_api.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/event_generator.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/animation/animation_container_element.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif
namespace ash {
namespace internal {
namespace {
void StepWidgetLayerAnimatorToEnd(views::Widget* widget) {
gfx::AnimationContainerElement* element =
static_cast<gfx::AnimationContainerElement*>(
widget->GetNativeView()->layer()->GetAnimator());
element->Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
}
ShelfWidget* GetShelfWidget() {
return Shell::GetPrimaryRootWindowController()->shelf();
}
ShelfLayoutManager* GetShelfLayoutManager() {
return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
}
SystemTray* GetSystemTray() {
return Shell::GetPrimaryRootWindowController()->GetSystemTray();
}
// Class which waits till the shelf finishes animating to the target size and
// counts the number of animation steps.
class ShelfAnimationWaiter : views::WidgetObserver {
public:
explicit ShelfAnimationWaiter(const gfx::Rect& target_bounds)
: target_bounds_(target_bounds),
animation_steps_(0),
done_waiting_(false) {
GetShelfWidget()->AddObserver(this);
}
virtual ~ShelfAnimationWaiter() {
GetShelfWidget()->RemoveObserver(this);
}
// Wait till the shelf finishes animating to its expected bounds.
void WaitTillDoneAnimating() {
if (IsDoneAnimating())
done_waiting_ = true;
else
base::MessageLoop::current()->Run();
}
// Returns true if the animation has completed and it was valid.
bool WasValidAnimation() const {
return done_waiting_ && animation_steps_ > 0;
}
private:
// Returns true if shelf has finished animating to the target size.
bool IsDoneAnimating() const {
ShelfLayoutManager* layout_manager = GetShelfLayoutManager();
gfx::Rect current_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
int size = layout_manager->PrimaryAxisValue(current_bounds.height(),
current_bounds.width());
int desired_size = layout_manager->PrimaryAxisValue(target_bounds_.height(),
target_bounds_.width());
return (size == desired_size);
}
// views::WidgetObserver override.
virtual void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) OVERRIDE {
if (done_waiting_)
return;
++animation_steps_;
if (IsDoneAnimating()) {
done_waiting_ = true;
base::MessageLoop::current()->Quit();
}
}
gfx::Rect target_bounds_;
int animation_steps_;
bool done_waiting_;
DISALLOW_COPY_AND_ASSIGN(ShelfAnimationWaiter);
};
class ShelfDragCallback {
public:
ShelfDragCallback(const gfx::Rect& not_visible, const gfx::Rect& visible)
: not_visible_bounds_(not_visible),
visible_bounds_(visible),
was_visible_on_drag_start_(false) {
EXPECT_EQ(not_visible_bounds_.bottom(), visible_bounds_.bottom());
}
virtual ~ShelfDragCallback() {
}
void ProcessScroll(ui::EventType type, const gfx::Vector2dF& delta) {
if (GetShelfLayoutManager()->visibility_state() == ash::SHELF_HIDDEN)
return;
if (type == ui::ET_GESTURE_SCROLL_BEGIN) {
scroll_ = gfx::Vector2dF();
was_visible_on_drag_start_ = GetShelfLayoutManager()->IsVisible();
return;
}
// The state of the shelf at the end of the gesture is tested separately.
if (type == ui::ET_GESTURE_SCROLL_END)
return;
if (type == ui::ET_GESTURE_SCROLL_UPDATE)
scroll_.Add(delta);
gfx::Rect shelf_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
if (GetShelfLayoutManager()->IsHorizontalAlignment()) {
EXPECT_EQ(not_visible_bounds_.bottom(), shelf_bounds.bottom());
EXPECT_EQ(visible_bounds_.bottom(), shelf_bounds.bottom());
} else if (SHELF_ALIGNMENT_RIGHT ==
GetShelfLayoutManager()->GetAlignment()){
EXPECT_EQ(not_visible_bounds_.right(), shelf_bounds.right());
EXPECT_EQ(visible_bounds_.right(), shelf_bounds.right());
} else if (SHELF_ALIGNMENT_LEFT ==
GetShelfLayoutManager()->GetAlignment()) {
EXPECT_EQ(not_visible_bounds_.x(), shelf_bounds.x());
EXPECT_EQ(visible_bounds_.x(), shelf_bounds.x());
}
// if the shelf is being dimmed test dimmer bounds as well.
if (GetShelfWidget()->GetDimsShelf())
EXPECT_EQ(GetShelfWidget()->GetWindowBoundsInScreen(),
GetShelfWidget()->GetDimmerBoundsForTest());
// The shelf should never be smaller than the hidden state.
EXPECT_GE(shelf_bounds.height(), not_visible_bounds_.height());
float scroll_delta = GetShelfLayoutManager()->PrimaryAxisValue(
scroll_.y(),
scroll_.x());
bool increasing_drag =
GetShelfLayoutManager()->SelectValueForShelfAlignment(
scroll_delta < 0,
scroll_delta > 0,
scroll_delta < 0,
scroll_delta > 0);
int shelf_size = GetShelfLayoutManager()->PrimaryAxisValue(
shelf_bounds.height(),
shelf_bounds.width());
int visible_bounds_size = GetShelfLayoutManager()->PrimaryAxisValue(
visible_bounds_.height(),
visible_bounds_.width());
int not_visible_bounds_size = GetShelfLayoutManager()->PrimaryAxisValue(
not_visible_bounds_.height(),
not_visible_bounds_.width());
if (was_visible_on_drag_start_) {
if (increasing_drag) {
// If dragging inwards from the visible state, then the shelf should
// increase in size, but not more than the scroll delta.
EXPECT_LE(visible_bounds_size, shelf_size);
EXPECT_LE(abs(shelf_size - visible_bounds_size),
abs(scroll_delta));
} else {
if (shelf_size > not_visible_bounds_size) {
// If dragging outwards from the visible state, then the shelf
// should decrease in size, until it reaches the minimum size.
EXPECT_EQ(shelf_size, visible_bounds_size - abs(scroll_delta));
}
}
} else {
if (fabs(scroll_delta) <
visible_bounds_size - not_visible_bounds_size) {
// Tests that the shelf sticks with the touch point during the drag
// until the shelf is completely visible.
EXPECT_EQ(shelf_size, not_visible_bounds_size + abs(scroll_delta));
} else {
// Tests that after the shelf is completely visible, the shelf starts
// resisting the drag.
EXPECT_LT(shelf_size, not_visible_bounds_size + abs(scroll_delta));
}
}
}
private:
const gfx::Rect not_visible_bounds_;
const gfx::Rect visible_bounds_;
gfx::Vector2dF scroll_;
bool was_visible_on_drag_start_;
DISALLOW_COPY_AND_ASSIGN(ShelfDragCallback);
};
class ShelfLayoutObserverTest : public ShelfLayoutManagerObserver {
public:
ShelfLayoutObserverTest()
: changed_auto_hide_state_(false) {
}
virtual ~ShelfLayoutObserverTest() {}
bool changed_auto_hide_state() const { return changed_auto_hide_state_; }
private:
virtual void OnAutoHideStateChanged(
ShelfAutoHideState new_state) OVERRIDE {
changed_auto_hide_state_ = true;
}
bool changed_auto_hide_state_;
DISALLOW_COPY_AND_ASSIGN(ShelfLayoutObserverTest);
};
// Trivial item implementation that tracks its views for testing.
class TestItem : public SystemTrayItem {
public:
TestItem()
: SystemTrayItem(GetSystemTray()),
tray_view_(NULL),
default_view_(NULL),
detailed_view_(NULL),
notification_view_(NULL) {}
virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
tray_view_ = new views::View;
// Add a label so it has non-zero width.
tray_view_->SetLayoutManager(new views::FillLayout);
tray_view_->AddChildView(new views::Label(UTF8ToUTF16("Tray")));
return tray_view_;
}
virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
default_view_ = new views::View;
default_view_->SetLayoutManager(new views::FillLayout);
default_view_->AddChildView(new views::Label(UTF8ToUTF16("Default")));
return default_view_;
}
virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
detailed_view_ = new views::View;
detailed_view_->SetLayoutManager(new views::FillLayout);
detailed_view_->AddChildView(new views::Label(UTF8ToUTF16("Detailed")));
return detailed_view_;
}
virtual views::View* CreateNotificationView(
user::LoginStatus status) OVERRIDE {
notification_view_ = new views::View;
return notification_view_;
}
virtual void DestroyTrayView() OVERRIDE {
tray_view_ = NULL;
}
virtual void DestroyDefaultView() OVERRIDE {
default_view_ = NULL;
}
virtual void DestroyDetailedView() OVERRIDE {
detailed_view_ = NULL;
}
virtual void DestroyNotificationView() OVERRIDE {
notification_view_ = NULL;
}
virtual void UpdateAfterLoginStatusChange(
user::LoginStatus status) OVERRIDE {}
views::View* tray_view() const { return tray_view_; }
views::View* default_view() const { return default_view_; }
views::View* detailed_view() const { return detailed_view_; }
views::View* notification_view() const { return notification_view_; }
private:
views::View* tray_view_;
views::View* default_view_;
views::View* detailed_view_;
views::View* notification_view_;
DISALLOW_COPY_AND_ASSIGN(TestItem);
};
} // namespace
class ShelfLayoutManagerTest : public ash::test::AshTestBase {
public:
ShelfLayoutManagerTest() {}
void SetState(ShelfLayoutManager* shelf,
ShelfVisibilityState state) {
shelf->SetState(state);
}
void UpdateAutoHideStateNow() {
GetShelfLayoutManager()->UpdateAutoHideStateNow();
}
aura::Window* CreateTestWindow() {
aura::Window* window = new aura::Window(NULL);
window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
window->SetType(aura::client::WINDOW_TYPE_NORMAL);
window->Init(ui::LAYER_TEXTURED);
ParentWindowInPrimaryRootWindow(window);
return window;
}
views::Widget* CreateTestWidgetWithParams(
const views::Widget::InitParams& params) {
views::Widget* out = new views::Widget;
out->Init(params);
out->Show();
return out;
}
// Create a simple widget attached to the current context (will
// delete on TearDown).
views::Widget* CreateTestWidget() {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
return CreateTestWidgetWithParams(params);
}
// Overridden from AshTestBase:
virtual void SetUp() OVERRIDE {
CommandLine::ForCurrentProcess()->AppendSwitch(
ash::switches::kAshEnableTrayDragging);
test::AshTestBase::SetUp();
}
void RunGestureDragTests(gfx::Vector2d);
private:
DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManagerTest);
};
void ShelfLayoutManagerTest::RunGestureDragTests(gfx::Vector2d delta) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
widget->Init(params);
widget->Show();
widget->Maximize();
aura::Window* window = widget->GetNativeWindow();
shelf->LayoutShelf();
gfx::Rect shelf_shown = GetShelfWidget()->GetWindowBoundsInScreen();
gfx::Rect bounds_shelf = window->bounds();
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
shelf->LayoutShelf();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
gfx::Rect bounds_noshelf = window->bounds();
gfx::Rect shelf_hidden = GetShelfWidget()->GetWindowBoundsInScreen();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
shelf->LayoutShelf();
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
const int kNumScrollSteps = 4;
ShelfDragCallback handler(shelf_hidden, shelf_shown);
// Swipe up on the shelf. This should not change any state.
gfx::Point start = GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
gfx::Point end = start + delta;
// Swipe down on the shelf to hide it.
generator.GestureScrollSequenceWithCallback(start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_NE(bounds_shelf.ToString(), window->bounds().ToString());
EXPECT_NE(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up to show the shelf.
generator.GestureScrollSequenceWithCallback(end, start,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(),
GetShelfWidget()->GetWindowBoundsInScreen());
EXPECT_EQ(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up again. The shelf should hide.
end = start - delta;
generator.GestureScrollSequenceWithCallback(start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up yet again to show it.
end = start + delta;
generator.GestureScrollSequenceWithCallback(end, start,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
// Swipe down very little. It shouldn't change any state.
if (GetShelfLayoutManager()->IsHorizontalAlignment())
end.set_y(start.y() + shelf_shown.height() * 3 / 10);
else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment())
end.set_x(start.x() - shelf_shown.width() * 3 / 10);
else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment())
end.set_x(start.x() + shelf_shown.width() * 3 / 10);
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 5);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString());
EXPECT_EQ(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe down again to hide.
end = start + delta;
generator.GestureScrollSequenceWithCallback(start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect());
EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up in extended hit region to show it.
gfx::Point extended_start = start;
if (GetShelfLayoutManager()->IsHorizontalAlignment())
extended_start.set_y(GetShelfWidget()->GetWindowBoundsInScreen().y() -1);
else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment())
extended_start.set_x(
GetShelfWidget()->GetWindowBoundsInScreen().right() + 1);
else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment())
extended_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().x() - 1);
end = extended_start - delta;
generator.GestureScrollSequenceWithCallback(extended_start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(),
GetShelfWidget()->GetWindowBoundsInScreen());
EXPECT_EQ(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe down again to hide.
end = start + delta;
generator.GestureScrollSequenceWithCallback(start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect());
EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up outside the hit area. This should not change anything.
gfx::Point outside_start = gfx::Point(
(GetShelfWidget()->GetWindowBoundsInScreen().x() +
GetShelfWidget()->GetWindowBoundsInScreen().right())/2,
GetShelfWidget()->GetWindowBoundsInScreen().y() - 50);
end = outside_start + delta;
generator.GestureScrollSequence(outside_start,
end,
base::TimeDelta::FromMilliseconds(10),
kNumScrollSteps);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe up from below the shelf where a bezel would be, this should show the
// shelf.
gfx::Point below_start = start;
if (GetShelfLayoutManager()->IsHorizontalAlignment())
below_start.set_y(GetShelfWidget()->GetWindowBoundsInScreen().bottom() + 1);
else if (SHELF_ALIGNMENT_LEFT == GetShelfLayoutManager()->GetAlignment())
below_start.set_x(
GetShelfWidget()->GetWindowBoundsInScreen().x() - 1);
else if (SHELF_ALIGNMENT_RIGHT == GetShelfLayoutManager()->GetAlignment())
below_start.set_x(GetShelfWidget()->GetWindowBoundsInScreen().right() + 1);
end = below_start - delta;
generator.GestureScrollSequence(below_start,
end,
base::TimeDelta::FromMilliseconds(10),
kNumScrollSteps);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(bounds_shelf.ToString(), window->bounds().ToString());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(),
GetShelfWidget()->GetWindowBoundsInScreen());
EXPECT_EQ(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Swipe down again to hide.
end = start + delta;
generator.GestureScrollSequenceWithCallback(start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(GetShelfWidget()->GetDimmerBoundsForTest(), gfx::Rect());
EXPECT_EQ(bounds_noshelf.ToString(), window->bounds().ToString());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
// Put |widget| into fullscreen. Set the shelf to be auto hidden when |widget|
// is fullscreen. (eg browser immersive fullscreen).
widget->SetFullscreen(true);
wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(false);
shelf->UpdateVisibilityState();
gfx::Rect bounds_fullscreen = window->bounds();
EXPECT_TRUE(widget->IsFullscreen());
EXPECT_NE(bounds_noshelf.ToString(), bounds_fullscreen.ToString());
// Swipe up. This should show the shelf.
end = below_start - delta;
generator.GestureScrollSequenceWithCallback(below_start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, shelf->auto_hide_behavior());
EXPECT_EQ(shelf_shown.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString());
// Swipe up again. This should hide the shelf.
generator.GestureScrollSequenceWithCallback(below_start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(shelf_hidden.ToString(),
GetShelfWidget()->GetWindowBoundsInScreen().ToString());
EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString());
// Set the shelf to be hidden when |widget| is fullscreen. (eg tab fullscreen
// with or without immersive browser fullscreen).
wm::GetWindowState(window)->set_hide_shelf_when_fullscreen(true);
shelf->UpdateVisibilityState();
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
// Swipe-up. This should not change anything.
end = start - delta;
generator.GestureScrollSequenceWithCallback(below_start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
EXPECT_EQ(bounds_fullscreen.ToString(), window->bounds().ToString());
// Close actually, otherwise further event may be affected since widget
// is fullscreen status.
widget->Close();
RunAllPendingInMessageLoop();
// The shelf should be shown because there are no more visible windows.
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
// Swipe-up to hide. This should have no effect because there are no visible
// windows.
end = below_start - delta;
generator.GestureScrollSequenceWithCallback(below_start, end,
base::TimeDelta::FromMilliseconds(10), kNumScrollSteps,
base::Bind(&ShelfDragCallback::ProcessScroll,
base::Unretained(&handler)));
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, shelf->auto_hide_behavior());
}
// Need to be implemented. http://crbug.com/111279.
#if defined(OS_WIN)
#define MAYBE_SetVisible DISABLED_SetVisible
#else
#define MAYBE_SetVisible SetVisible
#endif
// Makes sure SetVisible updates work area and widget appropriately.
TEST_F(ShelfLayoutManagerTest, MAYBE_SetVisible) {
ShelfWidget* shelf = GetShelfWidget();
ShelfLayoutManager* manager = shelf->shelf_layout_manager();
// Force an initial layout.
manager->LayoutShelf();
EXPECT_EQ(SHELF_VISIBLE, manager->visibility_state());
gfx::Rect status_bounds(
shelf->status_area_widget()->GetWindowBoundsInScreen());
gfx::Rect launcher_bounds(
shelf->GetWindowBoundsInScreen());
int shelf_height = manager->GetIdealBounds().height();
gfx::Screen* screen = Shell::GetScreen();
gfx::Display display = screen->GetDisplayNearestWindow(
Shell::GetPrimaryRootWindow());
ASSERT_NE(-1, display.id());
// Bottom inset should be the max of widget heights.
EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom());
// Hide the shelf.
SetState(manager, SHELF_HIDDEN);
// Run the animation to completion.
StepWidgetLayerAnimatorToEnd(shelf);
StepWidgetLayerAnimatorToEnd(shelf->status_area_widget());
EXPECT_EQ(SHELF_HIDDEN, manager->visibility_state());
display = screen->GetDisplayNearestWindow(
Shell::GetPrimaryRootWindow());
EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
// Make sure the bounds of the two widgets changed.
EXPECT_GE(shelf->GetNativeView()->bounds().y(),
screen->GetPrimaryDisplay().bounds().bottom());
EXPECT_GE(shelf->status_area_widget()->GetNativeView()->bounds().y(),
screen->GetPrimaryDisplay().bounds().bottom());
// And show it again.
SetState(manager, SHELF_VISIBLE);
// Run the animation to completion.
StepWidgetLayerAnimatorToEnd(shelf);
StepWidgetLayerAnimatorToEnd(shelf->status_area_widget());
EXPECT_EQ(SHELF_VISIBLE, manager->visibility_state());
display = screen->GetDisplayNearestWindow(
Shell::GetPrimaryRootWindow());
EXPECT_EQ(shelf_height, display.GetWorkAreaInsets().bottom());
// Make sure the bounds of the two widgets changed.
launcher_bounds = shelf->GetNativeView()->bounds();
EXPECT_LT(launcher_bounds.y(),
screen->GetPrimaryDisplay().bounds().bottom());
status_bounds = shelf->status_area_widget()->GetNativeView()->bounds();
EXPECT_LT(status_bounds.y(),
screen->GetPrimaryDisplay().bounds().bottom());
}
// Makes sure shelf alignment is correct for lock screen.
TEST_F(ShelfLayoutManagerTest, SideAlignmentInteractionWithLockScreen) {
ShelfLayoutManager* manager = GetShelfWidget()->shelf_layout_manager();
manager->SetAlignment(SHELF_ALIGNMENT_LEFT);
EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment());
Shell::GetInstance()->session_state_delegate()->LockScreen();
EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, manager->GetAlignment());
Shell::GetInstance()->session_state_delegate()->UnlockScreen();
EXPECT_EQ(SHELF_ALIGNMENT_LEFT, manager->GetAlignment());
}
// Makes sure LayoutShelf invoked while animating cleans things up.
TEST_F(ShelfLayoutManagerTest, LayoutShelfWhileAnimating) {
ShelfWidget* shelf = GetShelfWidget();
// Force an initial layout.
shelf->shelf_layout_manager()->LayoutShelf();
EXPECT_EQ(SHELF_VISIBLE, shelf->shelf_layout_manager()->visibility_state());
// Hide the shelf.
SetState(shelf->shelf_layout_manager(), SHELF_HIDDEN);
shelf->shelf_layout_manager()->LayoutShelf();
EXPECT_EQ(SHELF_HIDDEN, shelf->shelf_layout_manager()->visibility_state());
gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
Shell::GetPrimaryRootWindow());
EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
// Make sure the bounds of the two widgets changed.
EXPECT_GE(shelf->GetNativeView()->bounds().y(),
Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom());
EXPECT_GE(shelf->status_area_widget()->GetNativeView()->bounds().y(),
Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom());
}
// Test that switching to a different visibility state does not restart the
// shelf show / hide animation if it is already running. (crbug.com/250918)
TEST_F(ShelfLayoutManagerTest, SetStateWhileAnimating) {
ShelfWidget* shelf = GetShelfWidget();
SetState(shelf->shelf_layout_manager(), SHELF_VISIBLE);
gfx::Rect initial_shelf_bounds = shelf->GetWindowBoundsInScreen();
gfx::Rect initial_status_bounds =
shelf->status_area_widget()->GetWindowBoundsInScreen();
ui::ScopedAnimationDurationScaleMode normal_animation_duration(
ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
SetState(shelf->shelf_layout_manager(), SHELF_HIDDEN);
SetState(shelf->shelf_layout_manager(), SHELF_VISIBLE);
gfx::Rect current_shelf_bounds = shelf->GetWindowBoundsInScreen();
gfx::Rect current_status_bounds =
shelf->status_area_widget()->GetWindowBoundsInScreen();
const int small_change = initial_shelf_bounds.height() / 2;
EXPECT_LE(
std::abs(initial_shelf_bounds.height() - current_shelf_bounds.height()),
small_change);
EXPECT_LE(
std::abs(initial_status_bounds.height() - current_status_bounds.height()),
small_change);
}
// Makes sure the launcher is sized when the status area changes size.
TEST_F(ShelfLayoutManagerTest, LauncherUpdatedWhenStatusAreaChangesSize) {
Launcher* launcher = Launcher::ForPrimaryDisplay();
ASSERT_TRUE(launcher);
ShelfWidget* shelf_widget = GetShelfWidget();
ASSERT_TRUE(shelf_widget);
ASSERT_TRUE(shelf_widget->status_area_widget());
shelf_widget->status_area_widget()->SetBounds(
gfx::Rect(0, 0, 200, 200));
EXPECT_EQ(200, shelf_widget->GetContentsView()->width() -
test::LauncherTestAPI(launcher).shelf_view()->width());
}
#if defined(OS_WIN)
// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
#define MAYBE_AutoHide DISABLED_AutoHide
#else
#define MAYBE_AutoHide AutoHide
#endif
// Various assertions around auto-hide.
TEST_F(ShelfLayoutManagerTest, MAYBE_AutoHide) {
aura::Window* root = Shell::GetPrimaryRootWindow();
aura::test::EventGenerator generator(root, root);
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Maximize();
widget->Show();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// LayoutShelf() forces the animation to completion, at which point the
// launcher should go off the screen.
shelf->LayoutShelf();
EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
GetShelfWidget()->GetWindowBoundsInScreen().y());
EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
Shell::GetScreen()->GetDisplayNearestWindow(
root).work_area().bottom());
// Move the mouse to the bottom of the screen.
generator.MoveMouseTo(0, root->bounds().bottom() - 1);
// Shelf should be shown again (but it shouldn't have changed the work area).
SetState(shelf, SHELF_AUTO_HIDE);
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
shelf->LayoutShelf();
EXPECT_EQ(root->bounds().bottom() - shelf->GetIdealBounds().height(),
GetShelfWidget()->GetWindowBoundsInScreen().y());
EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
Shell::GetScreen()->GetDisplayNearestWindow(
root).work_area().bottom());
// Move mouse back up.
generator.MoveMouseTo(0, 0);
SetState(shelf, SHELF_AUTO_HIDE);
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
shelf->LayoutShelf();
EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
GetShelfWidget()->GetWindowBoundsInScreen().y());
// Drag mouse to bottom of screen.
generator.PressLeftButton();
generator.MoveMouseTo(0, root->bounds().bottom() - 1);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
generator.ReleaseLeftButton();
generator.MoveMouseTo(1, root->bounds().bottom() - 1);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
generator.PressLeftButton();
generator.MoveMouseTo(1, root->bounds().bottom() - 1);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
}
// Test the behavior of the shelf when it is auto hidden and it is on the
// boundary between the primary and the secondary display.
TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnScreenBoundary) {
if (!SupportsMultipleDisplays())
return;
UpdateDisplay("800x600,800x600");
DisplayLayout display_layout(DisplayLayout::RIGHT, 0);
Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
display_layout);
// Put the primary monitor's shelf on the display boundary.
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
// Create a window because the shelf is always shown when no windows are
// visible.
CreateTestWidget();
aura::Window::Windows root_windows = Shell::GetAllRootWindows();
ASSERT_EQ(root_windows[0],
GetShelfWidget()->GetNativeWindow()->GetRootWindow());
shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
int right_edge = root_windows[0]->GetBoundsInScreen().right() - 1;
int y = root_windows[0]->GetBoundsInScreen().y();
// Start off the mouse nowhere near the shelf; the shelf should be hidden.
aura::test::EventGenerator& generator(GetEventGenerator());
generator.MoveMouseTo(right_edge - 50, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Moving the mouse over the light bar (but not to the edge of the screen)
// should show the shelf.
generator.MoveMouseTo(right_edge - 1, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
EXPECT_EQ(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x());
// Moving the mouse off the light bar should hide the shelf.
generator.MoveMouseTo(right_edge - 50, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Moving the mouse to the right edge of the screen crossing the light bar
// should show the shelf despite the mouse cursor getting warped to the
// secondary display.
generator.MoveMouseTo(right_edge - 1, y);
generator.MoveMouseTo(right_edge, y);
UpdateAutoHideStateNow();
EXPECT_NE(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Hide the shelf.
generator.MoveMouseTo(right_edge - 50, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Moving the mouse to the right edge of the screen crossing the light bar and
// overshooting by a lot should keep the shelf hidden.
generator.MoveMouseTo(right_edge - 1, y);
generator.MoveMouseTo(right_edge + 50, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Moving the mouse to the right edge of the screen crossing the light bar and
// overshooting a bit should show the shelf.
generator.MoveMouseTo(right_edge - 1, y);
generator.MoveMouseTo(right_edge + 2, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Keeping the mouse close to the left edge of the secondary display after the
// shelf is shown should keep the shelf shown.
generator.MoveMouseTo(right_edge + 2, y + 1);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Moving the mouse far from the left edge of the secondary display should
// hide the shelf.
generator.MoveMouseTo(right_edge + 50, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Moving to the left edge of the secondary display without first crossing
// the primary display's right aligned shelf first should not show the shelf.
generator.MoveMouseTo(right_edge + 2, y);
UpdateAutoHideStateNow();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
}
// Assertions around the lock screen showing.
TEST_F(ShelfLayoutManagerTest, VisibleWhenLockScreenShowing) {
// Since ShelfLayoutManager queries for mouse location, move the mouse so
// it isn't over the shelf.
aura::test::EventGenerator generator(
Shell::GetPrimaryRootWindow(), gfx::Point());
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Maximize();
widget->Show();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
aura::Window* root = Shell::GetPrimaryRootWindow();
// LayoutShelf() forces the animation to completion, at which point the
// launcher should go off the screen.
shelf->LayoutShelf();
EXPECT_EQ(root->bounds().bottom() - ShelfLayoutManager::kAutoHideSize,
GetShelfWidget()->GetWindowBoundsInScreen().y());
aura::Window* lock_container = Shell::GetContainer(
Shell::GetPrimaryRootWindow(),
internal::kShellWindowId_LockScreenContainer);
views::Widget* lock_widget = new views::Widget;
views::Widget::InitParams lock_params(
views::Widget::InitParams::TYPE_WINDOW);
lock_params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
lock_params.parent = lock_container;
// Widget is now owned by the parent window.
lock_widget->Init(lock_params);
lock_widget->Maximize();
lock_widget->Show();
// Lock the screen.
Shell::GetInstance()->session_state_delegate()->LockScreen();
shelf->UpdateVisibilityState();
// Showing a widget in the lock screen should force the shelf to be visibile.
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
Shell::GetInstance()->session_state_delegate()->UnlockScreen();
shelf->UpdateVisibilityState();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
}
// Assertions around SetAutoHideBehavior.
TEST_F(ShelfLayoutManagerTest, SetAutoHideBehavior) {
// Since ShelfLayoutManager queries for mouse location, move the mouse so
// it isn't over the shelf.
aura::test::EventGenerator generator(
Shell::GetPrimaryRootWindow(), gfx::Point());
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Show();
aura::Window* window = widget->GetNativeWindow();
gfx::Rect display_bounds(
Shell::GetScreen()->GetDisplayNearestWindow(window).bounds());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
widget->Maximize();
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
window).work_area().bottom(),
widget->GetWorkAreaBoundsInScreen().bottom());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
window).work_area().bottom(),
widget->GetWorkAreaBoundsInScreen().bottom());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
window).work_area().bottom(),
widget->GetWorkAreaBoundsInScreen().bottom());
}
// Basic assertions around the dimming of the shelf.
TEST_F(ShelfLayoutManagerTest, TestDimmingBehavior) {
// Since ShelfLayoutManager queries for mouse location, move the mouse so
// it isn't over the shelf.
aura::test::EventGenerator generator(
Shell::GetPrimaryRootWindow(), gfx::Point());
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->shelf_widget()->DisableDimmingAnimationsForTest();
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Show();
aura::Window* window = widget->GetNativeWindow();
gfx::Rect display_bounds(
Shell::GetScreen()->GetDisplayNearestWindow(window).bounds());
gfx::Point off_shelf = display_bounds.CenterPoint();
gfx::Point on_shelf =
shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint();
// Test there is no dimming object active at this point.
generator.MoveMouseTo(on_shelf.x(), on_shelf.y());
EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveMouseTo(off_shelf.x(), off_shelf.y());
EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest());
// After maximization, the shelf should be visible and the dimmer created.
widget->Maximize();
on_shelf = shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint();
EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Moving the mouse off the shelf should dim the bar.
generator.MoveMouseTo(off_shelf.x(), off_shelf.y());
EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Adding touch events outside the shelf should still keep the shelf in
// dimmed state.
generator.PressTouch();
generator.MoveTouch(off_shelf);
EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Move the touch into the shelf area should undim.
generator.MoveTouch(on_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.ReleaseTouch();
// And a release dims again.
EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Moving the mouse on the shelf should undim the bar.
generator.MoveMouseTo(on_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// No matter what the touch events do, the shelf should stay undimmed.
generator.PressTouch();
generator.MoveTouch(off_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveTouch(on_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveTouch(off_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveTouch(on_shelf);
generator.ReleaseTouch();
// After restore, the dimming object should be deleted again.
widget->Restore();
EXPECT_EQ(-1, shelf->shelf_widget()->GetDimmingAlphaForTest());
}
// Assertions around the dimming of the shelf in conjunction with menus.
TEST_F(ShelfLayoutManagerTest, TestDimmingBehaviorWithMenus) {
// Since ShelfLayoutManager queries for mouse location, move the mouse so
// it isn't over the shelf.
aura::test::EventGenerator generator(
Shell::GetPrimaryRootWindow(), gfx::Point());
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->shelf_widget()->DisableDimmingAnimationsForTest();
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Show();
aura::Window* window = widget->GetNativeWindow();
gfx::Rect display_bounds(
Shell::GetScreen()->GetDisplayNearestWindow(window).bounds());
// After maximization, the shelf should be visible and the dimmer created.
widget->Maximize();
gfx::Point off_shelf = display_bounds.CenterPoint();
gfx::Point on_shelf =
shelf->shelf_widget()->GetWindowBoundsInScreen().CenterPoint();
// Moving the mouse on the shelf should undim the bar.
generator.MoveMouseTo(on_shelf.x(), on_shelf.y());
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Simulate a menu opening.
shelf->shelf_widget()->ForceUndimming(true);
// Moving the mouse off the shelf should not dim the bar.
generator.MoveMouseTo(off_shelf.x(), off_shelf.y());
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// No matter what the touch events do, the shelf should stay undimmed.
generator.PressTouch();
generator.MoveTouch(off_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveTouch(on_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveTouch(off_shelf);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.ReleaseTouch();
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// "Closing the menu" should now turn off the menu since no event is inside
// the shelf any longer.
shelf->shelf_widget()->ForceUndimming(false);
EXPECT_LT(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
// Moving the mouse again on the shelf which should undim the bar again.
// This time we check that the bar stays undimmed when the mouse remains on
// the bar and the "menu gets closed".
generator.MoveMouseTo(on_shelf.x(), on_shelf.y());
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
shelf->shelf_widget()->ForceUndimming(true);
generator.MoveMouseTo(off_shelf.x(), off_shelf.y());
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
generator.MoveMouseTo(on_shelf.x(), on_shelf.y());
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
shelf->shelf_widget()->ForceUndimming(true);
EXPECT_EQ(0, shelf->shelf_widget()->GetDimmingAlphaForTest());
}
// Verifies the shelf is visible when status/launcher is focused.
TEST_F(ShelfLayoutManagerTest, VisibleWhenStatusOrLauncherFocused) {
// Since ShelfLayoutManager queries for mouse location, move the mouse so
// it isn't over the shelf.
aura::test::EventGenerator generator(
Shell::GetPrimaryRootWindow(), gfx::Point());
generator.MoveMouseTo(0, 0);
ShelfLayoutManager* shelf = GetShelfLayoutManager();
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Show();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Focus the launcher. Have to go through the focus cycler as normal focus
// requests to it do nothing.
GetShelfWidget()->GetFocusCycler()->RotateFocus(FocusCycler::FORWARD);
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
widget->Activate();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Trying to activate the status should fail, since we only allow activating
// it when the user is using the keyboard (i.e. through FocusCycler).
GetShelfWidget()->status_area_widget()->Activate();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
GetShelfWidget()->GetFocusCycler()->RotateFocus(FocusCycler::FORWARD);
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
}
// Makes sure shelf will be visible when app list opens as shelf is in
// SHELF_VISIBLE state,and toggling app list won't change shelf
// visibility state.
TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfVisibleState) {
Shell* shell = Shell::GetInstance();
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->LayoutShelf();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
// Create a normal unmaximized windowm shelf should be visible.
aura::Window* window = CreateTestWindow();
window->SetBounds(gfx::Rect(0, 0, 100, 100));
window->Show();
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
// Toggle app list to show, and the shelf stays visible.
shell->ToggleAppList(NULL);
EXPECT_TRUE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
// Toggle app list to hide, and the shelf stays visible.
shell->ToggleAppList(NULL);
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
}
// Makes sure shelf will be shown with SHELF_AUTO_HIDE_SHOWN state
// when app list opens as shelf is in SHELF_AUTO_HIDE state, and
// toggling app list won't change shelf visibility state.
TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfAutoHideState) {
Shell* shell = Shell::GetInstance();
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->LayoutShelf();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
// Create a window and show it in maximized state.
aura::Window* window = CreateTestWindow();
window->SetBounds(gfx::Rect(0, 0, 100, 100));
window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
window->Show();
wm::ActivateWindow(window);
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
// Toggle app list to show.
shell->ToggleAppList(NULL);
// The shelf's auto hide state won't be changed until the timer fires, so
// calling shell->UpdateShelfVisibility() is kind of manually helping it to
// update the state.
shell->UpdateShelfVisibility();
EXPECT_TRUE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Toggle app list to hide.
shell->ToggleAppList(NULL);
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
}
// Makes sure shelf will be hidden when app list opens as shelf is in HIDDEN
// state, and toggling app list won't change shelf visibility state.
TEST_F(ShelfLayoutManagerTest, OpenAppListWithShelfHiddenState) {
Shell* shell = Shell::GetInstance();
ShelfLayoutManager* shelf = GetShelfLayoutManager();
// For shelf to be visible, app list is not open in initial state.
shelf->LayoutShelf();
// Create a window and make it full screen.
aura::Window* window = CreateTestWindow();
window->SetBounds(gfx::Rect(0, 0, 100, 100));
window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
window->Show();
wm::ActivateWindow(window);
// App list and shelf is not shown.
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
// Toggle app list to show.
shell->ToggleAppList(NULL);
EXPECT_TRUE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
// Toggle app list to hide.
shell->ToggleAppList(NULL);
EXPECT_FALSE(shell->GetAppListTargetVisibility());
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
}
// Tests that the shelf is only hidden for a fullscreen window at the front and
// toggles visibility when another window is activated.
TEST_F(ShelfLayoutManagerTest, FullscreenWindowInFrontHidesShelf) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
// Create a window and make it full screen.
aura::Window* window1 = CreateTestWindow();
window1->SetBounds(gfx::Rect(0, 0, 100, 100));
window1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
window1->Show();
aura::Window* window2 = CreateTestWindow();
window2->SetBounds(gfx::Rect(0, 0, 100, 100));
window2->Show();
wm::GetWindowState(window1)->Activate();
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
wm::GetWindowState(window2)->Activate();
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
wm::GetWindowState(window1)->Activate();
EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
}
// Test the behavior of the shelf when a window on one display is fullscreen
// but the other display has the active window.
TEST_F(ShelfLayoutManagerTest, FullscreenWindowOnSecondDisplay) {
if (!SupportsMultipleDisplays())
return;
UpdateDisplay("800x600,800x600");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
aura::Window::Windows root_windows = Shell::GetAllRootWindows();
Shell::RootWindowControllerList root_window_controllers =
Shell::GetAllRootWindowControllers();
// Create windows on either display.
aura::Window* window1 = CreateTestWindow();
window1->SetBoundsInScreen(
gfx::Rect(0, 0, 100, 100),
display_manager->GetDisplayAt(0));
window1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
window1->Show();
aura::Window* window2 = CreateTestWindow();
window2->SetBoundsInScreen(
gfx::Rect(800, 0, 100, 100),
display_manager->GetDisplayAt(1));
window2->Show();
EXPECT_EQ(root_windows[0], window1->GetRootWindow());
EXPECT_EQ(root_windows[1], window2->GetRootWindow());
wm::GetWindowState(window2)->Activate();
EXPECT_EQ(SHELF_HIDDEN,
root_window_controllers[0]->GetShelfLayoutManager()->visibility_state());
EXPECT_EQ(SHELF_VISIBLE,
root_window_controllers[1]->GetShelfLayoutManager()->visibility_state());
}
#if defined(OS_WIN)
// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
#define MAYBE_SetAlignment DISABLED_SetAlignment
#else
#define MAYBE_SetAlignment SetAlignment
#endif
// Tests SHELF_ALIGNMENT_(LEFT, RIGHT, TOP).
TEST_F(ShelfLayoutManagerTest, MAYBE_SetAlignment) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
// Force an initial layout.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
shelf->LayoutShelf();
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
gfx::Rect launcher_bounds(
GetShelfWidget()->GetWindowBoundsInScreen());
const gfx::Screen* screen = Shell::GetScreen();
gfx::Display display =
screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
ASSERT_NE(-1, display.id());
EXPECT_EQ(shelf->GetIdealBounds().width(),
display.GetWorkAreaInsets().left());
EXPECT_GE(
launcher_bounds.width(),
GetShelfWidget()->GetContentsView()->GetPreferredSize().width());
EXPECT_EQ(SHELF_ALIGNMENT_LEFT, GetSystemTray()->shelf_alignment());
StatusAreaWidget* status_area_widget = GetShelfWidget()->status_area_widget();
gfx::Rect status_bounds(status_area_widget->GetWindowBoundsInScreen());
EXPECT_GE(status_bounds.width(),
status_area_widget->GetContentsView()->GetPreferredSize().width());
EXPECT_EQ(shelf->GetIdealBounds().width(),
display.GetWorkAreaInsets().left());
EXPECT_EQ(0, display.GetWorkAreaInsets().top());
EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
EXPECT_EQ(0, display.GetWorkAreaInsets().right());
EXPECT_EQ(display.bounds().x(), launcher_bounds.x());
EXPECT_EQ(display.bounds().y(), launcher_bounds.y());
EXPECT_EQ(display.bounds().height(), launcher_bounds.height());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
display.GetWorkAreaInsets().left());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize, display.work_area().x());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
launcher_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
ASSERT_NE(-1, display.id());
EXPECT_EQ(shelf->GetIdealBounds().width(),
display.GetWorkAreaInsets().right());
EXPECT_GE(launcher_bounds.width(),
GetShelfWidget()->GetContentsView()->GetPreferredSize().width());
EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, GetSystemTray()->shelf_alignment());
status_bounds = gfx::Rect(status_area_widget->GetWindowBoundsInScreen());
EXPECT_GE(status_bounds.width(),
status_area_widget->GetContentsView()->GetPreferredSize().width());
EXPECT_EQ(shelf->GetIdealBounds().width(),
display.GetWorkAreaInsets().right());
EXPECT_EQ(0, display.GetWorkAreaInsets().top());
EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
EXPECT_EQ(0, display.GetWorkAreaInsets().left());
EXPECT_EQ(display.work_area().right(), launcher_bounds.x());
EXPECT_EQ(display.bounds().y(), launcher_bounds.y());
EXPECT_EQ(display.bounds().height(), launcher_bounds.height());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
display.GetWorkAreaInsets().right());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
display.bounds().right() - display.work_area().right());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
shelf->SetAlignment(SHELF_ALIGNMENT_TOP);
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
launcher_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
ASSERT_NE(-1, display.id());
EXPECT_EQ(shelf->GetIdealBounds().height(),
display.GetWorkAreaInsets().top());
EXPECT_GE(launcher_bounds.height(),
GetShelfWidget()->GetContentsView()->GetPreferredSize().height());
EXPECT_EQ(SHELF_ALIGNMENT_TOP, GetSystemTray()->shelf_alignment());
status_bounds = gfx::Rect(status_area_widget->GetWindowBoundsInScreen());
EXPECT_GE(status_bounds.height(),
status_area_widget->GetContentsView()->GetPreferredSize().height());
EXPECT_EQ(shelf->GetIdealBounds().height(),
display.GetWorkAreaInsets().top());
EXPECT_EQ(0, display.GetWorkAreaInsets().right());
EXPECT_EQ(0, display.GetWorkAreaInsets().bottom());
EXPECT_EQ(0, display.GetWorkAreaInsets().left());
EXPECT_EQ(display.work_area().y(), launcher_bounds.bottom());
EXPECT_EQ(display.bounds().x(), launcher_bounds.x());
EXPECT_EQ(display.bounds().width(), launcher_bounds.width());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
display = screen->GetDisplayNearestWindow(Shell::GetPrimaryRootWindow());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
display.GetWorkAreaInsets().top());
EXPECT_EQ(ShelfLayoutManager::kAutoHideSize,
display.work_area().y() - display.bounds().y());
}
#if defined(OS_WIN)
// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
#define MAYBE_GestureDrag DISABLED_GestureDrag
#else
#define MAYBE_GestureDrag GestureDrag
#endif
TEST_F(ShelfLayoutManagerTest, MAYBE_GestureDrag) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
{
SCOPED_TRACE("BOTTOM");
RunGestureDragTests(gfx::Vector2d(0, 120));
}
{
SCOPED_TRACE("LEFT");
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
RunGestureDragTests(gfx::Vector2d(-120, 0));
}
{
SCOPED_TRACE("RIGHT");
shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
RunGestureDragTests(gfx::Vector2d(120, 0));
}
}
TEST_F(ShelfLayoutManagerTest, WindowVisibilityDisablesAutoHide) {
if (!SupportsMultipleDisplays())
return;
UpdateDisplay("800x600,800x600");
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->LayoutShelf();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
// Create a visible window so auto-hide behavior is enforced
views::Widget* dummy = CreateTestWidget();
// Window visible => auto hide behaves normally.
shelf->UpdateVisibilityState();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Window minimized => auto hide disabled.
dummy->Minimize();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Window closed => auto hide disabled.
dummy->CloseNow();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Multiple window test
views::Widget* window1 = CreateTestWidget();
views::Widget* window2 = CreateTestWidget();
// both visible => normal autohide
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// either minimzed => normal autohide
window2->Minimize();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
window2->Restore();
window1->Minimize();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// both minimized => disable auto hide
window2->Minimize();
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Test moving windows to/from other display.
window2->Restore();
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Move to second display.
window2->SetBounds(gfx::Rect(850, 50, 50, 50));
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
// Move back to primary display.
window2->SetBounds(gfx::Rect(50, 50, 50, 50));
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
}
// Test that the shelf animates back to its normal position upon a user
// completing a gesture drag.
TEST_F(ShelfLayoutManagerTest, ShelfAnimatesWhenGestureComplete) {
if (!SupportsHostWindowResize())
return;
// Test the shelf animates back to its original visible bounds when it is
// dragged when there are no visible windows.
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
gfx::Rect visible_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
{
// Enable animations so that we can make sure that they occur.
ui::ScopedAnimationDurationScaleMode regular_animations(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
gfx::Rect shelf_bounds_in_screen =
GetShelfWidget()->GetWindowBoundsInScreen();
gfx::Point start(shelf_bounds_in_screen.CenterPoint());
gfx::Point end(start.x(), shelf_bounds_in_screen.bottom());
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 5);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
ShelfAnimationWaiter waiter(visible_bounds);
// Wait till the animation completes and check that it occurred.
waiter.WaitTillDoneAnimating();
EXPECT_TRUE(waiter.WasValidAnimation());
}
// Create a visible window so auto-hide behavior is enforced.
CreateTestWidget();
// Get the bounds of the shelf when it is hidden.
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
gfx::Rect auto_hidden_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
{
// Enable the animations so that we can make sure they do occur.
ui::ScopedAnimationDurationScaleMode regular_animations(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
gfx::Point start =
GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
gfx::Point end(start.x(), start.y() - 100);
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
// Test that the shelf animates to the visible bounds after a swipe up on
// the auto hidden shelf.
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 1);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
ShelfAnimationWaiter waiter1(visible_bounds);
waiter1.WaitTillDoneAnimating();
EXPECT_TRUE(waiter1.WasValidAnimation());
// Test that the shelf animates to the auto hidden bounds after a swipe up
// on the visible shelf.
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 1);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
ShelfAnimationWaiter waiter2(auto_hidden_bounds);
waiter2.WaitTillDoneAnimating();
EXPECT_TRUE(waiter2.WasValidAnimation());
}
}
TEST_F(ShelfLayoutManagerTest, GestureRevealsTrayBubble) {
if (!SupportsHostWindowResize())
return;
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->LayoutShelf();
// Create a visible window so auto-hide behavior is enforced.
CreateTestWidget();
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
SystemTray* tray = GetSystemTray();
// First, make sure the shelf is visible.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
EXPECT_FALSE(tray->HasSystemBubble());
// Now, drag up on the tray to show the bubble.
gfx::Point start = GetShelfWidget()->status_area_widget()->
GetWindowBoundsInScreen().CenterPoint();
gfx::Point end(start.x(), start.y() - 100);
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 1);
EXPECT_TRUE(tray->HasSystemBubble());
tray->CloseSystemBubble();
RunAllPendingInMessageLoop();
EXPECT_FALSE(tray->HasSystemBubble());
// Drag again, but only a small amount, and slowly. The bubble should not be
// visible.
end.set_y(start.y() - 30);
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(500), 100);
EXPECT_FALSE(tray->HasSystemBubble());
// Now, hide the shelf.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
// Start a drag from the bezel, and drag up to show both the shelf and the
// tray bubble.
start.set_y(start.y() + 100);
end.set_y(start.y() - 400);
generator.GestureScrollSequence(start, end,
base::TimeDelta::FromMilliseconds(10), 1);
EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
EXPECT_TRUE(tray->HasSystemBubble());
}
TEST_F(ShelfLayoutManagerTest, ShelfFlickerOnTrayActivation) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
// Create a visible window so auto-hide behavior is enforced.
CreateTestWidget();
// Turn on auto-hide for the shelf.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
// Show the status menu. That should make the shelf visible again.
Shell::GetInstance()->accelerator_controller()->PerformAction(
SHOW_SYSTEM_TRAY_BUBBLE, ui::Accelerator());
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
EXPECT_TRUE(GetSystemTray()->HasSystemBubble());
}
TEST_F(ShelfLayoutManagerTest, WorkAreaChangeWorkspace) {
// Make sure the shelf is always visible.
ShelfLayoutManager* shelf = GetShelfLayoutManager();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
shelf->LayoutShelf();
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, 0, 200, 200);
params.context = CurrentContext();
views::Widget* widget_one = CreateTestWidgetWithParams(params);
widget_one->Maximize();
views::Widget* widget_two = CreateTestWidgetWithParams(params);
widget_two->Maximize();
widget_two->Activate();
// Both windows are maximized. They should be of the same size.
EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(),
widget_two->GetNativeWindow()->bounds().ToString());
int area_when_shelf_shown =
widget_one->GetNativeWindow()->bounds().size().GetArea();
// Now hide the shelf.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
// Both windows should be resized according to the shelf status.
EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(),
widget_two->GetNativeWindow()->bounds().ToString());
// Resized to small.
EXPECT_LT(area_when_shelf_shown,
widget_one->GetNativeWindow()->bounds().size().GetArea());
// Now show the shelf.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
// Again both windows should be of the same size.
EXPECT_EQ(widget_one->GetNativeWindow()->bounds().ToString(),
widget_two->GetNativeWindow()->bounds().ToString());
EXPECT_EQ(area_when_shelf_shown,
widget_one->GetNativeWindow()->bounds().size().GetArea());
}
// Confirm that the shelf is dimmed only when content is maximized and
// shelf is not autohidden.
TEST_F(ShelfLayoutManagerTest, Dimming) {
GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
scoped_ptr<aura::Window> w1(CreateTestWindow());
w1->Show();
wm::ActivateWindow(w1.get());
// Normal window doesn't dim shelf.
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
ShelfWidget* shelf = GetShelfWidget();
EXPECT_FALSE(shelf->GetDimsShelf());
// Maximized window does.
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
EXPECT_TRUE(shelf->GetDimsShelf());
// Change back to normal stops dimming.
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
EXPECT_FALSE(shelf->GetDimsShelf());
// Changing back to maximized dims again.
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
EXPECT_TRUE(shelf->GetDimsShelf());
// Changing shelf to autohide stops dimming.
GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_FALSE(shelf->GetDimsShelf());
}
// Make sure that the shelf will not hide if the mouse is between a bubble and
// the shelf.
TEST_F(ShelfLayoutManagerTest, BubbleEnlargesShelfMouseHitArea) {
ShelfLayoutManager* shelf = GetShelfLayoutManager();
StatusAreaWidget* status_area_widget =
Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
SystemTray* tray = GetSystemTray();
// Create a visible window so auto-hide behavior is enforced.
CreateTestWidget();
shelf->LayoutShelf();
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
// Make two iterations - first without a message bubble which should make
// the shelf disappear and then with a message bubble which should keep it
// visible.
for (int i = 0; i < 2; i++) {
// Make sure the shelf is visible and position the mouse over it. Then
// allow auto hide.
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
gfx::Point center =
status_area_widget->GetWindowBoundsInScreen().CenterPoint();
generator.MoveMouseTo(center.x(), center.y());
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
EXPECT_TRUE(shelf->IsVisible());
if (!i) {
// In our first iteration we make sure there is no bubble.
tray->CloseSystemBubble();
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
} else {
// In our second iteration we show a bubble.
TestItem *item = new TestItem;
tray->AddTrayItem(item);
tray->ShowNotificationView(item);
EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
}
// Move the pointer over the edge of the shelf.
generator.MoveMouseTo(
center.x(), status_area_widget->GetWindowBoundsInScreen().y() - 8);
shelf->UpdateVisibilityState();
if (i) {
EXPECT_TRUE(shelf->IsVisible());
EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
} else {
EXPECT_FALSE(shelf->IsVisible());
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
}
}
}
TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColor) {
EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType());
scoped_ptr<aura::Window> w1(CreateTestWindow());
w1->Show();
wm::ActivateWindow(w1.get());
EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType());
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType());
scoped_ptr<aura::Window> w2(CreateTestWindow());
w2->Show();
wm::ActivateWindow(w2.get());
// Overlaps with shelf.
w2->SetBounds(GetShelfLayoutManager()->GetIdealBounds());
// Still background is 'maximized'.
EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType());
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType());
w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType());
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType());
w1.reset();
EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget()->GetBackgroundType());
}
// Verify that the shelf doesn't have the opaque background if it's auto-hide
// status.
TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColorAutoHide) {
EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, GetShelfWidget ()->GetBackgroundType());
GetShelfLayoutManager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
scoped_ptr<aura::Window> w1(CreateTestWindow());
w1->Show();
wm::ActivateWindow(w1.get());
EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType());
w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, GetShelfWidget()->GetBackgroundType());
}
#if defined(OS_CHROMEOS)
#define MAYBE_StatusAreaHitBoxCoversEdge StatusAreaHitBoxCoversEdge
#else
#define MAYBE_StatusAreaHitBoxCoversEdge DISABLED_StatusAreaHitBoxCoversEdge
#endif
// Verify the hit bounds of the status area extend to the edge of the shelf.
TEST_F(ShelfLayoutManagerTest, MAYBE_StatusAreaHitBoxCoversEdge) {
UpdateDisplay("400x400");
ShelfLayoutManager* shelf = GetShelfLayoutManager();
StatusAreaWidget* status_area_widget =
Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget();
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
generator.MoveMouseTo(399,399);
// Test bottom right pixel for bottom alignment.
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
// Test bottom right pixel for right alignment.
shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
// Test bottom left pixel for left alignment.
generator.MoveMouseTo(0, 399);
shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_TRUE(status_area_widget->IsMessageBubbleShown());
generator.ClickLeftButton();
EXPECT_FALSE(status_area_widget->IsMessageBubbleShown());
}
} // namespace internal
} // namespace ash