1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/shelf/shelf_widget.h"
7 #include "ash/root_window_controller.h"
8 #include "ash/shelf/shelf.h"
9 #include "ash/shelf/shelf_button.h"
10 #include "ash/shelf/shelf_layout_manager.h"
11 #include "ash/shelf/shelf_model.h"
12 #include "ash/shelf/shelf_view.h"
13 #include "ash/shell.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ash/test/shelf_test_api.h"
16 #include "ash/test/shelf_view_test_api.h"
17 #include "ash/wm/window_util.h"
18 #include "ui/aura/window_event_dispatcher.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/gfx/display.h"
21 #include "ui/gfx/screen.h"
22 #include "ui/views/view.h"
23 #include "ui/views/widget/widget.h"
29 ShelfWidget
* GetShelfWidget() {
30 return Shelf::ForPrimaryDisplay()->shelf_widget();
33 ShelfLayoutManager
* GetShelfLayoutManager() {
34 return GetShelfWidget()->shelf_layout_manager();
39 typedef test::AshTestBase ShelfWidgetTest
;
41 void TestLauncherAlignment(aura::Window
* root
,
42 ShelfAlignment alignment
,
43 const std::string
& expected
) {
44 Shell::GetInstance()->SetShelfAlignment(alignment
, root
);
45 gfx::Screen
* screen
= gfx::Screen::GetScreenFor(root
);
47 screen
->GetDisplayNearestWindow(root
).work_area().ToString());
50 TEST_F(ShelfWidgetTest
, TestAlignment
) {
51 Shelf
* shelf
= Shelf::ForPrimaryDisplay();
52 UpdateDisplay("400x400");
55 SCOPED_TRACE("Single Bottom");
56 TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
57 SHELF_ALIGNMENT_BOTTOM
,
61 SCOPED_TRACE("Single Right");
62 TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
63 SHELF_ALIGNMENT_RIGHT
,
67 SCOPED_TRACE("Single Left");
68 TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
72 if (!SupportsMultipleDisplays())
75 UpdateDisplay("300x300,500x500");
76 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
78 SCOPED_TRACE("Primary Bottom");
79 TestLauncherAlignment(root_windows
[0],
80 SHELF_ALIGNMENT_BOTTOM
,
84 SCOPED_TRACE("Primary Right");
85 TestLauncherAlignment(root_windows
[0],
86 SHELF_ALIGNMENT_RIGHT
,
90 SCOPED_TRACE("Primary Left");
91 TestLauncherAlignment(root_windows
[0],
96 SCOPED_TRACE("Secondary Bottom");
97 TestLauncherAlignment(root_windows
[1],
98 SHELF_ALIGNMENT_BOTTOM
,
102 SCOPED_TRACE("Secondary Right");
103 TestLauncherAlignment(root_windows
[1],
104 SHELF_ALIGNMENT_RIGHT
,
108 SCOPED_TRACE("Secondary Left");
109 TestLauncherAlignment(root_windows
[1],
110 SHELF_ALIGNMENT_LEFT
,
115 // Makes sure the shelf is initially sized correctly.
116 TEST_F(ShelfWidgetTest
, LauncherInitiallySized
) {
117 ShelfWidget
* shelf_widget
= GetShelfWidget();
118 Shelf
* shelf
= shelf_widget
->shelf();
120 ShelfLayoutManager
* shelf_layout_manager
= GetShelfLayoutManager();
121 ASSERT_TRUE(shelf_layout_manager
);
122 ASSERT_TRUE(shelf_widget
->status_area_widget());
123 int status_width
= shelf_widget
->status_area_widget()->
124 GetWindowBoundsInScreen().width();
125 // Test only makes sense if the status is > 0, which it better be.
126 EXPECT_GT(status_width
, 0);
127 EXPECT_EQ(status_width
, shelf_widget
->GetContentsView()->width() -
128 test::ShelfTestAPI(shelf
).shelf_view()->width());
131 // Verifies when the shell is deleted with a full screen window we don't crash.
132 TEST_F(ShelfWidgetTest
, DontReferenceShelfAfterDeletion
) {
133 views::Widget
* widget
= new views::Widget
;
134 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
135 params
.bounds
= gfx::Rect(0, 0, 200, 200);
136 params
.context
= CurrentContext();
137 // Widget is now owned by the parent window.
138 widget
->Init(params
);
139 widget
->SetFullscreen(true);
142 #if defined(OS_CHROMEOS)
143 // Verifies shelf is created with correct size after user login and when its
144 // container and status widget has finished sizing.
145 // See http://crbug.com/252533
146 TEST_F(ShelfWidgetTest
, ShelfInitiallySizedAfterLogin
) {
147 SetUserLoggedIn(false);
148 UpdateDisplay("300x200,400x300");
150 ShelfWidget
* shelf_widget
= NULL
;
151 Shell::RootWindowControllerList
controllers(
152 Shell::GetAllRootWindowControllers());
153 for (Shell::RootWindowControllerList::const_iterator i
= controllers
.begin();
154 i
!= controllers
.end();
156 if (!(*i
)->shelf()->shelf()) {
157 shelf_widget
= (*i
)->shelf();
161 ASSERT_TRUE(shelf_widget
!= NULL
);
163 SetUserLoggedIn(true);
164 Shell::GetInstance()->CreateShelf();
166 Shelf
* shelf
= shelf_widget
->shelf();
167 ASSERT_TRUE(shelf
!= NULL
);
169 const int status_width
=
170 shelf_widget
->status_area_widget()->GetWindowBoundsInScreen().width();
171 EXPECT_GT(status_width
, 0);
172 EXPECT_EQ(status_width
,
173 shelf_widget
->GetContentsView()->width() -
174 test::ShelfTestAPI(shelf
).shelf_view()->width());
176 #endif // defined(OS_CHROMEOS)
178 // Tests that the shelf lets mouse-events close to the edge fall through to the
179 // window underneath.
180 TEST_F(ShelfWidgetTest
, ShelfEdgeOverlappingWindowHitTestMouse
) {
181 ShelfWidget
* shelf_widget
= GetShelfWidget();
182 gfx::Rect shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
183 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
184 ShelfLayoutManager
* shelf_layout_manager
=
185 shelf_widget
->shelf_layout_manager();
186 ASSERT_TRUE(shelf_layout_manager
);
187 EXPECT_EQ(SHELF_VISIBLE
, shelf_layout_manager
->visibility_state());
189 // Create a Widget which overlaps with the shelf in the top edge.
190 const int kOverlapSize
= 15;
191 const int kWindowHeight
= 200;
192 views::Widget
* widget
= new views::Widget
;
193 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
194 params
.bounds
= gfx::Rect(0, shelf_bounds
.y() - kWindowHeight
+ kOverlapSize
,
196 params
.context
= CurrentContext();
197 // Widget is now owned by the parent window.
198 widget
->Init(params
);
200 gfx::Rect widget_bounds
= widget
->GetWindowBoundsInScreen();
201 EXPECT_TRUE(widget_bounds
.Intersects(shelf_bounds
));
204 ui::EventTarget
* root
= widget
->GetNativeWindow()->GetRootWindow();
205 ui::EventTargeter
* targeter
= root
->GetEventTargeter();
207 // Create a mouse-event targetting the top of the shelf widget. The
208 // window-targeter should find |widget| as the target (instead of the
210 gfx::Point
event_location(20, shelf_bounds
.y() + 1);
211 ui::MouseEvent
mouse(ui::ET_MOUSE_MOVED
, event_location
, event_location
,
212 ui::EF_NONE
, ui::EF_NONE
);
213 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &mouse
);
214 EXPECT_EQ(widget
->GetNativeWindow(), target
);
217 // Now auto-hide (hidden) the shelf.
218 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
219 shelf_layout_manager
->LayoutShelf();
220 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf_layout_manager
->visibility_state());
221 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf_layout_manager
->auto_hide_state());
222 shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
223 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
225 // Move |widget| so it still overlaps the shelf.
226 widget
->SetBounds(gfx::Rect(0, shelf_bounds
.y() - kWindowHeight
+
227 kOverlapSize
, 200, kWindowHeight
));
228 widget_bounds
= widget
->GetWindowBoundsInScreen();
229 EXPECT_TRUE(widget_bounds
.Intersects(shelf_bounds
));
231 // Create a mouse-event targetting the top of the shelf widget. This time,
232 // window-target should find the shelf as the target.
233 gfx::Point
event_location(20, shelf_bounds
.y() + 1);
234 ui::MouseEvent
mouse(ui::ET_MOUSE_MOVED
, event_location
, event_location
,
235 ui::EF_NONE
, ui::EF_NONE
);
236 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &mouse
);
237 EXPECT_EQ(shelf_widget
->GetNativeWindow(), target
);
241 // Tests that the shelf has a slightly larger hit-region for touch-events when
242 // it's in the auto-hidden state.
243 TEST_F(ShelfWidgetTest
, HiddenShelfHitTestTouch
) {
244 ShelfWidget
* shelf_widget
= GetShelfWidget();
245 gfx::Rect shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
246 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
247 ShelfLayoutManager
* shelf_layout_manager
=
248 shelf_widget
->shelf_layout_manager();
249 ASSERT_TRUE(shelf_layout_manager
);
250 EXPECT_EQ(SHELF_VISIBLE
, shelf_layout_manager
->visibility_state());
252 // Create a widget to make sure that the shelf does auto-hide.
253 views::Widget
* widget
= new views::Widget
;
254 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
255 params
.bounds
= gfx::Rect(0, 0, 200, 200);
256 params
.context
= CurrentContext();
257 // Widget is now owned by the parent window.
258 widget
->Init(params
);
261 ui::EventTarget
* root
= shelf_widget
->GetNativeWindow()->GetRootWindow();
262 ui::EventTargeter
* targeter
= root
->GetEventTargeter();
263 // Touch just over the shelf. Since the shelf is visible, the window-targeter
264 // should not find the shelf as the target.
266 gfx::Point
event_location(20, shelf_bounds
.y() - 1);
267 ui::TouchEvent
touch(ui::ET_TOUCH_PRESSED
, event_location
, 0,
268 ui::EventTimeForNow());
269 EXPECT_NE(shelf_widget
->GetNativeWindow(),
270 targeter
->FindTargetForEvent(root
, &touch
));
273 // Now auto-hide (hidden) the shelf.
274 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
275 shelf_layout_manager
->LayoutShelf();
276 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf_layout_manager
->visibility_state());
277 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf_layout_manager
->auto_hide_state());
278 shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
279 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
281 // Touch just over the shelf again. This time, the targeter should find the
282 // shelf as the target.
284 gfx::Point
event_location(20, shelf_bounds
.y() - 1);
285 ui::TouchEvent
touch(ui::ET_TOUCH_PRESSED
, event_location
, 0,
286 ui::EventTimeForNow());
287 EXPECT_EQ(shelf_widget
->GetNativeWindow(),
288 targeter
->FindTargetForEvent(root
, &touch
));