blob: bbd6b4c1e32e4322e051f75143a9195af4d1d0e8 [file] [log] [blame]
// Copyright (c) 2013 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_widget.h"
#include "ash/root_window_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_button.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shelf/shelf_model.h"
#include "ash/shelf/shelf_view.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/shelf_test_api.h"
#include "ash/test/shelf_view_test_api.h"
#include "ash/wm/window_util.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
ShelfWidget* GetShelfWidget() {
return Shelf::ForPrimaryDisplay()->shelf_widget();
}
ShelfLayoutManager* GetShelfLayoutManager() {
return GetShelfWidget()->shelf_layout_manager();
}
} // namespace
typedef test::AshTestBase ShelfWidgetTest;
void TestLauncherAlignment(aura::Window* root,
ShelfAlignment alignment,
const std::string& expected) {
Shell::GetInstance()->SetShelfAlignment(alignment, root);
gfx::Screen* screen = gfx::Screen::GetScreenFor(root);
EXPECT_EQ(expected,
screen->GetDisplayNearestWindow(root).work_area().ToString());
}
TEST_F(ShelfWidgetTest, TestAlignment) {
Shelf* shelf = Shelf::ForPrimaryDisplay();
UpdateDisplay("400x400");
ASSERT_TRUE(shelf);
{
SCOPED_TRACE("Single Bottom");
TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
SHELF_ALIGNMENT_BOTTOM,
"0,0 400x353");
}
{
SCOPED_TRACE("Single Right");
TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
SHELF_ALIGNMENT_RIGHT,
"0,0 353x400");
}
{
SCOPED_TRACE("Single Left");
TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
SHELF_ALIGNMENT_LEFT,
"47,0 353x400");
}
if (!SupportsMultipleDisplays())
return;
UpdateDisplay("300x300,500x500");
aura::Window::Windows root_windows = Shell::GetAllRootWindows();
{
SCOPED_TRACE("Primary Bottom");
TestLauncherAlignment(root_windows[0],
SHELF_ALIGNMENT_BOTTOM,
"0,0 300x253");
}
{
SCOPED_TRACE("Primary Right");
TestLauncherAlignment(root_windows[0],
SHELF_ALIGNMENT_RIGHT,
"0,0 253x300");
}
{
SCOPED_TRACE("Primary Left");
TestLauncherAlignment(root_windows[0],
SHELF_ALIGNMENT_LEFT,
"47,0 253x300");
}
{
SCOPED_TRACE("Secondary Bottom");
TestLauncherAlignment(root_windows[1],
SHELF_ALIGNMENT_BOTTOM,
"300,0 500x453");
}
{
SCOPED_TRACE("Secondary Right");
TestLauncherAlignment(root_windows[1],
SHELF_ALIGNMENT_RIGHT,
"300,0 453x500");
}
{
SCOPED_TRACE("Secondary Left");
TestLauncherAlignment(root_windows[1],
SHELF_ALIGNMENT_LEFT,
"347,0 453x500");
}
}
// Makes sure the shelf is initially sized correctly.
TEST_F(ShelfWidgetTest, LauncherInitiallySized) {
ShelfWidget* shelf_widget = GetShelfWidget();
Shelf* shelf = shelf_widget->shelf();
ASSERT_TRUE(shelf);
ShelfLayoutManager* shelf_layout_manager = GetShelfLayoutManager();
ASSERT_TRUE(shelf_layout_manager);
ASSERT_TRUE(shelf_widget->status_area_widget());
int status_width = shelf_widget->status_area_widget()->
GetWindowBoundsInScreen().width();
// Test only makes sense if the status is > 0, which it better be.
EXPECT_GT(status_width, 0);
EXPECT_EQ(status_width, shelf_widget->GetContentsView()->width() -
test::ShelfTestAPI(shelf).shelf_view()->width());
}
// Verifies when the shell is deleted with a full screen window we don't crash.
TEST_F(ShelfWidgetTest, DontReferenceShelfAfterDeletion) {
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->SetFullscreen(true);
}
#if defined(OS_CHROMEOS)
// Verifies shelf is created with correct size after user login and when its
// container and status widget has finished sizing.
// See http://crbug.com/252533
TEST_F(ShelfWidgetTest, ShelfInitiallySizedAfterLogin) {
SetUserLoggedIn(false);
UpdateDisplay("300x200,400x300");
ShelfWidget* shelf_widget = NULL;
Shell::RootWindowControllerList controllers(
Shell::GetAllRootWindowControllers());
for (Shell::RootWindowControllerList::const_iterator i = controllers.begin();
i != controllers.end();
++i) {
if (!(*i)->shelf()->shelf()) {
shelf_widget = (*i)->shelf();
break;
}
}
ASSERT_TRUE(shelf_widget != NULL);
SetUserLoggedIn(true);
Shell::GetInstance()->CreateShelf();
Shelf* shelf = shelf_widget->shelf();
ASSERT_TRUE(shelf != NULL);
const int status_width =
shelf_widget->status_area_widget()->GetWindowBoundsInScreen().width();
EXPECT_GT(status_width, 0);
EXPECT_EQ(status_width,
shelf_widget->GetContentsView()->width() -
test::ShelfTestAPI(shelf).shelf_view()->width());
}
#endif // defined(OS_CHROMEOS)
// Tests that the shelf lets mouse-events close to the edge fall through to the
// window underneath.
TEST_F(ShelfWidgetTest, ShelfEdgeOverlappingWindowHitTestMouse) {
ShelfWidget* shelf_widget = GetShelfWidget();
gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
EXPECT_TRUE(!shelf_bounds.IsEmpty());
ShelfLayoutManager* shelf_layout_manager =
shelf_widget->shelf_layout_manager();
ASSERT_TRUE(shelf_layout_manager);
EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
// Create a Widget which overlaps with the shelf in the top edge.
const int kOverlapSize = 15;
const int kWindowHeight = 200;
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = gfx::Rect(0, shelf_bounds.y() - kWindowHeight + kOverlapSize,
200, kWindowHeight);
params.context = CurrentContext();
// Widget is now owned by the parent window.
widget->Init(params);
widget->Show();
gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
ui::EventTarget* root = widget->GetNativeWindow()->GetRootWindow();
ui::EventTargeter* targeter = root->GetEventTargeter();
{
// Create a mouse-event targetting the top of the shelf widget. The
// window-targeter should find |widget| as the target (instead of the
// shelf).
gfx::Point event_location(20, shelf_bounds.y() + 1);
ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
EXPECT_EQ(widget->GetNativeWindow(), target);
}
// Now auto-hide (hidden) the shelf.
shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
shelf_layout_manager->LayoutShelf();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
EXPECT_TRUE(!shelf_bounds.IsEmpty());
// Move |widget| so it still overlaps the shelf.
widget->SetBounds(gfx::Rect(0, shelf_bounds.y() - kWindowHeight +
kOverlapSize, 200, kWindowHeight));
widget_bounds = widget->GetWindowBoundsInScreen();
EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
{
// Create a mouse-event targetting the top of the shelf widget. This time,
// window-target should find the shelf as the target.
gfx::Point event_location(20, shelf_bounds.y() + 1);
ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
EXPECT_EQ(shelf_widget->GetNativeWindow(), target);
}
}
// Tests that the shelf has a slightly larger hit-region for touch-events when
// it's in the auto-hidden state.
TEST_F(ShelfWidgetTest, HiddenShelfHitTestTouch) {
ShelfWidget* shelf_widget = GetShelfWidget();
gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
EXPECT_TRUE(!shelf_bounds.IsEmpty());
ShelfLayoutManager* shelf_layout_manager =
shelf_widget->shelf_layout_manager();
ASSERT_TRUE(shelf_layout_manager);
EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
// Create a widget to make sure that the shelf does auto-hide.
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();
ui::EventTarget* root = shelf_widget->GetNativeWindow()->GetRootWindow();
ui::EventTargeter* targeter = root->GetEventTargeter();
// Touch just over the shelf. Since the shelf is visible, the window-targeter
// should not find the shelf as the target.
{
gfx::Point event_location(20, shelf_bounds.y() - 1);
ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0,
ui::EventTimeForNow());
EXPECT_NE(shelf_widget->GetNativeWindow(),
targeter->FindTargetForEvent(root, &touch));
}
// Now auto-hide (hidden) the shelf.
shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
shelf_layout_manager->LayoutShelf();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
EXPECT_TRUE(!shelf_bounds.IsEmpty());
// Touch just over the shelf again. This time, the targeter should find the
// shelf as the target.
{
gfx::Point event_location(20, shelf_bounds.y() - 1);
ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0,
ui::EventTimeForNow());
EXPECT_EQ(shelf_widget->GetNativeWindow(),
targeter->FindTargetForEvent(root, &touch));
}
}
} // namespace ash