Home | History | Annotate | Download | only in shelf
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/shelf/shelf_widget.h"
      6 
      7 #include "ash/root_window_controller.h"
      8 #include "ash/shelf/shelf.h"
      9 #include "ash/shelf/shelf_button.h"
     10 #include "ash/shelf/shelf_layout_manager.h"
     11 #include "ash/shelf/shelf_model.h"
     12 #include "ash/shelf/shelf_view.h"
     13 #include "ash/shell.h"
     14 #include "ash/test/ash_test_base.h"
     15 #include "ash/test/shelf_test_api.h"
     16 #include "ash/test/shelf_view_test_api.h"
     17 #include "ash/wm/window_util.h"
     18 #include "ui/aura/window_event_dispatcher.h"
     19 #include "ui/events/event_utils.h"
     20 #include "ui/gfx/display.h"
     21 #include "ui/gfx/screen.h"
     22 #include "ui/views/view.h"
     23 #include "ui/views/widget/widget.h"
     24 
     25 namespace ash {
     26 
     27 namespace {
     28 
     29 ShelfWidget* GetShelfWidget() {
     30   return Shelf::ForPrimaryDisplay()->shelf_widget();
     31 }
     32 
     33 ShelfLayoutManager* GetShelfLayoutManager() {
     34   return GetShelfWidget()->shelf_layout_manager();
     35 }
     36 
     37 } // namespace
     38 
     39 typedef test::AshTestBase ShelfWidgetTest;
     40 
     41 void TestLauncherAlignment(aura::Window* root,
     42                            ShelfAlignment alignment,
     43                            const std::string& expected) {
     44   Shell::GetInstance()->SetShelfAlignment(alignment, root);
     45   gfx::Screen* screen = gfx::Screen::GetScreenFor(root);
     46   EXPECT_EQ(expected,
     47             screen->GetDisplayNearestWindow(root).work_area().ToString());
     48 }
     49 
     50 TEST_F(ShelfWidgetTest, TestAlignment) {
     51   Shelf* shelf = Shelf::ForPrimaryDisplay();
     52   UpdateDisplay("400x400");
     53   ASSERT_TRUE(shelf);
     54   {
     55     SCOPED_TRACE("Single Bottom");
     56     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
     57                           SHELF_ALIGNMENT_BOTTOM,
     58                           "0,0 400x353");
     59   }
     60   {
     61     SCOPED_TRACE("Single Right");
     62     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
     63                           SHELF_ALIGNMENT_RIGHT,
     64                           "0,0 353x400");
     65   }
     66   {
     67     SCOPED_TRACE("Single Left");
     68     TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
     69                           SHELF_ALIGNMENT_LEFT,
     70                           "47,0 353x400");
     71   }
     72   if (!SupportsMultipleDisplays())
     73     return;
     74 
     75   UpdateDisplay("300x300,500x500");
     76   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     77   {
     78     SCOPED_TRACE("Primary Bottom");
     79     TestLauncherAlignment(root_windows[0],
     80                           SHELF_ALIGNMENT_BOTTOM,
     81                           "0,0 300x253");
     82   }
     83   {
     84     SCOPED_TRACE("Primary Right");
     85     TestLauncherAlignment(root_windows[0],
     86                           SHELF_ALIGNMENT_RIGHT,
     87                           "0,0 253x300");
     88   }
     89   {
     90     SCOPED_TRACE("Primary Left");
     91     TestLauncherAlignment(root_windows[0],
     92                           SHELF_ALIGNMENT_LEFT,
     93                           "47,0 253x300");
     94   }
     95   {
     96     SCOPED_TRACE("Secondary Bottom");
     97     TestLauncherAlignment(root_windows[1],
     98                           SHELF_ALIGNMENT_BOTTOM,
     99                           "300,0 500x453");
    100   }
    101   {
    102     SCOPED_TRACE("Secondary Right");
    103     TestLauncherAlignment(root_windows[1],
    104                           SHELF_ALIGNMENT_RIGHT,
    105                           "300,0 453x500");
    106   }
    107   {
    108     SCOPED_TRACE("Secondary Left");
    109     TestLauncherAlignment(root_windows[1],
    110                           SHELF_ALIGNMENT_LEFT,
    111                           "347,0 453x500");
    112   }
    113 }
    114 
    115 // Makes sure the shelf is initially sized correctly.
    116 TEST_F(ShelfWidgetTest, LauncherInitiallySized) {
    117   ShelfWidget* shelf_widget = GetShelfWidget();
    118   Shelf* shelf = shelf_widget->shelf();
    119   ASSERT_TRUE(shelf);
    120   ShelfLayoutManager* shelf_layout_manager = GetShelfLayoutManager();
    121   ASSERT_TRUE(shelf_layout_manager);
    122   ASSERT_TRUE(shelf_widget->status_area_widget());
    123   int status_width = shelf_widget->status_area_widget()->
    124       GetWindowBoundsInScreen().width();
    125   // Test only makes sense if the status is > 0, which it better be.
    126   EXPECT_GT(status_width, 0);
    127   EXPECT_EQ(status_width, shelf_widget->GetContentsView()->width() -
    128             test::ShelfTestAPI(shelf).shelf_view()->width());
    129 }
    130 
    131 // Verifies when the shell is deleted with a full screen window we don't crash.
    132 TEST_F(ShelfWidgetTest, DontReferenceShelfAfterDeletion) {
    133   views::Widget* widget = new views::Widget;
    134   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    135   params.bounds = gfx::Rect(0, 0, 200, 200);
    136   params.context = CurrentContext();
    137   // Widget is now owned by the parent window.
    138   widget->Init(params);
    139   widget->SetFullscreen(true);
    140 }
    141 
    142 #if defined(OS_CHROMEOS)
    143 // Verifies shelf is created with correct size after user login and when its
    144 // container and status widget has finished sizing.
    145 // See http://crbug.com/252533
    146 TEST_F(ShelfWidgetTest, ShelfInitiallySizedAfterLogin) {
    147   SetUserLoggedIn(false);
    148   UpdateDisplay("300x200,400x300");
    149 
    150   ShelfWidget* shelf_widget = NULL;
    151   Shell::RootWindowControllerList controllers(
    152       Shell::GetAllRootWindowControllers());
    153   for (Shell::RootWindowControllerList::const_iterator i = controllers.begin();
    154        i != controllers.end();
    155        ++i) {
    156     if (!(*i)->shelf()->shelf()) {
    157       shelf_widget = (*i)->shelf();
    158       break;
    159     }
    160   }
    161   ASSERT_TRUE(shelf_widget != NULL);
    162 
    163   SetUserLoggedIn(true);
    164   Shell::GetInstance()->CreateShelf();
    165 
    166   Shelf* shelf = shelf_widget->shelf();
    167   ASSERT_TRUE(shelf != NULL);
    168 
    169   const int status_width =
    170       shelf_widget->status_area_widget()->GetWindowBoundsInScreen().width();
    171   EXPECT_GT(status_width, 0);
    172   EXPECT_EQ(status_width,
    173             shelf_widget->GetContentsView()->width() -
    174                 test::ShelfTestAPI(shelf).shelf_view()->width());
    175 }
    176 #endif  // defined(OS_CHROMEOS)
    177 
    178 // Tests that the shelf lets mouse-events close to the edge fall through to the
    179 // window underneath.
    180 TEST_F(ShelfWidgetTest, ShelfEdgeOverlappingWindowHitTestMouse) {
    181   ShelfWidget* shelf_widget = GetShelfWidget();
    182   gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
    183   EXPECT_TRUE(!shelf_bounds.IsEmpty());
    184   ShelfLayoutManager* shelf_layout_manager =
    185       shelf_widget->shelf_layout_manager();
    186   ASSERT_TRUE(shelf_layout_manager);
    187   EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
    188 
    189   // Create a Widget which overlaps with the shelf in the top edge.
    190   const int kOverlapSize = 15;
    191   const int kWindowHeight = 200;
    192   views::Widget* widget = new views::Widget;
    193   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    194   params.bounds = gfx::Rect(0, shelf_bounds.y() - kWindowHeight + kOverlapSize,
    195                             200, kWindowHeight);
    196   params.context = CurrentContext();
    197   // Widget is now owned by the parent window.
    198   widget->Init(params);
    199   widget->Show();
    200   gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
    201   EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
    202 
    203 
    204   ui::EventTarget* root = widget->GetNativeWindow()->GetRootWindow();
    205   ui::EventTargeter* targeter = root->GetEventTargeter();
    206   {
    207     // Create a mouse-event targetting the top of the shelf widget. The
    208     // window-targeter should find |widget| as the target (instead of the
    209     // shelf).
    210     gfx::Point event_location(20, shelf_bounds.y() + 1);
    211     ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
    212                          ui::EF_NONE, ui::EF_NONE);
    213     ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
    214     EXPECT_EQ(widget->GetNativeWindow(), target);
    215   }
    216 
    217   // Now auto-hide (hidden) the shelf.
    218   shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    219   shelf_layout_manager->LayoutShelf();
    220   EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
    221   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
    222   shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
    223   EXPECT_TRUE(!shelf_bounds.IsEmpty());
    224 
    225   // Move |widget| so it still overlaps the shelf.
    226   widget->SetBounds(gfx::Rect(0, shelf_bounds.y() - kWindowHeight +
    227                               kOverlapSize, 200, kWindowHeight));
    228   widget_bounds = widget->GetWindowBoundsInScreen();
    229   EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
    230   {
    231     // Create a mouse-event targetting the top of the shelf widget. This time,
    232     // window-target should find the shelf as the target.
    233     gfx::Point event_location(20, shelf_bounds.y() + 1);
    234     ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
    235                          ui::EF_NONE, ui::EF_NONE);
    236     ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
    237     EXPECT_EQ(shelf_widget->GetNativeWindow(), target);
    238   }
    239 }
    240 
    241 // Tests that the shelf has a slightly larger hit-region for touch-events when
    242 // it's in the auto-hidden state.
    243 TEST_F(ShelfWidgetTest, HiddenShelfHitTestTouch) {
    244   ShelfWidget* shelf_widget = GetShelfWidget();
    245   gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
    246   EXPECT_TRUE(!shelf_bounds.IsEmpty());
    247   ShelfLayoutManager* shelf_layout_manager =
    248       shelf_widget->shelf_layout_manager();
    249   ASSERT_TRUE(shelf_layout_manager);
    250   EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
    251 
    252   // Create a widget to make sure that the shelf does auto-hide.
    253   views::Widget* widget = new views::Widget;
    254   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    255   params.bounds = gfx::Rect(0, 0, 200, 200);
    256   params.context = CurrentContext();
    257   // Widget is now owned by the parent window.
    258   widget->Init(params);
    259   widget->Show();
    260 
    261   ui::EventTarget* root = shelf_widget->GetNativeWindow()->GetRootWindow();
    262   ui::EventTargeter* targeter = root->GetEventTargeter();
    263   // Touch just over the shelf. Since the shelf is visible, the window-targeter
    264   // should not find the shelf as the target.
    265   {
    266     gfx::Point event_location(20, shelf_bounds.y() - 1);
    267     ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0,
    268                          ui::EventTimeForNow());
    269     EXPECT_NE(shelf_widget->GetNativeWindow(),
    270               targeter->FindTargetForEvent(root, &touch));
    271   }
    272 
    273   // Now auto-hide (hidden) the shelf.
    274   shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    275   shelf_layout_manager->LayoutShelf();
    276   EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
    277   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
    278   shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
    279   EXPECT_TRUE(!shelf_bounds.IsEmpty());
    280 
    281   // Touch just over the shelf again. This time, the targeter should find the
    282   // shelf as the target.
    283   {
    284     gfx::Point event_location(20, shelf_bounds.y() - 1);
    285     ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0,
    286                          ui::EventTimeForNow());
    287     EXPECT_EQ(shelf_widget->GetNativeWindow(),
    288               targeter->FindTargetForEvent(root, &touch));
    289   }
    290 }
    291 
    292 }  // namespace ash
    293