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 the shelf in both left and bottom
191 const int kOverlapSize
= 15;
192 const int kWindowHeight
= 200;
193 const int kWindowWidth
= 200;
194 views::Widget
* widget
= new views::Widget
;
195 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
196 params
.bounds
= gfx::Rect(shelf_bounds
.height() - kOverlapSize
,
197 shelf_bounds
.y() - kWindowHeight
+ kOverlapSize
,
198 kWindowWidth
, kWindowHeight
);
199 params
.context
= CurrentContext();
200 // Widget is now owned by the parent window.
201 widget
->Init(params
);
203 gfx::Rect widget_bounds
= widget
->GetWindowBoundsInScreen();
204 EXPECT_TRUE(widget_bounds
.Intersects(shelf_bounds
));
206 ui::EventTarget
* root
= widget
->GetNativeWindow()->GetRootWindow();
207 ui::EventTargeter
* targeter
= root
->GetEventTargeter();
209 // Create a mouse-event targeting the top of the shelf widget. The
210 // window-targeter should find |widget| as the target (instead of the
212 gfx::Point
event_location(widget_bounds
.x() + 5, shelf_bounds
.y() + 1);
213 ui::MouseEvent
mouse(ui::ET_MOUSE_MOVED
, event_location
, event_location
,
214 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
215 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &mouse
);
216 EXPECT_EQ(widget
->GetNativeWindow(), target
);
219 // Change shelf alignment to verify that the targeter insets are updated.
220 shelf_layout_manager
->SetAlignment(SHELF_ALIGNMENT_LEFT
);
221 shelf_layout_manager
->LayoutShelf();
222 shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
224 // Create a mouse-event targeting the right edge of the shelf widget. The
225 // window-targeter should find |widget| as the target (instead of the
227 gfx::Point
event_location(shelf_bounds
.right() - 1, widget_bounds
.y() + 5);
228 ui::MouseEvent
mouse(ui::ET_MOUSE_MOVED
, event_location
, event_location
,
229 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
230 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &mouse
);
231 EXPECT_EQ(widget
->GetNativeWindow(), target
);
234 // Now restore shelf alignment (bottom) and auto-hide (hidden) the shelf.
235 shelf_layout_manager
->SetAlignment(SHELF_ALIGNMENT_BOTTOM
);
236 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
237 shelf_layout_manager
->LayoutShelf();
238 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf_layout_manager
->visibility_state());
239 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf_layout_manager
->auto_hide_state());
240 shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
241 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
243 // Move |widget| so it still overlaps the shelf.
244 widget
->SetBounds(gfx::Rect(0,
245 shelf_bounds
.y() - kWindowHeight
+ kOverlapSize
,
246 kWindowWidth
, kWindowHeight
));
247 widget_bounds
= widget
->GetWindowBoundsInScreen();
248 EXPECT_TRUE(widget_bounds
.Intersects(shelf_bounds
));
250 // Create a mouse-event targeting the top of the shelf widget. This time,
251 // window-target should find the shelf as the target.
252 gfx::Point
event_location(widget_bounds
.x() + 5, shelf_bounds
.y() + 1);
253 ui::MouseEvent
mouse(ui::ET_MOUSE_MOVED
, event_location
, event_location
,
254 ui::EventTimeForNow(), ui::EF_NONE
, ui::EF_NONE
);
255 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &mouse
);
256 EXPECT_EQ(shelf_widget
->GetNativeWindow(), target
);
260 // Tests that the shelf has a slightly larger hit-region for touch-events when
261 // it's in the auto-hidden state.
262 TEST_F(ShelfWidgetTest
, HiddenShelfHitTestTouch
) {
263 ShelfWidget
* shelf_widget
= GetShelfWidget();
264 gfx::Rect shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
265 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
266 ShelfLayoutManager
* shelf_layout_manager
=
267 shelf_widget
->shelf_layout_manager();
268 ASSERT_TRUE(shelf_layout_manager
);
269 EXPECT_EQ(SHELF_VISIBLE
, shelf_layout_manager
->visibility_state());
271 // Create a widget to make sure that the shelf does auto-hide.
272 views::Widget
* widget
= new views::Widget
;
273 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
274 params
.bounds
= gfx::Rect(0, 0, 200, 200);
275 params
.context
= CurrentContext();
276 // Widget is now owned by the parent window.
277 widget
->Init(params
);
280 ui::EventTarget
* root
= shelf_widget
->GetNativeWindow()->GetRootWindow();
281 ui::EventTargeter
* targeter
= root
->GetEventTargeter();
282 // Touch just over the shelf. Since the shelf is visible, the window-targeter
283 // should not find the shelf as the target.
285 gfx::Point
event_location(20, shelf_bounds
.y() - 1);
286 ui::TouchEvent
touch(ui::ET_TOUCH_PRESSED
, event_location
, 0,
287 ui::EventTimeForNow());
288 EXPECT_NE(shelf_widget
->GetNativeWindow(),
289 targeter
->FindTargetForEvent(root
, &touch
));
292 // Now auto-hide (hidden) the shelf.
293 shelf_layout_manager
->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
294 shelf_layout_manager
->LayoutShelf();
295 EXPECT_EQ(SHELF_AUTO_HIDE
, shelf_layout_manager
->visibility_state());
296 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN
, shelf_layout_manager
->auto_hide_state());
297 shelf_bounds
= shelf_widget
->GetWindowBoundsInScreen();
298 EXPECT_TRUE(!shelf_bounds
.IsEmpty());
300 // Touch just over the shelf again. This time, the targeter should find the
301 // shelf as the target.
303 gfx::Point
event_location(20, shelf_bounds
.y() - 1);
304 ui::TouchEvent
touch(ui::ET_TOUCH_PRESSED
, event_location
, 0,
305 ui::EventTimeForNow());
306 EXPECT_EQ(shelf_widget
->GetNativeWindow(),
307 targeter
->FindTargetForEvent(root
, &touch
));