panel_layout_manager_unittest.cc revision a3f7b4e666c476898878fa745f637129375cd889
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.
4
5#include "ash/wm/panels/panel_layout_manager.h"
6
7#include "ash/ash_switches.h"
8#include "ash/launcher/launcher.h"
9#include "ash/launcher/launcher_button.h"
10#include "ash/launcher/launcher_model.h"
11#include "ash/launcher/launcher_view.h"
12#include "ash/root_window_controller.h"
13#include "ash/screen_ash.h"
14#include "ash/shelf/shelf_layout_manager.h"
15#include "ash/shelf/shelf_types.h"
16#include "ash/shelf/shelf_widget.h"
17#include "ash/shell.h"
18#include "ash/shell_window_ids.h"
19#include "ash/test/ash_test_base.h"
20#include "ash/test/launcher_view_test_api.h"
21#include "ash/test/shell_test_api.h"
22#include "ash/test/test_launcher_delegate.h"
23#include "ash/wm/window_util.h"
24#include "base/basictypes.h"
25#include "base/command_line.h"
26#include "base/compiler_specific.h"
27#include "base/i18n/rtl.h"
28#include "base/run_loop.h"
29#include "ui/aura/client/aura_constants.h"
30#include "ui/aura/root_window.h"
31#include "ui/aura/test/event_generator.h"
32#include "ui/aura/test/test_windows.h"
33#include "ui/aura/window.h"
34#include "ui/base/l10n/l10n_util.h"
35#include "ui/views/corewm/corewm_switches.h"
36#include "ui/views/widget/widget.h"
37
38namespace ash {
39namespace internal {
40
41using aura::test::WindowIsAbove;
42
43class PanelLayoutManagerTest : public test::AshTestBase {
44 public:
45  PanelLayoutManagerTest() {}
46  virtual ~PanelLayoutManagerTest() {}
47
48  virtual void SetUp() OVERRIDE {
49    test::AshTestBase::SetUp();
50    ASSERT_TRUE(test::TestLauncherDelegate::instance());
51
52    launcher_view_test_.reset(new test::LauncherViewTestAPI(
53        Launcher::ForPrimaryDisplay()->GetLauncherViewForTest()));
54    launcher_view_test_->SetAnimationDuration(1);
55  }
56
57  aura::Window* CreateNormalWindow(const gfx::Rect& bounds) {
58    return CreateTestWindowInShellWithBounds(bounds);
59  }
60
61  aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
62    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
63        NULL,
64        aura::client::WINDOW_TYPE_PANEL,
65        0,
66        bounds);
67    test::TestLauncherDelegate* launcher_delegate =
68        test::TestLauncherDelegate::instance();
69    launcher_delegate->AddLauncherItem(window);
70    PanelLayoutManager* manager =
71        static_cast<PanelLayoutManager*>(GetPanelContainer(window)->
72                                         layout_manager());
73    manager->Relayout();
74    launcher_view_test()->RunMessageLoopUntilAnimationsDone();
75    return window;
76  }
77
78  aura::Window* GetPanelContainer(aura::Window* panel) {
79    return Shell::GetContainer(panel->GetRootWindow(),
80                               internal::kShellWindowId_PanelContainer);
81  }
82
83  views::Widget* GetCalloutWidgetForPanel(aura::Window* panel) {
84    PanelLayoutManager* manager =
85        static_cast<PanelLayoutManager*>(GetPanelContainer(panel)->
86                                         layout_manager());
87    DCHECK(manager);
88    PanelLayoutManager::PanelList::iterator found = std::find(
89        manager->panel_windows_.begin(), manager->panel_windows_.end(),
90        panel);
91    DCHECK(found != manager->panel_windows_.end());
92    DCHECK(found->callout_widget);
93    return reinterpret_cast<views::Widget*>(found->callout_widget);
94  }
95
96  void PanelInScreen(aura::Window* panel) {
97    gfx::Rect panel_bounds = panel->GetBoundsInRootWindow();
98    gfx::Point root_point = gfx::Point(panel_bounds.x(), panel_bounds.y());
99    gfx::Display display = ScreenAsh::FindDisplayContainingPoint(root_point);
100
101    gfx::Rect panel_bounds_in_screen = panel->GetBoundsInScreen();
102    gfx::Point screen_bottom_right = gfx::Point(
103        panel_bounds_in_screen.right(),
104        panel_bounds_in_screen.bottom());
105    gfx::Rect display_bounds = display.bounds();
106    EXPECT_TRUE(screen_bottom_right.x() < display_bounds.width() &&
107                screen_bottom_right.y() < display_bounds.height());
108  }
109
110  void PanelsNotOverlapping(aura::Window* panel1, aura::Window* panel2) {
111    // Waits until all launcher view animations are done.
112    launcher_view_test()->RunMessageLoopUntilAnimationsDone();
113    gfx::Rect window1_bounds = panel1->GetBoundsInRootWindow();
114    gfx::Rect window2_bounds = panel2->GetBoundsInRootWindow();
115
116    EXPECT_FALSE(window1_bounds.Intersects(window2_bounds));
117  }
118
119  // TODO(dcheng): This should be const, but GetScreenBoundsOfItemIconForWindow
120  // takes a non-const Window. We can probably fix that.
121  void IsPanelAboveLauncherIcon(aura::Window* panel) {
122    // Waits until all launcher view animations are done.
123    launcher_view_test()->RunMessageLoopUntilAnimationsDone();
124
125    Launcher* launcher =
126        RootWindowController::ForLauncher(panel)->shelf()->launcher();
127    gfx::Rect icon_bounds = launcher->GetScreenBoundsOfItemIconForWindow(panel);
128    ASSERT_FALSE(icon_bounds.width() == 0 && icon_bounds.height() == 0);
129
130    gfx::Rect window_bounds = panel->GetBoundsInScreen();
131    gfx::Rect launcher_bounds = launcher->shelf_widget()->
132        GetWindowBoundsInScreen();
133    ShelfAlignment alignment = GetAlignment(panel->GetRootWindow());
134
135    if (IsHorizontal(alignment)) {
136      // The horizontal bounds of the panel window should contain the bounds of
137      // the launcher icon.
138      EXPECT_LE(window_bounds.x(), icon_bounds.x());
139      EXPECT_GE(window_bounds.right(), icon_bounds.right());
140    } else {
141      // The vertical bounds of the panel window should contain the bounds of
142      // the launcher icon.
143      EXPECT_LE(window_bounds.y(), icon_bounds.y());
144      EXPECT_GE(window_bounds.bottom(), icon_bounds.bottom());
145    }
146
147    switch (alignment) {
148      case SHELF_ALIGNMENT_BOTTOM:
149        EXPECT_EQ(launcher_bounds.y(), window_bounds.bottom());
150        break;
151      case SHELF_ALIGNMENT_LEFT:
152        EXPECT_EQ(launcher_bounds.right(), window_bounds.x());
153        break;
154      case SHELF_ALIGNMENT_RIGHT:
155        EXPECT_EQ(launcher_bounds.x(), window_bounds.right());
156        break;
157      case SHELF_ALIGNMENT_TOP:
158        EXPECT_EQ(launcher_bounds.bottom(), window_bounds.y());
159        break;
160    }
161  }
162
163  void IsCalloutAboveLauncherIcon(aura::Window* panel) {
164    // Flush the message loop, since callout updates use a delayed task.
165    base::RunLoop().RunUntilIdle();
166    views::Widget* widget = GetCalloutWidgetForPanel(panel);
167
168    Launcher* launcher =
169        RootWindowController::ForLauncher(panel)->shelf()->launcher();
170    gfx::Rect icon_bounds = launcher->GetScreenBoundsOfItemIconForWindow(panel);
171    ASSERT_FALSE(icon_bounds.IsEmpty());
172
173    gfx::Rect panel_bounds = panel->GetBoundsInScreen();
174    gfx::Rect callout_bounds = widget->GetWindowBoundsInScreen();
175    ASSERT_FALSE(icon_bounds.IsEmpty());
176
177    EXPECT_TRUE(widget->IsVisible());
178
179    ShelfAlignment alignment = GetAlignment(panel->GetRootWindow());
180    switch (alignment) {
181      case SHELF_ALIGNMENT_BOTTOM:
182        EXPECT_EQ(panel_bounds.bottom(), callout_bounds.y());
183        break;
184      case SHELF_ALIGNMENT_LEFT:
185        EXPECT_EQ(panel_bounds.x(), callout_bounds.right());
186        break;
187      case SHELF_ALIGNMENT_RIGHT:
188        EXPECT_EQ(panel_bounds.right(), callout_bounds.x());
189        break;
190      case SHELF_ALIGNMENT_TOP:
191        EXPECT_EQ(panel_bounds.y(), callout_bounds.bottom());
192        break;
193    }
194
195    if (IsHorizontal(alignment)) {
196      EXPECT_NEAR(icon_bounds.CenterPoint().x(),
197                  widget->GetWindowBoundsInScreen().CenterPoint().x(),
198                  1);
199    } else {
200      EXPECT_NEAR(icon_bounds.CenterPoint().y(),
201                  widget->GetWindowBoundsInScreen().CenterPoint().y(),
202                  1);
203    }
204  }
205
206  bool IsPanelCalloutVisible(aura::Window* panel) {
207    views::Widget* widget = GetCalloutWidgetForPanel(panel);
208    return widget->IsVisible();
209  }
210
211  test::LauncherViewTestAPI* launcher_view_test() {
212    return launcher_view_test_.get();
213  }
214
215  // Clicks the launcher items on |launcher_view| that is
216  /// associated with given |window|.
217  void ClickLauncherItemForWindow(LauncherView* launcher_view,
218                                  aura::Window* window) {
219    test::LauncherViewTestAPI test_api(launcher_view);
220    test_api.SetAnimationDuration(1);
221    test_api.RunMessageLoopUntilAnimationsDone();
222    LauncherModel* model =
223        test::ShellTestApi(Shell::GetInstance()).launcher_model();
224    test::TestLauncherDelegate* launcher_delegate =
225        test::TestLauncherDelegate::instance();
226    int index = model->ItemIndexByID(launcher_delegate->GetIDByWindow(window));
227    gfx::Rect bounds = test_api.GetButton(index)->GetBoundsInScreen();
228
229    aura::test::EventGenerator& event_generator = GetEventGenerator();
230    event_generator.MoveMouseTo(bounds.CenterPoint());
231    event_generator.ClickLeftButton();
232
233    test_api.RunMessageLoopUntilAnimationsDone();
234  }
235
236  void SetAlignment(aura::RootWindow* root_window, ShelfAlignment alignment) {
237    ash::Shell* shell = ash::Shell::GetInstance();
238    shell->SetShelfAlignment(alignment, root_window);
239  }
240
241  ShelfAlignment GetAlignment(aura::RootWindow* root_window) {
242    ash::Shell* shell = ash::Shell::GetInstance();
243    return shell->GetShelfAlignment(root_window);
244  }
245
246  void SetShelfAutoHideBehavior(aura::Window* window,
247                                ShelfAutoHideBehavior behavior) {
248    internal::ShelfLayoutManager* shelf =
249        RootWindowController::ForWindow(window)->shelf()->
250        shelf_layout_manager();
251    shelf->SetAutoHideBehavior(behavior);
252    LauncherView* launcher_view =
253        Launcher::ForWindow(window)->GetLauncherViewForTest();
254    test::LauncherViewTestAPI test_api(launcher_view);
255    test_api.RunMessageLoopUntilAnimationsDone();
256  }
257
258  void SetShelfVisibilityState(aura::Window* window,
259                               ShelfVisibilityState visibility_state) {
260    internal::ShelfLayoutManager* shelf =
261        RootWindowController::ForWindow(window)->shelf()->
262        shelf_layout_manager();
263    shelf->SetState(visibility_state);
264  }
265
266 private:
267  scoped_ptr<test::LauncherViewTestAPI> launcher_view_test_;
268
269  bool IsHorizontal(ShelfAlignment alignment) {
270    return alignment == SHELF_ALIGNMENT_BOTTOM ||
271           alignment == SHELF_ALIGNMENT_TOP;
272  }
273
274  DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTest);
275};
276
277class PanelLayoutManagerTextDirectionTest
278    : public PanelLayoutManagerTest,
279      public testing::WithParamInterface<bool> {
280 public:
281  PanelLayoutManagerTextDirectionTest() : is_rtl_(GetParam()) {}
282  virtual ~PanelLayoutManagerTextDirectionTest() {}
283
284  virtual void SetUp() OVERRIDE {
285    original_locale = l10n_util::GetApplicationLocale(std::string());
286    if (is_rtl_)
287      base::i18n::SetICUDefaultLocale("he");
288    PanelLayoutManagerTest::SetUp();
289    ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
290  }
291
292  virtual void TearDown() OVERRIDE {
293    if (is_rtl_)
294      base::i18n::SetICUDefaultLocale(original_locale);
295    PanelLayoutManagerTest::TearDown();
296  }
297
298 private:
299  bool is_rtl_;
300  std::string original_locale;
301
302  DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTextDirectionTest);
303};
304
305// Tests that a created panel window is above the launcher icon in LTR and RTL.
306TEST_P(PanelLayoutManagerTextDirectionTest, AddOnePanel) {
307  gfx::Rect bounds(0, 0, 201, 201);
308  scoped_ptr<aura::Window> window(CreatePanelWindow(bounds));
309  EXPECT_EQ(GetPanelContainer(window.get()), window->parent());
310  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get()));
311  EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(window.get()));
312}
313
314// Tests that a created panel window is successfully aligned over a hidden
315// launcher icon.
316TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIcon) {
317  gfx::Rect bounds(0, 0, 201, 201);
318  SetShelfAutoHideBehavior(Shell::GetPrimaryRootWindow(),
319                           SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
320  scoped_ptr<aura::Window> normal_window(CreateNormalWindow(bounds));
321  scoped_ptr<aura::Window> window(CreatePanelWindow(bounds));
322  EXPECT_EQ(GetPanelContainer(window.get()), window->parent());
323  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get()));
324}
325
326TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIconSecondDisplay) {
327  if (!SupportsMultipleDisplays())
328    return;
329
330  // Keep the displays wide so that launchers have enough
331  // space for launcher buttons.
332  UpdateDisplay("400x400,600x400");
333  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
334
335  scoped_ptr<aura::Window> normal_window(
336      CreateNormalWindow(gfx::Rect(450, 0, 100, 100)));
337  scoped_ptr<aura::Window> panel(CreatePanelWindow(gfx::Rect(400, 0, 50, 50)));
338  EXPECT_EQ(root_windows[1], panel->GetRootWindow());
339  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get()));
340  gfx::Rect shelf_visible_position = panel->GetBoundsInScreen();
341
342  SetShelfAutoHideBehavior(root_windows[1],
343                           SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
344  // Expect the panel X position to remain the same after the shelf is hidden
345  // but the Y to move down.
346  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get()));
347  EXPECT_EQ(shelf_visible_position.x(), panel->GetBoundsInScreen().x());
348  EXPECT_GT(panel->GetBoundsInScreen().y(), shelf_visible_position.y());
349}
350
351// Tests interactions between multiple panels
352TEST_F(PanelLayoutManagerTest, MultiplePanelsAreAboveIcons) {
353  gfx::Rect odd_bounds(0, 0, 201, 201);
354  gfx::Rect even_bounds(0, 0, 200, 200);
355
356  scoped_ptr<aura::Window> w1(CreatePanelWindow(odd_bounds));
357  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
358
359  scoped_ptr<aura::Window> w2(CreatePanelWindow(even_bounds));
360  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
361  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
362
363  scoped_ptr<aura::Window> w3(CreatePanelWindow(odd_bounds));
364  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
365  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
366  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
367}
368
369TEST_F(PanelLayoutManagerTest, MultiplePanelStacking) {
370  gfx::Rect bounds(0, 0, 201, 201);
371  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
372  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
373  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
374
375  // Default stacking order.
376  EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
377  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
378
379  // Changing the active window should update the stacking order.
380  wm::ActivateWindow(w1.get());
381  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
382  EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get()));
383  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
384
385  wm::ActivateWindow(w2.get());
386  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
387  EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get()));
388  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
389  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
390
391  wm::ActivateWindow(w3.get());
392  EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
393  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
394}
395
396TEST_F(PanelLayoutManagerTest, MultiplePanelStackingVertical) {
397  // set launcher shelf to be aligned on the right
398  SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT);
399
400  // Size panels in such a way that ordering them by X coordinate would cause
401  // stacking order to be incorrect. Test that stacking order is based on Y.
402  scoped_ptr<aura::Window> w1(CreatePanelWindow(gfx::Rect(0, 0, 210, 201)));
403  scoped_ptr<aura::Window> w2(CreatePanelWindow(gfx::Rect(0, 0, 220, 201)));
404  scoped_ptr<aura::Window> w3(CreatePanelWindow(gfx::Rect(0, 0, 200, 201)));
405
406  // Default stacking order.
407  EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
408  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
409
410  // Changing the active window should update the stacking order.
411  wm::ActivateWindow(w1.get());
412  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
413  EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get()));
414  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
415
416  wm::ActivateWindow(w2.get());
417  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
418  EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get()));
419  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
420  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
421
422  wm::ActivateWindow(w3.get());
423  EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
424  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
425}
426
427TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) {
428  gfx::Rect bounds(0, 0, 200, 200);
429  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
430  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
431  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
432  scoped_ptr<aura::Window> w4(CreateNormalWindow(gfx::Rect()));
433  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
434  EXPECT_TRUE(IsPanelCalloutVisible(w1.get()));
435  EXPECT_TRUE(IsPanelCalloutVisible(w2.get()));
436  EXPECT_TRUE(IsPanelCalloutVisible(w3.get()));
437  wm::ActivateWindow(w1.get());
438  EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w1.get()));
439  wm::ActivateWindow(w2.get());
440  EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get()));
441  wm::ActivateWindow(w3.get());
442  EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get()));
443  wm::ActivateWindow(w4.get());
444  wm::ActivateWindow(w3.get());
445  EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get()));
446  w3.reset();
447  if (views::corewm::UseFocusController())
448    EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get()));
449}
450
451// Tests removing panels.
452TEST_F(PanelLayoutManagerTest, RemoveLeftPanel) {
453  gfx::Rect bounds(0, 0, 201, 201);
454  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
455  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
456  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
457
458  // At this point, windows should be stacked with 1 < 2 < 3
459  wm::ActivateWindow(w1.get());
460  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
461  // Now, windows should be stacked 1 > 2 > 3
462  w1.reset();
463  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
464  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
465  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
466}
467
468TEST_F(PanelLayoutManagerTest, RemoveMiddlePanel) {
469  gfx::Rect bounds(0, 0, 201, 201);
470  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
471  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
472  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
473
474  // At this point, windows should be stacked with 1 < 2 < 3
475  wm::ActivateWindow(w2.get());
476  // Windows should be stacked 1 < 2 > 3
477  w2.reset();
478  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
479  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
480  EXPECT_TRUE(WindowIsAbove(w3.get(), w1.get()));
481}
482
483TEST_F(PanelLayoutManagerTest, RemoveRightPanel) {
484  gfx::Rect bounds(0, 0, 201, 201);
485  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
486  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
487  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
488
489  // At this point, windows should be stacked with 1 < 2 < 3
490  wm::ActivateWindow(w3.get());
491  // Order shouldn't change.
492  w3.reset();
493  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
494  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
495  EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
496}
497
498TEST_F(PanelLayoutManagerTest, RemoveNonActivePanel) {
499  gfx::Rect bounds(0, 0, 201, 201);
500  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
501  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
502  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
503
504  // At this point, windows should be stacked with 1 < 2 < 3
505  wm::ActivateWindow(w2.get());
506  // Windows should be stacked 1 < 2 > 3
507  w1.reset();
508  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
509  EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
510  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
511}
512
513TEST_F(PanelLayoutManagerTest, SplitView) {
514  gfx::Rect bounds(0, 0, 90, 201);
515  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
516  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
517
518  EXPECT_NO_FATAL_FAILURE(PanelsNotOverlapping(w1.get(), w2.get()));
519}
520
521#if defined(OS_WIN)
522// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
523#define MAYBE_SplitViewOverlapWhenLarge DISABLED_SplitViewOverlapWhenLarge
524#else
525#define MAYBE_SplitViewOverlapWhenLarge SplitViewOverlapWhenLarge
526#endif
527
528TEST_F(PanelLayoutManagerTest, MAYBE_SplitViewOverlapWhenLarge) {
529  gfx::Rect bounds(0, 0, 600, 201);
530  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
531  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
532
533  EXPECT_NO_FATAL_FAILURE(PanelInScreen(w1.get()));
534  EXPECT_NO_FATAL_FAILURE(PanelInScreen(w2.get()));
535}
536
537TEST_F(PanelLayoutManagerTest, FanWindows) {
538  gfx::Rect bounds(0, 0, 201, 201);
539  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
540  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
541  scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds));
542
543  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
544  int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x();
545  int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x();
546  int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x();
547  Launcher* launcher = Launcher::ForPrimaryDisplay();
548  int icon_x1 = launcher->GetScreenBoundsOfItemIconForWindow(w1.get()).x();
549  int icon_x2 = launcher->GetScreenBoundsOfItemIconForWindow(w2.get()).x();
550  EXPECT_EQ(window_x2 - window_x1, window_x3 - window_x2);
551  int spacing = window_x2 - window_x1;
552  EXPECT_GT(spacing, icon_x2 - icon_x1);
553}
554
555TEST_F(PanelLayoutManagerTest, FanLargeWindow) {
556  gfx::Rect small_bounds(0, 0, 201, 201);
557  gfx::Rect large_bounds(0, 0, 501, 201);
558  scoped_ptr<aura::Window> w1(CreatePanelWindow(small_bounds));
559  scoped_ptr<aura::Window> w2(CreatePanelWindow(large_bounds));
560  scoped_ptr<aura::Window> w3(CreatePanelWindow(small_bounds));
561
562  launcher_view_test()->RunMessageLoopUntilAnimationsDone();
563  int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x();
564  int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x();
565  int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x();
566  // The distances may not be equidistant with a large panel but the panels
567  // should be in the correct order with respect to their midpoints.
568  EXPECT_GT(window_x2, window_x1);
569  EXPECT_GT(window_x3, window_x2);
570}
571
572TEST_F(PanelLayoutManagerTest, MinimizeRestorePanel) {
573  gfx::Rect bounds(0, 0, 201, 201);
574  scoped_ptr<aura::Window> window(CreatePanelWindow(bounds));
575  // Activate the window, ensure callout is visible.
576  wm::ActivateWindow(window.get());
577  RunAllPendingInMessageLoop();
578  EXPECT_TRUE(IsPanelCalloutVisible(window.get()));
579  // Minimize the panel, callout should be hidden.
580  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
581  RunAllPendingInMessageLoop();
582  EXPECT_FALSE(IsPanelCalloutVisible(window.get()));
583  // Restore the pantel; panel should not be activated by default but callout
584  // should be visible.
585  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
586  RunAllPendingInMessageLoop();
587  EXPECT_TRUE(IsPanelCalloutVisible(window.get()));
588  // Activate the window, ensure callout is visible.
589  wm::ActivateWindow(window.get());
590  RunAllPendingInMessageLoop();
591  EXPECT_TRUE(IsPanelCalloutVisible(window.get()));
592}
593
594TEST_F(PanelLayoutManagerTest, PanelMoveBetweenMultipleDisplays) {
595  if (!SupportsMultipleDisplays())
596    return;
597
598  // Keep the displays wide so that launchers have enough
599  // space for launcher buttons.
600  UpdateDisplay("600x400,600x400");
601  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
602
603  scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
604  scoped_ptr<aura::Window> p2_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
605  scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
606  scoped_ptr<aura::Window> p2_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
607
608  LauncherView* launcher_view_1st =
609      Launcher::ForPrimaryDisplay()->GetLauncherViewForTest();
610  LauncherView* launcher_view_2nd =
611      Launcher::ForWindow(root_windows[1])->GetLauncherViewForTest();
612
613  EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow());
614  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
615  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
616  EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow());
617
618  EXPECT_EQ(internal::kShellWindowId_PanelContainer, p1_d1->parent()->id());
619  EXPECT_EQ(internal::kShellWindowId_PanelContainer, p2_d1->parent()->id());
620  EXPECT_EQ(internal::kShellWindowId_PanelContainer, p1_d2->parent()->id());
621  EXPECT_EQ(internal::kShellWindowId_PanelContainer, p2_d2->parent()->id());
622
623  // Test a panel on 1st display.
624  // Clicking on the same display has no effect.
625  ClickLauncherItemForWindow(launcher_view_1st, p1_d1.get());
626  EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow());
627  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
628  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
629  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
630  EXPECT_FALSE(root_windows[1]->GetBoundsInScreen().Contains(
631      p1_d1->GetBoundsInScreen()));
632
633  // Test if clicking on another display moves the panel to
634  // that display.
635  ClickLauncherItemForWindow(launcher_view_2nd, p1_d1.get());
636  EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow());
637  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
638  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
639  EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow());
640  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
641      p1_d1->GetBoundsInScreen()));
642
643  // Test a panel on 2nd display.
644  // Clicking on the same display has no effect.
645  ClickLauncherItemForWindow(launcher_view_2nd, p1_d2.get());
646  EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow());
647  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
648  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
649  EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow());
650  EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains(
651      p1_d2->GetBoundsInScreen()));
652
653  // Test if clicking on another display moves the panel to
654  // that display.
655  ClickLauncherItemForWindow(launcher_view_1st, p1_d2.get());
656  EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow());
657  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
658  EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow());
659  EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow());
660  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
661      p1_d2->GetBoundsInScreen()));
662
663  // Test if clicking on a previously moved window moves the
664  // panel back to the original display.
665  ClickLauncherItemForWindow(launcher_view_1st, p1_d1.get());
666  EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow());
667  EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow());
668  EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow());
669  EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow());
670  EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains(
671      p1_d1->GetBoundsInScreen()));
672}
673
674TEST_F(PanelLayoutManagerTest, PanelAttachPositionMultipleDisplays) {
675  if (!SupportsMultipleDisplays())
676    return;
677
678  // Keep the displays wide so that launchers have enough space for launcher
679  // buttons. Use differently sized displays so the launcher is in a different
680  // position on second display.
681  UpdateDisplay("600x400,600x600");
682  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
683
684  scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50)));
685  scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
686
687  EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow());
688  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
689
690  IsPanelAboveLauncherIcon(p1_d1.get());
691  IsCalloutAboveLauncherIcon(p1_d1.get());
692  IsPanelAboveLauncherIcon(p1_d2.get());
693  IsCalloutAboveLauncherIcon(p1_d2.get());
694}
695
696TEST_F(PanelLayoutManagerTest, PanelAlignmentSecondDisplay) {
697  if (!SupportsMultipleDisplays())
698    return;
699
700  UpdateDisplay("600x400,600x400");
701  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
702
703  scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
704  EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
705
706  IsPanelAboveLauncherIcon(p1_d2.get());
707  IsCalloutAboveLauncherIcon(p1_d2.get());
708
709  SetAlignment(root_windows[1], SHELF_ALIGNMENT_RIGHT);
710  IsPanelAboveLauncherIcon(p1_d2.get());
711  IsCalloutAboveLauncherIcon(p1_d2.get());
712  SetAlignment(root_windows[1], SHELF_ALIGNMENT_LEFT);
713  IsPanelAboveLauncherIcon(p1_d2.get());
714  IsCalloutAboveLauncherIcon(p1_d2.get());
715  SetAlignment(root_windows[1], SHELF_ALIGNMENT_TOP);
716  IsPanelAboveLauncherIcon(p1_d2.get());
717  IsCalloutAboveLauncherIcon(p1_d2.get());
718}
719
720TEST_F(PanelLayoutManagerTest, AlignmentLeft) {
721  gfx::Rect bounds(0, 0, 201, 201);
722  scoped_ptr<aura::Window> w(CreatePanelWindow(bounds));
723  SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT);
724  IsPanelAboveLauncherIcon(w.get());
725  IsCalloutAboveLauncherIcon(w.get());
726}
727
728TEST_F(PanelLayoutManagerTest, AlignmentRight) {
729  gfx::Rect bounds(0, 0, 201, 201);
730  scoped_ptr<aura::Window> w(CreatePanelWindow(bounds));
731  SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT);
732  IsPanelAboveLauncherIcon(w.get());
733  IsCalloutAboveLauncherIcon(w.get());
734}
735
736TEST_F(PanelLayoutManagerTest, AlignmentTop) {
737  gfx::Rect bounds(0, 0, 201, 201);
738  scoped_ptr<aura::Window> w(CreatePanelWindow(bounds));
739  SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP);
740  IsPanelAboveLauncherIcon(w.get());
741  IsCalloutAboveLauncherIcon(w.get());
742}
743
744// Tests that panels will hide and restore their state with the shelf visibility
745// state. This ensures that entering full-screen mode will hide your panels
746// until you leave it.
747TEST_F(PanelLayoutManagerTest, PanelsHideAndRestoreWithShelf) {
748  gfx::Rect bounds(0, 0, 201, 201);
749
750  scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
751  scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
752  scoped_ptr<aura::Window> w3;
753  // Minimize w2.
754  w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
755  RunAllPendingInMessageLoop();
756  EXPECT_TRUE(w1->IsVisible());
757  EXPECT_FALSE(w2->IsVisible());
758
759  SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_HIDDEN);
760  RunAllPendingInMessageLoop();
761
762  // w3 is created while in full-screen mode, should only become visible when
763  // we exit fullscreen mode.
764  w3.reset(CreatePanelWindow(bounds));
765
766  EXPECT_FALSE(w1->IsVisible());
767  EXPECT_FALSE(w2->IsVisible());
768  EXPECT_FALSE(w3->IsVisible());
769
770  SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_VISIBLE);
771  RunAllPendingInMessageLoop();
772
773  // Windows should be restored to their prior state.
774  EXPECT_TRUE(w1->IsVisible());
775  EXPECT_FALSE(w2->IsVisible());
776  EXPECT_TRUE(w3->IsVisible());
777}
778
779INSTANTIATE_TEST_CASE_P(LtrRtl, PanelLayoutManagerTextDirectionTest,
780                        testing::Bool());
781
782}  // namespace internal
783}  // namespace ash
784