Home | History | Annotate | Download | only in ash
      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/shell.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "ash/ash_switches.h"
     11 #include "ash/desktop_background/desktop_background_widget_controller.h"
     12 #include "ash/display/mouse_cursor_event_filter.h"
     13 #include "ash/drag_drop/drag_drop_controller.h"
     14 #include "ash/launcher/launcher.h"
     15 #include "ash/root_window_controller.h"
     16 #include "ash/session_state_delegate.h"
     17 #include "ash/shelf/shelf_layout_manager.h"
     18 #include "ash/shelf/shelf_widget.h"
     19 #include "ash/shell_window_ids.h"
     20 #include "ash/test/ash_test_base.h"
     21 #include "ash/test/shell_test_api.h"
     22 #include "ash/wm/root_window_layout_manager.h"
     23 #include "ash/wm/window_util.h"
     24 #include "base/strings/utf_string_conversions.h"
     25 #include "ui/aura/client/aura_constants.h"
     26 #include "ui/aura/root_window.h"
     27 #include "ui/aura/window.h"
     28 #include "ui/gfx/size.h"
     29 #include "ui/views/widget/widget.h"
     30 #include "ui/views/widget/widget_delegate.h"
     31 #include "ui/views/window/dialog_delegate.h"
     32 
     33 using aura::RootWindow;
     34 
     35 namespace ash {
     36 
     37 namespace {
     38 
     39 aura::Window* GetDefaultContainer() {
     40   return Shell::GetContainer(
     41       Shell::GetPrimaryRootWindow(),
     42       internal::kShellWindowId_DefaultContainer);
     43 }
     44 
     45 aura::Window* GetAlwaysOnTopContainer() {
     46   return Shell::GetContainer(
     47       Shell::GetPrimaryRootWindow(),
     48       internal::kShellWindowId_AlwaysOnTopContainer);
     49 }
     50 
     51 // Expect ALL the containers!
     52 void ExpectAllContainers() {
     53   aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
     54   EXPECT_TRUE(Shell::GetContainer(
     55       root_window, internal::kShellWindowId_DesktopBackgroundContainer));
     56   EXPECT_TRUE(Shell::GetContainer(
     57       root_window, internal::kShellWindowId_DefaultContainer));
     58   EXPECT_TRUE(Shell::GetContainer(
     59       root_window, internal::kShellWindowId_AlwaysOnTopContainer));
     60   EXPECT_TRUE(Shell::GetContainer(
     61       root_window, internal::kShellWindowId_PanelContainer));
     62   EXPECT_TRUE(Shell::GetContainer(
     63       root_window, internal::kShellWindowId_ShelfContainer));
     64   EXPECT_TRUE(Shell::GetContainer(
     65       root_window, internal::kShellWindowId_SystemModalContainer));
     66   EXPECT_TRUE(Shell::GetContainer(
     67       root_window, internal::kShellWindowId_LockScreenBackgroundContainer));
     68   EXPECT_TRUE(Shell::GetContainer(
     69       root_window, internal::kShellWindowId_LockScreenContainer));
     70   EXPECT_TRUE(Shell::GetContainer(
     71       root_window, internal::kShellWindowId_LockSystemModalContainer));
     72   EXPECT_TRUE(Shell::GetContainer(
     73       root_window, internal::kShellWindowId_StatusContainer));
     74   EXPECT_TRUE(Shell::GetContainer(
     75       root_window, internal::kShellWindowId_MenuContainer));
     76   EXPECT_TRUE(Shell::GetContainer(
     77       root_window, internal::kShellWindowId_DragImageAndTooltipContainer));
     78   EXPECT_TRUE(Shell::GetContainer(
     79       root_window, internal::kShellWindowId_SettingBubbleContainer));
     80   EXPECT_TRUE(Shell::GetContainer(
     81       root_window, internal::kShellWindowId_OverlayContainer));
     82 }
     83 
     84 class ModalWindow : public views::WidgetDelegateView {
     85  public:
     86   ModalWindow() {}
     87   virtual ~ModalWindow() {}
     88 
     89   // Overridden from views::WidgetDelegate:
     90   virtual views::View* GetContentsView() OVERRIDE {
     91     return this;
     92   }
     93   virtual bool CanResize() const OVERRIDE {
     94     return true;
     95   }
     96   virtual base::string16 GetWindowTitle() const OVERRIDE {
     97     return ASCIIToUTF16("Modal Window");
     98   }
     99   virtual ui::ModalType GetModalType() const OVERRIDE {
    100     return ui::MODAL_TYPE_SYSTEM;
    101   }
    102 
    103  private:
    104   DISALLOW_COPY_AND_ASSIGN(ModalWindow);
    105 };
    106 
    107 }  // namespace
    108 
    109 class ShellTest : public test::AshTestBase {
    110  public:
    111   views::Widget* CreateTestWindow(views::Widget::InitParams params) {
    112     views::Widget* widget = new views::Widget;
    113     params.context = CurrentContext();
    114     widget->Init(params);
    115     return widget;
    116   }
    117 
    118   void TestCreateWindow(views::Widget::InitParams::Type type,
    119                         bool always_on_top,
    120                         aura::Window* expected_container) {
    121     views::Widget::InitParams widget_params(type);
    122     widget_params.keep_on_top = always_on_top;
    123 
    124     views::Widget* widget = CreateTestWindow(widget_params);
    125     widget->Show();
    126 
    127     EXPECT_TRUE(
    128         expected_container->Contains(widget->GetNativeWindow()->parent())) <<
    129         "TestCreateWindow: type=" << type << ", always_on_top=" <<
    130         always_on_top;
    131 
    132     widget->Close();
    133 }
    134 
    135 };
    136 
    137 TEST_F(ShellTest, CreateWindow) {
    138   // Normal window should be created in default container.
    139   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
    140                    false,  // always_on_top
    141                    GetDefaultContainer());
    142   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
    143                    false,  // always_on_top
    144                    GetDefaultContainer());
    145 
    146   // Always-on-top window and popup are created in always-on-top container.
    147   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
    148                    true,  // always_on_top
    149                    GetAlwaysOnTopContainer());
    150   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
    151                    true,  // always_on_top
    152                    GetAlwaysOnTopContainer());
    153 }
    154 
    155 TEST_F(ShellTest, ChangeAlwaysOnTop) {
    156   views::Widget::InitParams widget_params(
    157       views::Widget::InitParams::TYPE_WINDOW);
    158 
    159   // Creates a normal window
    160   views::Widget* widget = CreateTestWindow(widget_params);
    161   widget->Show();
    162 
    163   // It should be in default container.
    164   EXPECT_TRUE(GetDefaultContainer()->Contains(
    165                   widget->GetNativeWindow()->parent()));
    166 
    167   // Flip always-on-top flag.
    168   widget->SetAlwaysOnTop(true);
    169   // And it should in always on top container now.
    170   EXPECT_EQ(GetAlwaysOnTopContainer(), widget->GetNativeWindow()->parent());
    171 
    172   // Flip always-on-top flag.
    173   widget->SetAlwaysOnTop(false);
    174   // It should go back to default container.
    175   EXPECT_TRUE(GetDefaultContainer()->Contains(
    176                   widget->GetNativeWindow()->parent()));
    177 
    178   // Set the same always-on-top flag again.
    179   widget->SetAlwaysOnTop(false);
    180   // Should have no effect and we are still in the default container.
    181   EXPECT_TRUE(GetDefaultContainer()->Contains(
    182                   widget->GetNativeWindow()->parent()));
    183 
    184   widget->Close();
    185 }
    186 
    187 TEST_F(ShellTest, CreateModalWindow) {
    188   views::Widget::InitParams widget_params(
    189       views::Widget::InitParams::TYPE_WINDOW);
    190 
    191   // Create a normal window.
    192   views::Widget* widget = CreateTestWindow(widget_params);
    193   widget->Show();
    194 
    195   // It should be in default container.
    196   EXPECT_TRUE(GetDefaultContainer()->Contains(
    197                   widget->GetNativeWindow()->parent()));
    198 
    199   // Create a modal window.
    200   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
    201       new ModalWindow(), widget->GetNativeView());
    202   modal_widget->Show();
    203 
    204   // It should be in modal container.
    205   aura::Window* modal_container = Shell::GetContainer(
    206       Shell::GetPrimaryRootWindow(),
    207       internal::kShellWindowId_SystemModalContainer);
    208   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
    209 
    210   modal_widget->Close();
    211   widget->Close();
    212 }
    213 
    214 class TestModalDialogDelegate : public views::DialogDelegateView {
    215  public:
    216   TestModalDialogDelegate() {}
    217 
    218   // Overridden from views::WidgetDelegate:
    219   virtual ui::ModalType GetModalType() const OVERRIDE {
    220     return ui::MODAL_TYPE_SYSTEM;
    221   }
    222 };
    223 
    224 TEST_F(ShellTest, CreateLockScreenModalWindow) {
    225   views::Widget::InitParams widget_params(
    226       views::Widget::InitParams::TYPE_WINDOW);
    227 
    228   // Create a normal window.
    229   views::Widget* widget = CreateTestWindow(widget_params);
    230   widget->Show();
    231   EXPECT_TRUE(widget->GetNativeView()->HasFocus());
    232 
    233   // It should be in default container.
    234   EXPECT_TRUE(GetDefaultContainer()->Contains(
    235                   widget->GetNativeWindow()->parent()));
    236 
    237   Shell::GetInstance()->session_state_delegate()->LockScreen();
    238   // Create a LockScreen window.
    239   views::Widget* lock_widget = CreateTestWindow(widget_params);
    240   ash::Shell::GetContainer(
    241       Shell::GetPrimaryRootWindow(),
    242       ash::internal::kShellWindowId_LockScreenContainer)->
    243       AddChild(lock_widget->GetNativeView());
    244   lock_widget->Show();
    245   EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
    246 
    247   // It should be in LockScreen container.
    248   aura::Window* lock_screen = Shell::GetContainer(
    249       Shell::GetPrimaryRootWindow(),
    250       ash::internal::kShellWindowId_LockScreenContainer);
    251   EXPECT_EQ(lock_screen, lock_widget->GetNativeWindow()->parent());
    252 
    253   // Create a modal window with a lock window as parent.
    254   views::Widget* lock_modal_widget = views::Widget::CreateWindowWithParent(
    255       new ModalWindow(), lock_widget->GetNativeView());
    256   lock_modal_widget->Show();
    257   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
    258 
    259   // It should be in LockScreen modal container.
    260   aura::Window* lock_modal_container = Shell::GetContainer(
    261       Shell::GetPrimaryRootWindow(),
    262       ash::internal::kShellWindowId_LockSystemModalContainer);
    263   EXPECT_EQ(lock_modal_container,
    264             lock_modal_widget->GetNativeWindow()->parent());
    265 
    266   // Create a modal window with a normal window as parent.
    267   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
    268       new ModalWindow(), widget->GetNativeView());
    269   modal_widget->Show();
    270   // Window on lock screen shouldn't lost focus.
    271   EXPECT_FALSE(modal_widget->GetNativeView()->HasFocus());
    272   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
    273 
    274   // It should be in non-LockScreen modal container.
    275   aura::Window* modal_container = Shell::GetContainer(
    276       Shell::GetPrimaryRootWindow(),
    277       ash::internal::kShellWindowId_SystemModalContainer);
    278   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
    279 
    280   // Modal dialog without parent, caused crash see crbug.com/226141
    281   views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget(
    282       new TestModalDialogDelegate(), CurrentContext(), NULL);
    283 
    284   modal_dialog->Show();
    285   EXPECT_FALSE(modal_dialog->GetNativeView()->HasFocus());
    286   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
    287 
    288   modal_dialog->Close();
    289   modal_widget->Close();
    290   modal_widget->Close();
    291   lock_modal_widget->Close();
    292   lock_widget->Close();
    293   widget->Close();
    294 }
    295 
    296 TEST_F(ShellTest, IsScreenLocked) {
    297   SessionStateDelegate* delegate =
    298       Shell::GetInstance()->session_state_delegate();
    299   delegate->LockScreen();
    300   EXPECT_TRUE(delegate->IsScreenLocked());
    301   delegate->UnlockScreen();
    302   EXPECT_FALSE(delegate->IsScreenLocked());
    303 }
    304 
    305 // Fails on Mac, see http://crbug.com/115662
    306 #if defined(OS_MACOSX)
    307 #define MAYBE_ManagedWindowModeBasics DISABLED_ManagedWindowModeBasics
    308 #else
    309 #define MAYBE_ManagedWindowModeBasics ManagedWindowModeBasics
    310 #endif
    311 TEST_F(ShellTest, MAYBE_ManagedWindowModeBasics) {
    312   Shell* shell = Shell::GetInstance();
    313   Shell::TestApi test_api(shell);
    314 
    315   // We start with the usual window containers.
    316   ExpectAllContainers();
    317   // Launcher is visible.
    318   ShelfWidget* launcher_widget = Launcher::ForPrimaryDisplay()->shelf_widget();
    319   EXPECT_TRUE(launcher_widget->IsVisible());
    320   // Launcher is at bottom-left of screen.
    321   EXPECT_EQ(0, launcher_widget->GetWindowBoundsInScreen().x());
    322   EXPECT_EQ(Shell::GetPrimaryRootWindow()->GetHostSize().height(),
    323             launcher_widget->GetWindowBoundsInScreen().bottom());
    324   // We have a desktop background but not a bare layer.
    325   // TODO (antrim): enable once we find out why it fails component build.
    326   //  internal::DesktopBackgroundWidgetController* background =
    327   //      Shell::GetPrimaryRootWindow()->
    328   //          GetProperty(internal::kWindowDesktopComponent);
    329   //  EXPECT_TRUE(background);
    330   //  EXPECT_TRUE(background->widget());
    331   //  EXPECT_FALSE(background->layer());
    332 
    333   // Create a normal window.  It is not maximized.
    334   views::Widget::InitParams widget_params(
    335       views::Widget::InitParams::TYPE_WINDOW);
    336   widget_params.bounds.SetRect(11, 22, 300, 400);
    337   views::Widget* widget = CreateTestWindow(widget_params);
    338   widget->Show();
    339   EXPECT_FALSE(widget->IsMaximized());
    340 
    341   // Clean up.
    342   widget->Close();
    343 }
    344 
    345 TEST_F(ShellTest, FullscreenWindowHidesShelf) {
    346   ExpectAllContainers();
    347 
    348   // Create a normal window.  It is not maximized.
    349   views::Widget::InitParams widget_params(
    350       views::Widget::InitParams::TYPE_WINDOW);
    351   widget_params.bounds.SetRect(11, 22, 300, 400);
    352   views::Widget* widget = CreateTestWindow(widget_params);
    353   widget->Show();
    354   EXPECT_FALSE(widget->IsMaximized());
    355 
    356   // Shelf defaults to visible.
    357   EXPECT_EQ(
    358       SHELF_VISIBLE,
    359       Shell::GetPrimaryRootWindowController()->
    360           GetShelfLayoutManager()->visibility_state());
    361 
    362   // Fullscreen window hides it.
    363   widget->SetFullscreen(true);
    364   EXPECT_EQ(
    365       SHELF_HIDDEN,
    366       Shell::GetPrimaryRootWindowController()->
    367           GetShelfLayoutManager()->visibility_state());
    368 
    369   // Restoring the window restores it.
    370   widget->Restore();
    371   EXPECT_EQ(
    372       SHELF_VISIBLE,
    373       Shell::GetPrimaryRootWindowController()->
    374           GetShelfLayoutManager()->visibility_state());
    375 
    376   // Clean up.
    377   widget->Close();
    378 }
    379 
    380 namespace {
    381 
    382 // Builds the list of parents from |window| to the root. The returned vector is
    383 // in reverse order (|window| is first).
    384 std::vector<aura::Window*> BuildPathToRoot(aura::Window* window) {
    385   std::vector<aura::Window*> results;
    386   while (window) {
    387     results.push_back(window);
    388     window = window->parent();
    389   }
    390   return results;
    391 }
    392 
    393 }  // namespace
    394 
    395 // Various assertions around SetShelfAutoHideBehavior() and
    396 // GetShelfAutoHideBehavior().
    397 TEST_F(ShellTest, ToggleAutoHide) {
    398   scoped_ptr<aura::Window> window(new aura::Window(NULL));
    399   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    400   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
    401   window->Init(ui::LAYER_TEXTURED);
    402   SetDefaultParentByPrimaryRootWindow(window.get());
    403   window->Show();
    404   wm::ActivateWindow(window.get());
    405 
    406   Shell* shell = Shell::GetInstance();
    407   aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
    408   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
    409                                   root_window);
    410   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
    411             shell->GetShelfAutoHideBehavior(root_window));
    412   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
    413                                   root_window);
    414   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
    415             shell->GetShelfAutoHideBehavior(root_window));
    416   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    417   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
    418             shell->GetShelfAutoHideBehavior(root_window));
    419   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
    420                                   root_window);
    421   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
    422             shell->GetShelfAutoHideBehavior(root_window));
    423   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
    424                                   root_window);
    425   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
    426             shell->GetShelfAutoHideBehavior(root_window));
    427 }
    428 
    429 TEST_F(ShellTest, TestPreTargetHandlerOrder) {
    430   Shell* shell = Shell::GetInstance();
    431   Shell::TestApi test_api(shell);
    432   test::ShellTestApi shell_test_api(shell);
    433 
    434   const ui::EventHandlerList& handlers = test_api.pre_target_handlers();
    435   EXPECT_EQ(handlers[0], shell->mouse_cursor_filter());
    436   EXPECT_EQ(handlers[1], shell_test_api.drag_drop_controller());
    437 }
    438 
    439 // This verifies WindowObservers are removed when a window is destroyed after
    440 // the Shell is destroyed. This scenario (aura::Windows being deleted after the
    441 // Shell) occurs if someone is holding a reference to an unparented Window, as
    442 // is the case with a RenderWidgetHostViewAura that isn't on screen. As long as
    443 // everything is ok, we won't crash. If there is a bug, window's destructor will
    444 // notify some deleted object (say VideoDetector or ActivationController) and
    445 // this will crash.
    446 class ShellTest2 : public test::AshTestBase {
    447  public:
    448   ShellTest2() {}
    449   virtual ~ShellTest2() {}
    450 
    451  protected:
    452   scoped_ptr<aura::Window> window_;
    453 
    454  private:
    455   DISALLOW_COPY_AND_ASSIGN(ShellTest2);
    456 };
    457 
    458 TEST_F(ShellTest2, DontCrashWhenWindowDeleted) {
    459   window_.reset(new aura::Window(NULL));
    460   window_->Init(ui::LAYER_NOT_DRAWN);
    461 }
    462 
    463 }  // namespace ash
    464