Home | History | Annotate | Download | only in panels
      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/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/event_generator.h"
     35 #include "ui/aura/test/test_windows.h"
     36 #include "ui/aura/window.h"
     37 #include "ui/aura/window_event_dispatcher.h"
     38 #include "ui/base/l10n/l10n_util.h"
     39 #include "ui/events/event_utils.h"
     40 #include "ui/views/widget/widget.h"
     41 
     42 namespace ash {
     43 
     44 using aura::test::WindowIsAbove;
     45 
     46 class PanelLayoutManagerTest : public test::AshTestBase {
     47  public:
     48   PanelLayoutManagerTest() {}
     49   virtual ~PanelLayoutManagerTest() {}
     50 
     51   virtual void SetUp() OVERRIDE {
     52     test::AshTestBase::SetUp();
     53     ASSERT_TRUE(test::TestShelfDelegate::instance());
     54 
     55     shelf_view_test_.reset(new test::ShelfViewTestAPI(
     56         GetShelfView(Shelf::ForPrimaryDisplay())));
     57     shelf_view_test_->SetAnimationDuration(1);
     58   }
     59 
     60   aura::Window* CreateNormalWindow(const gfx::Rect& bounds) {
     61     return CreateTestWindowInShellWithBounds(bounds);
     62   }
     63 
     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();
     72     return window;
     73   }
     74 
     75   aura::Window* CreatePanelWindow(const gfx::Rect& bounds) {
     76     return CreatePanelWindowWithDelegate(NULL, bounds);
     77   }
     78 
     79   aura::Window* GetPanelContainer(aura::Window* panel) {
     80     return Shell::GetContainer(panel->GetRootWindow(),
     81                                kShellWindowId_PanelContainer);
     82   }
     83 
     84   views::Widget* GetCalloutWidgetForPanel(aura::Window* panel) {
     85     PanelLayoutManager* manager =
     86         static_cast<PanelLayoutManager*>(GetPanelContainer(panel)->
     87                                          layout_manager());
     88     DCHECK(manager);
     89     PanelLayoutManager::PanelList::iterator found = std::find(
     90         manager->panel_windows_.begin(), manager->panel_windows_.end(),
     91         panel);
     92     DCHECK(found != manager->panel_windows_.end());
     93     DCHECK(found->callout_widget);
     94     return reinterpret_cast<views::Widget*>(found->callout_widget);
     95   }
     96 
     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);
    101 
    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());
    109   }
    110 
    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();
    116 
    117     EXPECT_FALSE(window1_bounds.Intersects(window2_bounds));
    118   }
    119 
    120   void IsPanelAboveLauncherIcon(const aura::Window* panel) {
    121     // Waits until all shelf view animations are done.
    122     shelf_view_test()->RunMessageLoopUntilAnimationsDone();
    123 
    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);
    127 
    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());
    133 
    134     if (IsHorizontal(alignment)) {
    135       // The horizontal bounds of the panel window should contain the bounds of
    136       // the shelf icon.
    137       EXPECT_LE(window_bounds.x(), icon_bounds.x());
    138       EXPECT_GE(window_bounds.right(), icon_bounds.right());
    139     } else {
    140       // The vertical bounds of the panel window should contain the bounds of
    141       // the shelf icon.
    142       EXPECT_LE(window_bounds.y(), icon_bounds.y());
    143       EXPECT_GE(window_bounds.bottom(), icon_bounds.bottom());
    144     }
    145 
    146     switch (alignment) {
    147       case SHELF_ALIGNMENT_BOTTOM:
    148         EXPECT_EQ(shelf_bounds.y(), window_bounds.bottom());
    149         break;
    150       case SHELF_ALIGNMENT_LEFT:
    151         EXPECT_EQ(shelf_bounds.right(), window_bounds.x());
    152         break;
    153       case SHELF_ALIGNMENT_RIGHT:
    154         EXPECT_EQ(shelf_bounds.x(), window_bounds.right());
    155         break;
    156       case SHELF_ALIGNMENT_TOP:
    157         EXPECT_EQ(shelf_bounds.bottom(), window_bounds.y());
    158         break;
    159     }
    160   }
    161 
    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);
    166 
    167     Shelf* shelf = RootWindowController::ForShelf(panel)->shelf()->shelf();
    168     gfx::Rect icon_bounds = shelf->GetScreenBoundsOfItemIconForWindow(panel);
    169     ASSERT_FALSE(icon_bounds.IsEmpty());
    170 
    171     gfx::Rect panel_bounds = panel->GetBoundsInScreen();
    172     gfx::Rect callout_bounds = widget->GetWindowBoundsInScreen();
    173     ASSERT_FALSE(icon_bounds.IsEmpty());
    174 
    175     EXPECT_TRUE(widget->IsVisible());
    176 
    177     ShelfAlignment alignment = GetAlignment(panel->GetRootWindow());
    178     switch (alignment) {
    179       case SHELF_ALIGNMENT_BOTTOM:
    180         EXPECT_EQ(panel_bounds.bottom(), callout_bounds.y());
    181         break;
    182       case SHELF_ALIGNMENT_LEFT:
    183         EXPECT_EQ(panel_bounds.x(), callout_bounds.right());
    184         break;
    185       case SHELF_ALIGNMENT_RIGHT:
    186         EXPECT_EQ(panel_bounds.right(), callout_bounds.x());
    187         break;
    188       case SHELF_ALIGNMENT_TOP:
    189         EXPECT_EQ(panel_bounds.y(), callout_bounds.bottom());
    190         break;
    191     }
    192 
    193     if (IsHorizontal(alignment)) {
    194       EXPECT_NEAR(icon_bounds.CenterPoint().x(),
    195                   widget->GetWindowBoundsInScreen().CenterPoint().x(),
    196                   1);
    197     } else {
    198       EXPECT_NEAR(icon_bounds.CenterPoint().y(),
    199                   widget->GetWindowBoundsInScreen().CenterPoint().y(),
    200                   1);
    201     }
    202   }
    203 
    204   bool IsPanelCalloutVisible(aura::Window* panel) {
    205     views::Widget* widget = GetCalloutWidgetForPanel(panel);
    206     return widget->IsVisible();
    207   }
    208 
    209   test::ShelfViewTestAPI* shelf_view_test() {
    210     return shelf_view_test_.get();
    211   }
    212 
    213   // Clicks the shelf items on |shelf_view| that is associated with given
    214   // |window|.
    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();
    222 
    223     aura::test::EventGenerator& event_generator = GetEventGenerator();
    224     event_generator.MoveMouseTo(bounds.CenterPoint());
    225     event_generator.ClickLeftButton();
    226 
    227     test_api.RunMessageLoopUntilAnimationsDone();
    228   }
    229 
    230   void SetAlignment(aura::Window* root_window, ShelfAlignment alignment) {
    231     ash::Shell* shell = ash::Shell::GetInstance();
    232     shell->SetShelfAlignment(alignment, root_window);
    233   }
    234 
    235   ShelfAlignment GetAlignment(const aura::Window* root_window) {
    236     ash::Shell* shell = ash::Shell::GetInstance();
    237     return shell->GetShelfAlignment(root_window);
    238   }
    239 
    240   void SetShelfAutoHideBehavior(aura::Window* window,
    241                                 ShelfAutoHideBehavior behavior) {
    242     ShelfLayoutManager* shelf = RootWindowController::ForWindow(window)
    243                                     ->shelf()
    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();
    249   }
    250 
    251   void SetShelfVisibilityState(aura::Window* window,
    252                                ShelfVisibilityState visibility_state) {
    253     ShelfLayoutManager* shelf = RootWindowController::ForWindow(window)
    254                                     ->shelf()
    255                                     ->shelf_layout_manager();
    256     shelf->SetState(visibility_state);
    257   }
    258 
    259   ShelfView* GetShelfView(Shelf* shelf) {
    260     return test::ShelfTestAPI(shelf).shelf_view();
    261   }
    262 
    263  private:
    264   scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_;
    265 
    266   bool IsHorizontal(ShelfAlignment alignment) {
    267     return alignment == SHELF_ALIGNMENT_BOTTOM ||
    268            alignment == SHELF_ALIGNMENT_TOP;
    269   }
    270 
    271   DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTest);
    272 };
    273 
    274 class PanelLayoutManagerTextDirectionTest
    275     : public PanelLayoutManagerTest,
    276       public testing::WithParamInterface<bool> {
    277  public:
    278   PanelLayoutManagerTextDirectionTest() : is_rtl_(GetParam()) {}
    279   virtual ~PanelLayoutManagerTextDirectionTest() {}
    280 
    281   virtual void SetUp() OVERRIDE {
    282     original_locale = l10n_util::GetApplicationLocale(std::string());
    283     if (is_rtl_)
    284       base::i18n::SetICUDefaultLocale("he");
    285     PanelLayoutManagerTest::SetUp();
    286     ASSERT_EQ(is_rtl_, base::i18n::IsRTL());
    287   }
    288 
    289   virtual void TearDown() OVERRIDE {
    290     if (is_rtl_)
    291       base::i18n::SetICUDefaultLocale(original_locale);
    292     PanelLayoutManagerTest::TearDown();
    293   }
    294 
    295  private:
    296   bool is_rtl_;
    297   std::string original_locale;
    298 
    299   DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTextDirectionTest);
    300 };
    301 
    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()));
    309 }
    310 
    311 // Tests that a created panel window is successfully aligned over a hidden
    312 // shelf icon.
    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()));
    321 }
    322 
    323 TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIconSecondDisplay) {
    324   if (!SupportsMultipleDisplays())
    325     return;
    326 
    327   // Keep the displays wide so that shelves have enough space for shelves
    328   // buttons.
    329   UpdateDisplay("400x400,600x400");
    330   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    331 
    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();
    338 
    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());
    346 }
    347 
    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);
    352 
    353   scoped_ptr<aura::Window> w1(CreatePanelWindow(odd_bounds));
    354   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
    355 
    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()));
    359 
    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()));
    364 }
    365 
    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));
    371 
    372   // Default stacking order.
    373   EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
    374   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
    375 
    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()));
    381 
    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()));
    387 
    388   wm::ActivateWindow(w3.get());
    389   EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
    390   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
    391 }
    392 
    393 TEST_F(PanelLayoutManagerTest, MultiplePanelStackingVertical) {
    394   // Set shelf to be aligned on the right.
    395   SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT);
    396 
    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)));
    402 
    403   // Default stacking order.
    404   EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
    405   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
    406 
    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()));
    412 
    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()));
    418 
    419   wm::ActivateWindow(w3.get());
    420   EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get()));
    421   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
    422 }
    423 
    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()));
    443   w3.reset();
    444   EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get()));
    445 }
    446 
    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));
    453 
    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
    458   w1.reset();
    459   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
    460   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
    461   EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
    462 }
    463 
    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));
    469 
    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
    473   w2.reset();
    474   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
    475   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
    476   EXPECT_TRUE(WindowIsAbove(w3.get(), w1.get()));
    477 }
    478 
    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));
    484 
    485   // At this point, windows should be stacked with 1 < 2 < 3
    486   wm::ActivateWindow(w3.get());
    487   // Order shouldn't change.
    488   w3.reset();
    489   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get()));
    490   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
    491   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
    492 }
    493 
    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));
    499 
    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
    503   w1.reset();
    504   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get()));
    505   EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get()));
    506   EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
    507 }
    508 
    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));
    513 
    514   EXPECT_NO_FATAL_FAILURE(PanelsNotOverlapping(w1.get(), w2.get()));
    515 }
    516 
    517 #if defined(OS_WIN)
    518 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
    519 #define MAYBE_SplitViewOverlapWhenLarge DISABLED_SplitViewOverlapWhenLarge
    520 #else
    521 #define MAYBE_SplitViewOverlapWhenLarge SplitViewOverlapWhenLarge
    522 #endif
    523 
    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));
    528 
    529   EXPECT_NO_FATAL_FAILURE(PanelInScreen(w1.get()));
    530   EXPECT_NO_FATAL_FAILURE(PanelInScreen(w2.get()));
    531 }
    532 
    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));
    538 
    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);
    549 }
    550 
    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));
    557 
    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);
    566 }
    567 
    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()));
    588 }
    589 
    590 TEST_F(PanelLayoutManagerTest, PanelMoveBetweenMultipleDisplays) {
    591   if (!SupportsMultipleDisplays())
    592     return;
    593 
    594   // Keep the displays wide so that shelves have enough space for launcher
    595   // buttons.
    596   UpdateDisplay("600x400,600x400");
    597   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    598 
    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)));
    603 
    604   ShelfView* shelf_view_1st = GetShelfView(Shelf::ForPrimaryDisplay());
    605   ShelfView* shelf_view_2nd =
    606       GetShelfView(Shelf::ForWindow(root_windows[1]));
    607 
    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());
    612 
    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());
    617 
    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()));
    627 
    628   // Test if clicking on another display moves the panel to
    629   // that display.
    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()));
    637 
    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()));
    647 
    648   // Test if clicking on another display moves the panel to
    649   // that display.
    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()));
    657 
    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()));
    667 }
    668 
    669 TEST_F(PanelLayoutManagerTest, PanelAttachPositionMultipleDisplays) {
    670   if (!SupportsMultipleDisplays())
    671     return;
    672 
    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();
    678 
    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)));
    681 
    682   EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow());
    683   EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
    684 
    685   IsPanelAboveLauncherIcon(p1_d1.get());
    686   IsCalloutAboveLauncherIcon(p1_d1.get());
    687   IsPanelAboveLauncherIcon(p1_d2.get());
    688   IsCalloutAboveLauncherIcon(p1_d2.get());
    689 }
    690 
    691 TEST_F(PanelLayoutManagerTest, PanelAlignmentSecondDisplay) {
    692   if (!SupportsMultipleDisplays())
    693     return;
    694 
    695   UpdateDisplay("600x400,600x400");
    696   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    697 
    698   scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50)));
    699   EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow());
    700 
    701   IsPanelAboveLauncherIcon(p1_d2.get());
    702   IsCalloutAboveLauncherIcon(p1_d2.get());
    703 
    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());
    713 }
    714 
    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());
    721 }
    722 
    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());
    729 }
    730 
    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());
    737 }
    738 
    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);
    744 
    745   scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds));
    746   scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds));
    747   scoped_ptr<aura::Window> w3;
    748   // Minimize w2.
    749   wm::GetWindowState(w2.get())->Minimize();
    750   RunAllPendingInMessageLoop();
    751   EXPECT_TRUE(w1->IsVisible());
    752   EXPECT_FALSE(w2->IsVisible());
    753 
    754   SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_HIDDEN);
    755   RunAllPendingInMessageLoop();
    756 
    757   // w3 is created while in full-screen mode, should only become visible when
    758   // we exit fullscreen mode.
    759   w3.reset(CreatePanelWindow(bounds));
    760 
    761   EXPECT_FALSE(w1->IsVisible());
    762   EXPECT_FALSE(w2->IsVisible());
    763   EXPECT_FALSE(w3->IsVisible());
    764 
    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(),
    772           w1.get()));
    773   EXPECT_NE(switchable_window_list.end(),
    774       std::find(switchable_window_list.begin(), switchable_window_list.end(),
    775           w2.get()));
    776   EXPECT_NE(switchable_window_list.end(),
    777       std::find(switchable_window_list.begin(), switchable_window_list.end(),
    778           w3.get()));
    779 
    780   SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_VISIBLE);
    781   RunAllPendingInMessageLoop();
    782 
    783   // Windows should be restored to their prior state.
    784   EXPECT_TRUE(w1->IsVisible());
    785   EXPECT_FALSE(w2->IsVisible());
    786   EXPECT_TRUE(w3->IsVisible());
    787 }
    788 
    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();
    797 
    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
    801   // is calculated as
    802   // kResizeOutsideBoundsSize * kResizeOutsideBoundsScaleForTouch
    803   // in src/ash/root_window_controller.cc.
    804 
    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);
    813 
    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);
    818 
    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);
    825 
    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);
    830 
    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);
    837 
    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);
    842 
    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);
    849 
    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);
    854 }
    855 
    856 INSTANTIATE_TEST_CASE_P(LtrRtl, PanelLayoutManagerTextDirectionTest,
    857                         testing::Bool());
    858 
    859 }  // namespace ash
    860