1 // Copyright (c) 2012 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/wm/panels/panel_layout_manager.h"
7 #include "ash/ash_switches.h"
8 #include "ash/root_window_controller.h"
9 #include "ash/screen_util.h"
10 #include "ash/shelf/shelf.h"
11 #include "ash/shelf/shelf_button.h"
12 #include "ash/shelf/shelf_layout_manager.h"
13 #include "ash/shelf/shelf_model.h"
14 #include "ash/shelf/shelf_types.h"
15 #include "ash/shelf/shelf_util.h"
16 #include "ash/shelf/shelf_view.h"
17 #include "ash/shelf/shelf_widget.h"
18 #include "ash/shell.h"
19 #include "ash/shell_window_ids.h"
20 #include "ash/test/ash_test_base.h"
21 #include "ash/test/shelf_test_api.h"
22 #include "ash/test/shelf_view_test_api.h"
23 #include "ash/test/shell_test_api.h"
24 #include "ash/test/test_shelf_delegate.h"
25 #include "ash/wm/mru_window_tracker.h"
26 #include "ash/wm/window_state.h"
27 #include "ash/wm/window_util.h"
28 #include "base/basictypes.h"
29 #include "base/command_line.h"
30 #include "base/compiler_specific.h"
31 #include "base/i18n/rtl.h"
32 #include "base/run_loop.h"
33 #include "ui/aura/client/aura_constants.h"
34 #include "ui/aura/test/test_windows.h"
35 #include "ui/aura/window.h"
36 #include "ui/aura/window_event_dispatcher.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/events/event_utils.h"
39 #include "ui/events/test/event_generator.h"
40 #include "ui/views/widget/widget.h"
44 using aura::test::WindowIsAbove
;
46 class PanelLayoutManagerTest
: public test::AshTestBase
{
48 PanelLayoutManagerTest() {}
49 ~PanelLayoutManagerTest() override
{}
51 void SetUp() override
{
52 test::AshTestBase::SetUp();
53 ASSERT_TRUE(test::TestShelfDelegate::instance());
55 shelf_view_test_
.reset(new test::ShelfViewTestAPI(
56 GetShelfView(Shelf::ForPrimaryDisplay())));
57 shelf_view_test_
->SetAnimationDuration(1);
60 aura::Window
* CreateNormalWindow(const gfx::Rect
& bounds
) {
61 return CreateTestWindowInShellWithBounds(bounds
);
64 aura::Window
* CreatePanelWindowWithDelegate(aura::WindowDelegate
* delegate
,
65 const gfx::Rect
& bounds
) {
66 aura::Window
* window
= CreateTestWindowInShellWithDelegateAndType(
67 delegate
, ui::wm::WINDOW_TYPE_PANEL
, 0, bounds
);
68 test::TestShelfDelegate
* shelf_delegate
=
69 test::TestShelfDelegate::instance();
70 shelf_delegate
->AddShelfItem(window
);
71 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
75 aura::Window
* CreatePanelWindow(const gfx::Rect
& bounds
) {
76 return CreatePanelWindowWithDelegate(NULL
, bounds
);
79 aura::Window
* GetPanelContainer(aura::Window
* panel
) {
80 return Shell::GetContainer(panel
->GetRootWindow(),
81 kShellWindowId_PanelContainer
);
84 views::Widget
* GetCalloutWidgetForPanel(aura::Window
* panel
) {
85 PanelLayoutManager
* manager
=
86 static_cast<PanelLayoutManager
*>(GetPanelContainer(panel
)->
89 PanelLayoutManager::PanelList::iterator found
= std::find(
90 manager
->panel_windows_
.begin(), manager
->panel_windows_
.end(),
92 DCHECK(found
!= manager
->panel_windows_
.end());
93 DCHECK(found
->callout_widget
);
94 return reinterpret_cast<views::Widget
*>(found
->callout_widget
);
97 void PanelInScreen(aura::Window
* panel
) {
98 gfx::Rect panel_bounds
= panel
->GetBoundsInRootWindow();
99 gfx::Point root_point
= gfx::Point(panel_bounds
.x(), panel_bounds
.y());
100 gfx::Display display
= ScreenUtil::FindDisplayContainingPoint(root_point
);
102 gfx::Rect panel_bounds_in_screen
= panel
->GetBoundsInScreen();
103 gfx::Point screen_bottom_right
= gfx::Point(
104 panel_bounds_in_screen
.right(),
105 panel_bounds_in_screen
.bottom());
106 gfx::Rect display_bounds
= display
.bounds();
107 EXPECT_TRUE(screen_bottom_right
.x() < display_bounds
.width() &&
108 screen_bottom_right
.y() < display_bounds
.height());
111 void PanelsNotOverlapping(aura::Window
* panel1
, aura::Window
* panel2
) {
112 // Waits until all shelf view animations are done.
113 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
114 gfx::Rect window1_bounds
= panel1
->GetBoundsInRootWindow();
115 gfx::Rect window2_bounds
= panel2
->GetBoundsInRootWindow();
117 EXPECT_FALSE(window1_bounds
.Intersects(window2_bounds
));
120 void IsPanelAboveLauncherIcon(const aura::Window
* panel
) {
121 // Waits until all shelf view animations are done.
122 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
124 Shelf
* shelf
= RootWindowController::ForShelf(panel
)->shelf()->shelf();
125 gfx::Rect icon_bounds
= shelf
->GetScreenBoundsOfItemIconForWindow(panel
);
126 ASSERT_FALSE(icon_bounds
.width() == 0 && icon_bounds
.height() == 0);
128 gfx::Rect window_bounds
= panel
->GetBoundsInScreen();
129 ASSERT_LT(icon_bounds
.width(), window_bounds
.width());
130 ASSERT_LT(icon_bounds
.height(), window_bounds
.height());
131 gfx::Rect shelf_bounds
= shelf
->shelf_widget()->GetWindowBoundsInScreen();
132 ShelfAlignment alignment
= GetAlignment(panel
->GetRootWindow());
134 if (IsHorizontal(alignment
)) {
135 // The horizontal bounds of the panel window should contain the bounds of
137 EXPECT_LE(window_bounds
.x(), icon_bounds
.x());
138 EXPECT_GE(window_bounds
.right(), icon_bounds
.right());
140 // The vertical bounds of the panel window should contain the bounds of
142 EXPECT_LE(window_bounds
.y(), icon_bounds
.y());
143 EXPECT_GE(window_bounds
.bottom(), icon_bounds
.bottom());
147 case SHELF_ALIGNMENT_BOTTOM
:
148 EXPECT_EQ(shelf_bounds
.y(), window_bounds
.bottom());
150 case SHELF_ALIGNMENT_LEFT
:
151 EXPECT_EQ(shelf_bounds
.right(), window_bounds
.x());
153 case SHELF_ALIGNMENT_RIGHT
:
154 EXPECT_EQ(shelf_bounds
.x(), window_bounds
.right());
156 case SHELF_ALIGNMENT_TOP
:
157 EXPECT_EQ(shelf_bounds
.bottom(), window_bounds
.y());
162 void IsCalloutAboveLauncherIcon(aura::Window
* panel
) {
163 // Flush the message loop, since callout updates use a delayed task.
164 base::RunLoop().RunUntilIdle();
165 views::Widget
* widget
= GetCalloutWidgetForPanel(panel
);
167 Shelf
* shelf
= RootWindowController::ForShelf(panel
)->shelf()->shelf();
168 gfx::Rect icon_bounds
= shelf
->GetScreenBoundsOfItemIconForWindow(panel
);
169 ASSERT_FALSE(icon_bounds
.IsEmpty());
171 gfx::Rect panel_bounds
= panel
->GetBoundsInScreen();
172 gfx::Rect callout_bounds
= widget
->GetWindowBoundsInScreen();
173 ASSERT_FALSE(icon_bounds
.IsEmpty());
175 EXPECT_TRUE(widget
->IsVisible());
177 ShelfAlignment alignment
= GetAlignment(panel
->GetRootWindow());
179 case SHELF_ALIGNMENT_BOTTOM
:
180 EXPECT_EQ(panel_bounds
.bottom(), callout_bounds
.y());
182 case SHELF_ALIGNMENT_LEFT
:
183 EXPECT_EQ(panel_bounds
.x(), callout_bounds
.right());
185 case SHELF_ALIGNMENT_RIGHT
:
186 EXPECT_EQ(panel_bounds
.right(), callout_bounds
.x());
188 case SHELF_ALIGNMENT_TOP
:
189 EXPECT_EQ(panel_bounds
.y(), callout_bounds
.bottom());
193 if (IsHorizontal(alignment
)) {
194 EXPECT_NEAR(icon_bounds
.CenterPoint().x(),
195 widget
->GetWindowBoundsInScreen().CenterPoint().x(),
198 EXPECT_NEAR(icon_bounds
.CenterPoint().y(),
199 widget
->GetWindowBoundsInScreen().CenterPoint().y(),
204 bool IsPanelCalloutVisible(aura::Window
* panel
) {
205 views::Widget
* widget
= GetCalloutWidgetForPanel(panel
);
206 return widget
->IsVisible();
209 test::ShelfViewTestAPI
* shelf_view_test() {
210 return shelf_view_test_
.get();
213 // Clicks the shelf items on |shelf_view| that is associated with given
215 void ClickShelfItemForWindow(ShelfView
* shelf_view
, aura::Window
* window
) {
216 test::ShelfViewTestAPI
test_api(shelf_view
);
217 test_api
.SetAnimationDuration(1);
218 test_api
.RunMessageLoopUntilAnimationsDone();
219 ShelfModel
* model
= test::ShellTestApi(Shell::GetInstance()).shelf_model();
220 int index
= model
->ItemIndexByID(GetShelfIDForWindow(window
));
221 gfx::Rect bounds
= test_api
.GetButton(index
)->GetBoundsInScreen();
223 ui::test::EventGenerator
& event_generator
= GetEventGenerator();
224 event_generator
.MoveMouseTo(bounds
.CenterPoint());
225 event_generator
.ClickLeftButton();
227 test_api
.RunMessageLoopUntilAnimationsDone();
230 void SetAlignment(aura::Window
* root_window
, ShelfAlignment alignment
) {
231 ash::Shell
* shell
= ash::Shell::GetInstance();
232 shell
->SetShelfAlignment(alignment
, root_window
);
235 ShelfAlignment
GetAlignment(const aura::Window
* root_window
) {
236 ash::Shell
* shell
= ash::Shell::GetInstance();
237 return shell
->GetShelfAlignment(root_window
);
240 void SetShelfAutoHideBehavior(aura::Window
* window
,
241 ShelfAutoHideBehavior behavior
) {
242 ShelfLayoutManager
* shelf
= RootWindowController::ForWindow(window
)
244 ->shelf_layout_manager();
245 shelf
->SetAutoHideBehavior(behavior
);
246 ShelfView
* shelf_view
= GetShelfView(Shelf::ForWindow(window
));
247 test::ShelfViewTestAPI
test_api(shelf_view
);
248 test_api
.RunMessageLoopUntilAnimationsDone();
251 void SetShelfVisibilityState(aura::Window
* window
,
252 ShelfVisibilityState visibility_state
) {
253 ShelfLayoutManager
* shelf
= RootWindowController::ForWindow(window
)
255 ->shelf_layout_manager();
256 shelf
->SetState(visibility_state
);
259 ShelfView
* GetShelfView(Shelf
* shelf
) {
260 return test::ShelfTestAPI(shelf
).shelf_view();
264 scoped_ptr
<test::ShelfViewTestAPI
> shelf_view_test_
;
266 bool IsHorizontal(ShelfAlignment alignment
) {
267 return alignment
== SHELF_ALIGNMENT_BOTTOM
||
268 alignment
== SHELF_ALIGNMENT_TOP
;
271 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTest
);
274 class PanelLayoutManagerTextDirectionTest
275 : public PanelLayoutManagerTest
,
276 public testing::WithParamInterface
<bool> {
278 PanelLayoutManagerTextDirectionTest() : is_rtl_(GetParam()) {}
279 virtual ~PanelLayoutManagerTextDirectionTest() {}
281 void SetUp() override
{
282 original_locale
= l10n_util::GetApplicationLocale(std::string());
284 base::i18n::SetICUDefaultLocale("he");
285 PanelLayoutManagerTest::SetUp();
286 ASSERT_EQ(is_rtl_
, base::i18n::IsRTL());
289 void TearDown() override
{
291 base::i18n::SetICUDefaultLocale(original_locale
);
292 PanelLayoutManagerTest::TearDown();
297 std::string original_locale
;
299 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTextDirectionTest
);
302 // Tests that a created panel window is above the shelf icon in LTR and RTL.
303 TEST_P(PanelLayoutManagerTextDirectionTest
, AddOnePanel
) {
304 gfx::Rect
bounds(0, 0, 201, 201);
305 scoped_ptr
<aura::Window
> window(CreatePanelWindow(bounds
));
306 EXPECT_EQ(GetPanelContainer(window
.get()), window
->parent());
307 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window
.get()));
308 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(window
.get()));
311 // Tests that a created panel window is successfully aligned over a hidden
313 TEST_F(PanelLayoutManagerTest
, PanelAlignsToHiddenLauncherIcon
) {
314 gfx::Rect
bounds(0, 0, 201, 201);
315 SetShelfAutoHideBehavior(Shell::GetPrimaryRootWindow(),
316 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
317 scoped_ptr
<aura::Window
> normal_window(CreateNormalWindow(bounds
));
318 scoped_ptr
<aura::Window
> window(CreatePanelWindow(bounds
));
319 EXPECT_EQ(GetPanelContainer(window
.get()), window
->parent());
320 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window
.get()));
323 TEST_F(PanelLayoutManagerTest
, PanelAlignsToHiddenLauncherIconSecondDisplay
) {
324 if (!SupportsMultipleDisplays())
327 // Keep the displays wide so that shelves have enough space for shelves
329 UpdateDisplay("400x400,600x400");
330 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
332 scoped_ptr
<aura::Window
> normal_window(
333 CreateNormalWindow(gfx::Rect(450, 0, 100, 100)));
334 scoped_ptr
<aura::Window
> panel(CreatePanelWindow(gfx::Rect(400, 0, 50, 50)));
335 EXPECT_EQ(root_windows
[1], panel
->GetRootWindow());
336 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel
.get()));
337 gfx::Rect shelf_visible_position
= panel
->GetBoundsInScreen();
339 SetShelfAutoHideBehavior(root_windows
[1],
340 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
);
341 // Expect the panel X position to remain the same after the shelf is hidden
342 // but the Y to move down.
343 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel
.get()));
344 EXPECT_EQ(shelf_visible_position
.x(), panel
->GetBoundsInScreen().x());
345 EXPECT_GT(panel
->GetBoundsInScreen().y(), shelf_visible_position
.y());
348 // Tests interactions between multiple panels
349 TEST_F(PanelLayoutManagerTest
, MultiplePanelsAreAboveIcons
) {
350 gfx::Rect
odd_bounds(0, 0, 201, 201);
351 gfx::Rect
even_bounds(0, 0, 200, 200);
353 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(odd_bounds
));
354 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1
.get()));
356 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(even_bounds
));
357 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1
.get()));
358 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2
.get()));
360 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(odd_bounds
));
361 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1
.get()));
362 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2
.get()));
363 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3
.get()));
366 TEST_F(PanelLayoutManagerTest
, MultiplePanelStacking
) {
367 gfx::Rect
bounds(0, 0, 201, 201);
368 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
369 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
370 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
372 // Default stacking order.
373 EXPECT_TRUE(WindowIsAbove(w3
.get(), w2
.get()));
374 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
376 // Changing the active window should update the stacking order.
377 wm::ActivateWindow(w1
.get());
378 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
379 EXPECT_TRUE(WindowIsAbove(w1
.get(), w2
.get()));
380 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
382 wm::ActivateWindow(w2
.get());
383 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
384 EXPECT_TRUE(WindowIsAbove(w1
.get(), w3
.get()));
385 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
386 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
388 wm::ActivateWindow(w3
.get());
389 EXPECT_TRUE(WindowIsAbove(w3
.get(), w2
.get()));
390 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
393 TEST_F(PanelLayoutManagerTest
, MultiplePanelStackingVertical
) {
394 // Set shelf to be aligned on the right.
395 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT
);
397 // Size panels in such a way that ordering them by X coordinate would cause
398 // stacking order to be incorrect. Test that stacking order is based on Y.
399 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(gfx::Rect(0, 0, 210, 201)));
400 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(gfx::Rect(0, 0, 220, 201)));
401 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(gfx::Rect(0, 0, 200, 201)));
403 // Default stacking order.
404 EXPECT_TRUE(WindowIsAbove(w3
.get(), w2
.get()));
405 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
407 // Changing the active window should update the stacking order.
408 wm::ActivateWindow(w1
.get());
409 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
410 EXPECT_TRUE(WindowIsAbove(w1
.get(), w2
.get()));
411 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
413 wm::ActivateWindow(w2
.get());
414 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
415 EXPECT_TRUE(WindowIsAbove(w1
.get(), w3
.get()));
416 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
417 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
419 wm::ActivateWindow(w3
.get());
420 EXPECT_TRUE(WindowIsAbove(w3
.get(), w2
.get()));
421 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
424 TEST_F(PanelLayoutManagerTest
, MultiplePanelCallout
) {
425 gfx::Rect
bounds(0, 0, 200, 200);
426 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
427 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
428 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
429 scoped_ptr
<aura::Window
> w4(CreateNormalWindow(gfx::Rect()));
430 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
431 EXPECT_TRUE(IsPanelCalloutVisible(w1
.get()));
432 EXPECT_TRUE(IsPanelCalloutVisible(w2
.get()));
433 EXPECT_TRUE(IsPanelCalloutVisible(w3
.get()));
434 wm::ActivateWindow(w1
.get());
435 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w1
.get()));
436 wm::ActivateWindow(w2
.get());
437 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2
.get()));
438 wm::ActivateWindow(w3
.get());
439 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3
.get()));
440 wm::ActivateWindow(w4
.get());
441 wm::ActivateWindow(w3
.get());
442 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3
.get()));
444 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2
.get()));
447 // Tests removing panels.
448 TEST_F(PanelLayoutManagerTest
, RemoveLeftPanel
) {
449 gfx::Rect
bounds(0, 0, 201, 201);
450 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
451 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
452 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
454 // At this point, windows should be stacked with 1 < 2 < 3
455 wm::ActivateWindow(w1
.get());
456 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
457 // Now, windows should be stacked 1 > 2 > 3
459 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2
.get()));
460 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3
.get()));
461 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
464 TEST_F(PanelLayoutManagerTest
, RemoveMiddlePanel
) {
465 gfx::Rect
bounds(0, 0, 201, 201);
466 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
467 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
468 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
470 // At this point, windows should be stacked with 1 < 2 < 3
471 wm::ActivateWindow(w2
.get());
472 // Windows should be stacked 1 < 2 > 3
474 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1
.get()));
475 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3
.get()));
476 EXPECT_TRUE(WindowIsAbove(w3
.get(), w1
.get()));
479 TEST_F(PanelLayoutManagerTest
, RemoveRightPanel
) {
480 gfx::Rect
bounds(0, 0, 201, 201);
481 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
482 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
483 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
485 // At this point, windows should be stacked with 1 < 2 < 3
486 wm::ActivateWindow(w3
.get());
487 // Order shouldn't change.
489 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1
.get()));
490 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2
.get()));
491 EXPECT_TRUE(WindowIsAbove(w2
.get(), w1
.get()));
494 TEST_F(PanelLayoutManagerTest
, RemoveNonActivePanel
) {
495 gfx::Rect
bounds(0, 0, 201, 201);
496 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
497 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
498 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
500 // At this point, windows should be stacked with 1 < 2 < 3
501 wm::ActivateWindow(w2
.get());
502 // Windows should be stacked 1 < 2 > 3
504 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2
.get()));
505 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3
.get()));
506 EXPECT_TRUE(WindowIsAbove(w2
.get(), w3
.get()));
509 TEST_F(PanelLayoutManagerTest
, SplitView
) {
510 gfx::Rect
bounds(0, 0, 90, 201);
511 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
512 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
514 EXPECT_NO_FATAL_FAILURE(PanelsNotOverlapping(w1
.get(), w2
.get()));
518 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
519 #define MAYBE_SplitViewOverlapWhenLarge DISABLED_SplitViewOverlapWhenLarge
521 #define MAYBE_SplitViewOverlapWhenLarge SplitViewOverlapWhenLarge
524 TEST_F(PanelLayoutManagerTest
, MAYBE_SplitViewOverlapWhenLarge
) {
525 gfx::Rect
bounds(0, 0, 600, 201);
526 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
527 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
529 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w1
.get()));
530 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w2
.get()));
533 TEST_F(PanelLayoutManagerTest
, FanWindows
) {
534 gfx::Rect
bounds(0, 0, 201, 201);
535 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
536 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
537 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(bounds
));
539 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
540 int window_x1
= w1
->GetBoundsInRootWindow().CenterPoint().x();
541 int window_x2
= w2
->GetBoundsInRootWindow().CenterPoint().x();
542 int window_x3
= w3
->GetBoundsInRootWindow().CenterPoint().x();
543 Shelf
* shelf
= Shelf::ForPrimaryDisplay();
544 int icon_x1
= shelf
->GetScreenBoundsOfItemIconForWindow(w1
.get()).x();
545 int icon_x2
= shelf
->GetScreenBoundsOfItemIconForWindow(w2
.get()).x();
546 EXPECT_EQ(window_x2
- window_x1
, window_x3
- window_x2
);
547 int spacing
= window_x2
- window_x1
;
548 EXPECT_GT(spacing
, icon_x2
- icon_x1
);
551 TEST_F(PanelLayoutManagerTest
, FanLargeWindow
) {
552 gfx::Rect
small_bounds(0, 0, 201, 201);
553 gfx::Rect
large_bounds(0, 0, 501, 201);
554 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(small_bounds
));
555 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(large_bounds
));
556 scoped_ptr
<aura::Window
> w3(CreatePanelWindow(small_bounds
));
558 shelf_view_test()->RunMessageLoopUntilAnimationsDone();
559 int window_x1
= w1
->GetBoundsInRootWindow().CenterPoint().x();
560 int window_x2
= w2
->GetBoundsInRootWindow().CenterPoint().x();
561 int window_x3
= w3
->GetBoundsInRootWindow().CenterPoint().x();
562 // The distances may not be equidistant with a large panel but the panels
563 // should be in the correct order with respect to their midpoints.
564 EXPECT_GT(window_x2
, window_x1
);
565 EXPECT_GT(window_x3
, window_x2
);
568 TEST_F(PanelLayoutManagerTest
, MinimizeRestorePanel
) {
569 gfx::Rect
bounds(0, 0, 201, 201);
570 scoped_ptr
<aura::Window
> window(CreatePanelWindow(bounds
));
571 // Activate the window, ensure callout is visible.
572 wm::ActivateWindow(window
.get());
573 RunAllPendingInMessageLoop();
574 EXPECT_TRUE(IsPanelCalloutVisible(window
.get()));
575 // Minimize the panel, callout should be hidden.
576 wm::GetWindowState(window
.get())->Minimize();
577 RunAllPendingInMessageLoop();
578 EXPECT_FALSE(IsPanelCalloutVisible(window
.get()));
579 // Restore the panel; panel should not be activated by default but callout
580 // should be visible.
581 wm::GetWindowState(window
.get())->Unminimize();
582 RunAllPendingInMessageLoop();
583 EXPECT_TRUE(IsPanelCalloutVisible(window
.get()));
584 // Activate the window, ensure callout is visible.
585 wm::ActivateWindow(window
.get());
586 RunAllPendingInMessageLoop();
587 EXPECT_TRUE(IsPanelCalloutVisible(window
.get()));
590 TEST_F(PanelLayoutManagerTest
, PanelMoveBetweenMultipleDisplays
) {
591 if (!SupportsMultipleDisplays())
594 // Keep the displays wide so that shelves have enough space for launcher
596 UpdateDisplay("600x400,600x400");
597 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
599 scoped_ptr
<aura::Window
> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
600 scoped_ptr
<aura::Window
> p2_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
601 scoped_ptr
<aura::Window
> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
602 scoped_ptr
<aura::Window
> p2_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
604 ShelfView
* shelf_view_1st
= GetShelfView(Shelf::ForPrimaryDisplay());
605 ShelfView
* shelf_view_2nd
=
606 GetShelfView(Shelf::ForWindow(root_windows
[1]));
608 EXPECT_EQ(root_windows
[0], p1_d1
->GetRootWindow());
609 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
610 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
611 EXPECT_EQ(root_windows
[1], p2_d2
->GetRootWindow());
613 EXPECT_EQ(kShellWindowId_PanelContainer
, p1_d1
->parent()->id());
614 EXPECT_EQ(kShellWindowId_PanelContainer
, p2_d1
->parent()->id());
615 EXPECT_EQ(kShellWindowId_PanelContainer
, p1_d2
->parent()->id());
616 EXPECT_EQ(kShellWindowId_PanelContainer
, p2_d2
->parent()->id());
618 // Test a panel on 1st display.
619 // Clicking on the same display has no effect.
620 ClickShelfItemForWindow(shelf_view_1st
, p1_d1
.get());
621 EXPECT_EQ(root_windows
[0], p1_d1
->GetRootWindow());
622 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
623 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
624 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
625 EXPECT_FALSE(root_windows
[1]->GetBoundsInScreen().Contains(
626 p1_d1
->GetBoundsInScreen()));
628 // Test if clicking on another display moves the panel to
630 ClickShelfItemForWindow(shelf_view_2nd
, p1_d1
.get());
631 EXPECT_EQ(root_windows
[1], p1_d1
->GetRootWindow());
632 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
633 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
634 EXPECT_EQ(root_windows
[1], p2_d2
->GetRootWindow());
635 EXPECT_TRUE(root_windows
[1]->GetBoundsInScreen().Contains(
636 p1_d1
->GetBoundsInScreen()));
638 // Test a panel on 2nd display.
639 // Clicking on the same display has no effect.
640 ClickShelfItemForWindow(shelf_view_2nd
, p1_d2
.get());
641 EXPECT_EQ(root_windows
[1], p1_d1
->GetRootWindow());
642 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
643 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
644 EXPECT_EQ(root_windows
[1], p2_d2
->GetRootWindow());
645 EXPECT_TRUE(root_windows
[1]->GetBoundsInScreen().Contains(
646 p1_d2
->GetBoundsInScreen()));
648 // Test if clicking on another display moves the panel to
650 ClickShelfItemForWindow(shelf_view_1st
, p1_d2
.get());
651 EXPECT_EQ(root_windows
[1], p1_d1
->GetRootWindow());
652 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
653 EXPECT_EQ(root_windows
[0], p1_d2
->GetRootWindow());
654 EXPECT_EQ(root_windows
[1], p2_d2
->GetRootWindow());
655 EXPECT_TRUE(root_windows
[0]->GetBoundsInScreen().Contains(
656 p1_d2
->GetBoundsInScreen()));
658 // Test if clicking on a previously moved window moves the
659 // panel back to the original display.
660 ClickShelfItemForWindow(shelf_view_1st
, p1_d1
.get());
661 EXPECT_EQ(root_windows
[0], p1_d1
->GetRootWindow());
662 EXPECT_EQ(root_windows
[0], p2_d1
->GetRootWindow());
663 EXPECT_EQ(root_windows
[0], p1_d2
->GetRootWindow());
664 EXPECT_EQ(root_windows
[1], p2_d2
->GetRootWindow());
665 EXPECT_TRUE(root_windows
[0]->GetBoundsInScreen().Contains(
666 p1_d1
->GetBoundsInScreen()));
669 TEST_F(PanelLayoutManagerTest
, PanelAttachPositionMultipleDisplays
) {
670 if (!SupportsMultipleDisplays())
673 // Keep the displays wide so that shelves have enough space for shelf buttons.
674 // Use differently sized displays so the shelf is in a different
675 // position on second display.
676 UpdateDisplay("600x400,600x600");
677 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
679 scoped_ptr
<aura::Window
> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
680 scoped_ptr
<aura::Window
> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
682 EXPECT_EQ(root_windows
[0], p1_d1
->GetRootWindow());
683 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
685 IsPanelAboveLauncherIcon(p1_d1
.get());
686 IsCalloutAboveLauncherIcon(p1_d1
.get());
687 IsPanelAboveLauncherIcon(p1_d2
.get());
688 IsCalloutAboveLauncherIcon(p1_d2
.get());
691 TEST_F(PanelLayoutManagerTest
, PanelAlignmentSecondDisplay
) {
692 if (!SupportsMultipleDisplays())
695 UpdateDisplay("600x400,600x400");
696 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
698 scoped_ptr
<aura::Window
> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
699 EXPECT_EQ(root_windows
[1], p1_d2
->GetRootWindow());
701 IsPanelAboveLauncherIcon(p1_d2
.get());
702 IsCalloutAboveLauncherIcon(p1_d2
.get());
704 SetAlignment(root_windows
[1], SHELF_ALIGNMENT_RIGHT
);
705 IsPanelAboveLauncherIcon(p1_d2
.get());
706 IsCalloutAboveLauncherIcon(p1_d2
.get());
707 SetAlignment(root_windows
[1], SHELF_ALIGNMENT_LEFT
);
708 IsPanelAboveLauncherIcon(p1_d2
.get());
709 IsCalloutAboveLauncherIcon(p1_d2
.get());
710 SetAlignment(root_windows
[1], SHELF_ALIGNMENT_TOP
);
711 IsPanelAboveLauncherIcon(p1_d2
.get());
712 IsCalloutAboveLauncherIcon(p1_d2
.get());
715 TEST_F(PanelLayoutManagerTest
, AlignmentLeft
) {
716 gfx::Rect
bounds(0, 0, 201, 201);
717 scoped_ptr
<aura::Window
> w(CreatePanelWindow(bounds
));
718 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT
);
719 IsPanelAboveLauncherIcon(w
.get());
720 IsCalloutAboveLauncherIcon(w
.get());
723 TEST_F(PanelLayoutManagerTest
, AlignmentRight
) {
724 gfx::Rect
bounds(0, 0, 201, 201);
725 scoped_ptr
<aura::Window
> w(CreatePanelWindow(bounds
));
726 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT
);
727 IsPanelAboveLauncherIcon(w
.get());
728 IsCalloutAboveLauncherIcon(w
.get());
731 TEST_F(PanelLayoutManagerTest
, AlignmentTop
) {
732 gfx::Rect
bounds(0, 0, 201, 201);
733 scoped_ptr
<aura::Window
> w(CreatePanelWindow(bounds
));
734 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP
);
735 IsPanelAboveLauncherIcon(w
.get());
736 IsCalloutAboveLauncherIcon(w
.get());
739 // Tests that panels will hide and restore their state with the shelf visibility
740 // state. This ensures that entering full-screen mode will hide your panels
741 // until you leave it.
742 TEST_F(PanelLayoutManagerTest
, PanelsHideAndRestoreWithShelf
) {
743 gfx::Rect
bounds(0, 0, 201, 201);
745 scoped_ptr
<aura::Window
> w1(CreatePanelWindow(bounds
));
746 scoped_ptr
<aura::Window
> w2(CreatePanelWindow(bounds
));
747 scoped_ptr
<aura::Window
> w3
;
749 wm::GetWindowState(w2
.get())->Minimize();
750 RunAllPendingInMessageLoop();
751 EXPECT_TRUE(w1
->IsVisible());
752 EXPECT_FALSE(w2
->IsVisible());
754 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_HIDDEN
);
755 RunAllPendingInMessageLoop();
757 // w3 is created while in full-screen mode, should only become visible when
758 // we exit fullscreen mode.
759 w3
.reset(CreatePanelWindow(bounds
));
761 EXPECT_FALSE(w1
->IsVisible());
762 EXPECT_FALSE(w2
->IsVisible());
763 EXPECT_FALSE(w3
->IsVisible());
765 // While in full-screen mode, the panel windows should still be in the
766 // switchable window list - http://crbug.com/313919.
767 MruWindowTracker::WindowList switchable_window_list
=
768 Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
769 EXPECT_EQ(3u, switchable_window_list
.size());
770 EXPECT_NE(switchable_window_list
.end(),
771 std::find(switchable_window_list
.begin(), switchable_window_list
.end(),
773 EXPECT_NE(switchable_window_list
.end(),
774 std::find(switchable_window_list
.begin(), switchable_window_list
.end(),
776 EXPECT_NE(switchable_window_list
.end(),
777 std::find(switchable_window_list
.begin(), switchable_window_list
.end(),
780 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_VISIBLE
);
781 RunAllPendingInMessageLoop();
783 // Windows should be restored to their prior state.
784 EXPECT_TRUE(w1
->IsVisible());
785 EXPECT_FALSE(w2
->IsVisible());
786 EXPECT_TRUE(w3
->IsVisible());
789 // Verifies that touches along the attached edge of a panel do not
790 // target the panel itself.
791 TEST_F(PanelLayoutManagerTest
, TouchHitTestPanel
) {
792 aura::test::TestWindowDelegate delegate
;
793 scoped_ptr
<aura::Window
> w(
794 CreatePanelWindowWithDelegate(&delegate
, gfx::Rect(0, 0, 200, 200)));
795 ui::EventTarget
* root
= w
->GetRootWindow();
796 ui::EventTargeter
* targeter
= root
->GetEventTargeter();
798 // Note that the constants used in the touch locations below are
799 // arbitrarily-selected small numbers which will ensure the point is
800 // within the default extended region surrounding the panel. This value
802 // kResizeOutsideBoundsSize * kResizeOutsideBoundsScaleForTouch
803 // in src/ash/root_window_controller.cc.
805 // Hit test outside the right edge with a bottom-aligned shelf.
806 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_BOTTOM
);
807 gfx::Rect
bounds(w
->bounds());
808 ui::TouchEvent
touch(ui::ET_TOUCH_PRESSED
,
809 gfx::Point(bounds
.right() + 3, bounds
.y() + 2),
810 0, ui::EventTimeForNow());
811 ui::EventTarget
* target
= targeter
->FindTargetForEvent(root
, &touch
);
812 EXPECT_EQ(w
.get(), target
);
814 // Hit test outside the bottom edge with a bottom-aligned shelf.
815 touch
.set_location(gfx::Point(bounds
.x() + 6, bounds
.bottom() + 5));
816 target
= targeter
->FindTargetForEvent(root
, &touch
);
817 EXPECT_NE(w
.get(), target
);
819 // Hit test outside the bottom edge with a right-aligned shelf.
820 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT
);
821 bounds
= w
->bounds();
822 touch
.set_location(gfx::Point(bounds
.x() + 6, bounds
.bottom() + 5));
823 target
= targeter
->FindTargetForEvent(root
, &touch
);
824 EXPECT_EQ(w
.get(), target
);
826 // Hit test outside the right edge with a right-aligned shelf.
827 touch
.set_location(gfx::Point(bounds
.right() + 3, bounds
.y() + 2));
828 target
= targeter
->FindTargetForEvent(root
, &touch
);
829 EXPECT_NE(w
.get(), target
);
831 // Hit test outside the top edge with a left-aligned shelf.
832 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT
);
833 bounds
= w
->bounds();
834 touch
.set_location(gfx::Point(bounds
.x() + 4, bounds
.y() - 6));
835 target
= targeter
->FindTargetForEvent(root
, &touch
);
836 EXPECT_EQ(w
.get(), target
);
838 // Hit test outside the left edge with a left-aligned shelf.
839 touch
.set_location(gfx::Point(bounds
.x() - 1, bounds
.y() + 5));
840 target
= targeter
->FindTargetForEvent(root
, &touch
);
841 EXPECT_NE(w
.get(), target
);
843 // Hit test outside the left edge with a top-aligned shelf.
844 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP
);
845 bounds
= w
->bounds();
846 touch
.set_location(gfx::Point(bounds
.x() - 1, bounds
.y() + 5));
847 target
= targeter
->FindTargetForEvent(root
, &touch
);
848 EXPECT_EQ(w
.get(), target
);
850 // Hit test outside the top edge with a top-aligned shelf.
851 touch
.set_location(gfx::Point(bounds
.x() + 4, bounds
.y() - 6));
852 target
= targeter
->FindTargetForEvent(root
, &touch
);
853 EXPECT_NE(w
.get(), target
);
856 INSTANTIATE_TEST_CASE_P(LtrRtl
, PanelLayoutManagerTextDirectionTest
,