• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ash/shelf/shelf_widget.h"
6 
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"
24 
25 namespace ash {
26 
27 namespace {
28 
GetShelfWidget()29 ShelfWidget* GetShelfWidget() {
30   return Shelf::ForPrimaryDisplay()->shelf_widget();
31 }
32 
GetShelfLayoutManager()33 ShelfLayoutManager* GetShelfLayoutManager() {
34   return GetShelfWidget()->shelf_layout_manager();
35 }
36 
37 } // namespace
38 
39 typedef test::AshTestBase ShelfWidgetTest;
40 
TestLauncherAlignment(aura::Window * root,ShelfAlignment alignment,const std::string & expected)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);
46   EXPECT_EQ(expected,
47             screen->GetDisplayNearestWindow(root).work_area().ToString());
48 }
49 
TEST_F(ShelfWidgetTest,TestAlignment)50 TEST_F(ShelfWidgetTest, TestAlignment) {
51   Shelf* shelf = Shelf::ForPrimaryDisplay();
52   UpdateDisplay("400x400");
53   ASSERT_TRUE(shelf);
54   {
55     SCOPED_TRACE("Single Bottom");
56     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
57                           SHELF_ALIGNMENT_BOTTOM,
58                           "0,0 400x353");
59   }
60   {
61     SCOPED_TRACE("Single Right");
62     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
63                           SHELF_ALIGNMENT_RIGHT,
64                           "0,0 353x400");
65   }
66   {
67     SCOPED_TRACE("Single Left");
68     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
69                           SHELF_ALIGNMENT_LEFT,
70                           "47,0 353x400");
71   }
72   if (!SupportsMultipleDisplays())
73     return;
74 
75   UpdateDisplay("300x300,500x500");
76   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
77   {
78     SCOPED_TRACE("Primary Bottom");
79     TestLauncherAlignment(root_windows[0],
80                           SHELF_ALIGNMENT_BOTTOM,
81                           "0,0 300x253");
82   }
83   {
84     SCOPED_TRACE("Primary Right");
85     TestLauncherAlignment(root_windows[0],
86                           SHELF_ALIGNMENT_RIGHT,
87                           "0,0 253x300");
88   }
89   {
90     SCOPED_TRACE("Primary Left");
91     TestLauncherAlignment(root_windows[0],
92                           SHELF_ALIGNMENT_LEFT,
93                           "47,0 253x300");
94   }
95   {
96     SCOPED_TRACE("Secondary Bottom");
97     TestLauncherAlignment(root_windows[1],
98                           SHELF_ALIGNMENT_BOTTOM,
99                           "300,0 500x453");
100   }
101   {
102     SCOPED_TRACE("Secondary Right");
103     TestLauncherAlignment(root_windows[1],
104                           SHELF_ALIGNMENT_RIGHT,
105                           "300,0 453x500");
106   }
107   {
108     SCOPED_TRACE("Secondary Left");
109     TestLauncherAlignment(root_windows[1],
110                           SHELF_ALIGNMENT_LEFT,
111                           "347,0 453x500");
112   }
113 }
114 
115 // Makes sure the shelf is initially sized correctly.
TEST_F(ShelfWidgetTest,LauncherInitiallySized)116 TEST_F(ShelfWidgetTest, LauncherInitiallySized) {
117   ShelfWidget* shelf_widget = GetShelfWidget();
118   Shelf* shelf = shelf_widget->shelf();
119   ASSERT_TRUE(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());
129 }
130 
131 // Verifies when the shell is deleted with a full screen window we don't crash.
TEST_F(ShelfWidgetTest,DontReferenceShelfAfterDeletion)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);
140 }
141 
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
TEST_F(ShelfWidgetTest,ShelfInitiallySizedAfterLogin)146 TEST_F(ShelfWidgetTest, ShelfInitiallySizedAfterLogin) {
147   SetUserLoggedIn(false);
148   UpdateDisplay("300x200,400x300");
149 
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();
155        ++i) {
156     if (!(*i)->shelf()->shelf()) {
157       shelf_widget = (*i)->shelf();
158       break;
159     }
160   }
161   ASSERT_TRUE(shelf_widget != NULL);
162 
163   SetUserLoggedIn(true);
164   Shell::GetInstance()->CreateShelf();
165 
166   Shelf* shelf = shelf_widget->shelf();
167   ASSERT_TRUE(shelf != NULL);
168 
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());
175 }
176 #endif  // defined(OS_CHROMEOS)
177 
178 // Tests that the shelf lets mouse-events close to the edge fall through to the
179 // window underneath.
TEST_F(ShelfWidgetTest,ShelfEdgeOverlappingWindowHitTestMouse)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());
188 
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,
195                             200, kWindowHeight);
196   params.context = CurrentContext();
197   // Widget is now owned by the parent window.
198   widget->Init(params);
199   widget->Show();
200   gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
201   EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
202 
203 
204   ui::EventTarget* root = widget->GetNativeWindow()->GetRootWindow();
205   ui::EventTargeter* targeter = root->GetEventTargeter();
206   {
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
209     // shelf).
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);
215   }
216 
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());
224 
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));
230   {
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);
238   }
239 }
240 
241 // Tests that the shelf has a slightly larger hit-region for touch-events when
242 // it's in the auto-hidden state.
TEST_F(ShelfWidgetTest,HiddenShelfHitTestTouch)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());
251 
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);
259   widget->Show();
260 
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.
265   {
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));
271   }
272 
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());
280 
281   // Touch just over the shelf again. This time, the targeter should find the
282   // shelf as the target.
283   {
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));
289   }
290 }
291 
292 }  // namespace ash
293