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/root_window_controller.h"
      6 
      7 #include "ash/session/session_state_delegate.h"
      8 #include "ash/shelf/shelf_layout_manager.h"
      9 #include "ash/shell.h"
     10 #include "ash/shell_window_ids.h"
     11 #include "ash/system/tray/system_tray_delegate.h"
     12 #include "ash/test/ash_test_base.h"
     13 #include "ash/wm/system_modal_container_layout_manager.h"
     14 #include "ash/wm/window_properties.h"
     15 #include "ash/wm/window_state.h"
     16 #include "ash/wm/window_util.h"
     17 #include "base/command_line.h"
     18 #include "base/memory/scoped_ptr.h"
     19 #include "ui/aura/client/focus_change_observer.h"
     20 #include "ui/aura/client/focus_client.h"
     21 #include "ui/aura/client/window_tree_client.h"
     22 #include "ui/aura/env.h"
     23 #include "ui/aura/test/test_window_delegate.h"
     24 #include "ui/aura/test/test_windows.h"
     25 #include "ui/aura/window.h"
     26 #include "ui/aura/window_event_dispatcher.h"
     27 #include "ui/aura/window_tracker.h"
     28 #include "ui/base/ime/dummy_text_input_client.h"
     29 #include "ui/base/ime/input_method.h"
     30 #include "ui/base/ime/text_input_client.h"
     31 #include "ui/base/ime/text_input_focus_manager.h"
     32 #include "ui/base/ui_base_switches_util.h"
     33 #include "ui/events/test/event_generator.h"
     34 #include "ui/events/test/test_event_handler.h"
     35 #include "ui/keyboard/keyboard_controller_proxy.h"
     36 #include "ui/keyboard/keyboard_switches.h"
     37 #include "ui/keyboard/keyboard_util.h"
     38 #include "ui/views/controls/menu/menu_controller.h"
     39 #include "ui/views/widget/widget.h"
     40 #include "ui/views/widget/widget_delegate.h"
     41 
     42 using aura::Window;
     43 using views::Widget;
     44 
     45 namespace ash {
     46 namespace {
     47 
     48 class TestDelegate : public views::WidgetDelegateView {
     49  public:
     50   explicit TestDelegate(bool system_modal) : system_modal_(system_modal) {}
     51   virtual ~TestDelegate() {}
     52 
     53   // Overridden from views::WidgetDelegate:
     54   virtual views::View* GetContentsView() OVERRIDE {
     55     return this;
     56   }
     57 
     58   virtual ui::ModalType GetModalType() const OVERRIDE {
     59     return system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE;
     60   }
     61 
     62  private:
     63   bool system_modal_;
     64 
     65   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
     66 };
     67 
     68 class DeleteOnBlurDelegate : public aura::test::TestWindowDelegate,
     69                              public aura::client::FocusChangeObserver {
     70  public:
     71   DeleteOnBlurDelegate() : window_(NULL) {}
     72   virtual ~DeleteOnBlurDelegate() {}
     73 
     74   void SetWindow(aura::Window* window) {
     75     window_ = window;
     76     aura::client::SetFocusChangeObserver(window_, this);
     77   }
     78 
     79  private:
     80   // aura::test::TestWindowDelegate overrides:
     81   virtual bool CanFocus() OVERRIDE {
     82     return true;
     83   }
     84 
     85   // aura::client::FocusChangeObserver implementation:
     86   virtual void OnWindowFocused(aura::Window* gained_focus,
     87                                aura::Window* lost_focus) OVERRIDE {
     88     if (window_ == lost_focus)
     89       delete window_;
     90   }
     91 
     92   aura::Window* window_;
     93 
     94   DISALLOW_COPY_AND_ASSIGN(DeleteOnBlurDelegate);
     95 };
     96 
     97 }  // namespace
     98 
     99 namespace test {
    100 
    101 class RootWindowControllerTest : public test::AshTestBase {
    102  public:
    103   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
    104     views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
    105         NULL, CurrentContext(), bounds);
    106     widget->Show();
    107     return widget;
    108   }
    109 
    110   views::Widget* CreateModalWidget(const gfx::Rect& bounds) {
    111     views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
    112         new TestDelegate(true), CurrentContext(), bounds);
    113     widget->Show();
    114     return widget;
    115   }
    116 
    117   views::Widget* CreateModalWidgetWithParent(const gfx::Rect& bounds,
    118                                              gfx::NativeWindow parent) {
    119     views::Widget* widget =
    120         views::Widget::CreateWindowWithParentAndBounds(new TestDelegate(true),
    121                                                        parent,
    122                                                        bounds);
    123     widget->Show();
    124     return widget;
    125   }
    126 
    127   aura::Window* GetModalContainer(aura::Window* root_window) {
    128     return Shell::GetContainer(root_window,
    129                                ash::kShellWindowId_SystemModalContainer);
    130   }
    131 };
    132 
    133 TEST_F(RootWindowControllerTest, MoveWindows_Basic) {
    134   if (!SupportsMultipleDisplays())
    135     return;
    136   // Windows origin should be doubled when moved to the 1st display.
    137   UpdateDisplay("600x600,300x300");
    138   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    139   RootWindowController* controller = Shell::GetPrimaryRootWindowController();
    140   ShelfLayoutManager* shelf_layout_manager =
    141       controller->GetShelfLayoutManager();
    142   shelf_layout_manager->SetAutoHideBehavior(
    143       ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    144 
    145   views::Widget* normal = CreateTestWidget(gfx::Rect(650, 10, 100, 100));
    146   EXPECT_EQ(root_windows[1], normal->GetNativeView()->GetRootWindow());
    147   EXPECT_EQ("650,10 100x100", normal->GetWindowBoundsInScreen().ToString());
    148   EXPECT_EQ("50,10 100x100",
    149             normal->GetNativeView()->GetBoundsInRootWindow().ToString());
    150 
    151   views::Widget* maximized = CreateTestWidget(gfx::Rect(700, 10, 100, 100));
    152   maximized->Maximize();
    153   EXPECT_EQ(root_windows[1], maximized->GetNativeView()->GetRootWindow());
    154   EXPECT_EQ("600,0 300x253", maximized->GetWindowBoundsInScreen().ToString());
    155   EXPECT_EQ("0,0 300x253",
    156             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
    157 
    158   views::Widget* minimized = CreateTestWidget(gfx::Rect(800, 10, 100, 100));
    159   minimized->Minimize();
    160   EXPECT_EQ(root_windows[1], minimized->GetNativeView()->GetRootWindow());
    161   EXPECT_EQ("800,10 100x100",
    162             minimized->GetWindowBoundsInScreen().ToString());
    163 
    164   views::Widget* fullscreen = CreateTestWidget(gfx::Rect(850, 10, 100, 100));
    165   fullscreen->SetFullscreen(true);
    166   EXPECT_EQ(root_windows[1], fullscreen->GetNativeView()->GetRootWindow());
    167 
    168   EXPECT_EQ("600,0 300x300",
    169             fullscreen->GetWindowBoundsInScreen().ToString());
    170   EXPECT_EQ("0,0 300x300",
    171             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
    172 
    173   views::Widget* unparented_control = new Widget;
    174   Widget::InitParams params;
    175   params.bounds = gfx::Rect(650, 10, 100, 100);
    176   params.context = CurrentContext();
    177   params.type = Widget::InitParams::TYPE_CONTROL;
    178   unparented_control->Init(params);
    179   EXPECT_EQ(root_windows[1],
    180             unparented_control->GetNativeView()->GetRootWindow());
    181   EXPECT_EQ(kShellWindowId_UnparentedControlContainer,
    182             unparented_control->GetNativeView()->parent()->id());
    183 
    184   aura::Window* panel = CreateTestWindowInShellWithDelegateAndType(
    185       NULL, ui::wm::WINDOW_TYPE_PANEL, 0, gfx::Rect(700, 100, 100, 100));
    186   EXPECT_EQ(root_windows[1], panel->GetRootWindow());
    187   EXPECT_EQ(kShellWindowId_PanelContainer, panel->parent()->id());
    188 
    189   // Make sure a window that will delete itself when losing focus
    190   // will not crash.
    191   aura::WindowTracker tracker;
    192   DeleteOnBlurDelegate delete_on_blur_delegate;
    193   aura::Window* d2 = CreateTestWindowInShellWithDelegate(
    194       &delete_on_blur_delegate, 0, gfx::Rect(50, 50, 100, 100));
    195   delete_on_blur_delegate.SetWindow(d2);
    196   aura::client::GetFocusClient(root_windows[0])->FocusWindow(d2);
    197   tracker.Add(d2);
    198 
    199   UpdateDisplay("600x600");
    200 
    201   // d2 must have been deleted.
    202   EXPECT_FALSE(tracker.Contains(d2));
    203 
    204   EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
    205   EXPECT_EQ("100,20 100x100", normal->GetWindowBoundsInScreen().ToString());
    206   EXPECT_EQ("100,20 100x100",
    207             normal->GetNativeView()->GetBoundsInRootWindow().ToString());
    208 
    209   // Maximized area on primary display has 3px (given as
    210   // kAutoHideSize in shelf_layout_manager.cc) inset at the bottom.
    211 
    212   // First clear fullscreen status, since both fullscreen and maximized windows
    213   // share the same desktop workspace, which cancels the shelf status.
    214   fullscreen->SetFullscreen(false);
    215   EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
    216   EXPECT_EQ("0,0 600x597",
    217             maximized->GetWindowBoundsInScreen().ToString());
    218   EXPECT_EQ("0,0 600x597",
    219             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
    220 
    221   // Set fullscreen to true. In that case the 3px inset becomes invisible so
    222   // the maximized window can also use the area fully.
    223   fullscreen->SetFullscreen(true);
    224   EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
    225   EXPECT_EQ("0,0 600x600",
    226             maximized->GetWindowBoundsInScreen().ToString());
    227   EXPECT_EQ("0,0 600x600",
    228             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
    229 
    230   EXPECT_EQ(root_windows[0], minimized->GetNativeView()->GetRootWindow());
    231   EXPECT_EQ("400,20 100x100",
    232             minimized->GetWindowBoundsInScreen().ToString());
    233 
    234   EXPECT_EQ(root_windows[0], fullscreen->GetNativeView()->GetRootWindow());
    235   EXPECT_TRUE(fullscreen->IsFullscreen());
    236   EXPECT_EQ("0,0 600x600",
    237             fullscreen->GetWindowBoundsInScreen().ToString());
    238   EXPECT_EQ("0,0 600x600",
    239             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
    240 
    241   // Test if the restore bounds are correctly updated.
    242   wm::GetWindowState(maximized->GetNativeView())->Restore();
    243   EXPECT_EQ("200,20 100x100", maximized->GetWindowBoundsInScreen().ToString());
    244   EXPECT_EQ("200,20 100x100",
    245             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
    246 
    247   fullscreen->SetFullscreen(false);
    248   EXPECT_EQ("500,20 100x100",
    249             fullscreen->GetWindowBoundsInScreen().ToString());
    250   EXPECT_EQ("500,20 100x100",
    251             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
    252 
    253   // Test if the unparented widget has moved.
    254   EXPECT_EQ(root_windows[0],
    255             unparented_control->GetNativeView()->GetRootWindow());
    256   EXPECT_EQ(kShellWindowId_UnparentedControlContainer,
    257             unparented_control->GetNativeView()->parent()->id());
    258 
    259   // Test if the panel has moved.
    260   EXPECT_EQ(root_windows[0], panel->GetRootWindow());
    261   EXPECT_EQ(kShellWindowId_PanelContainer, panel->parent()->id());
    262 }
    263 
    264 TEST_F(RootWindowControllerTest, MoveWindows_Modal) {
    265   if (!SupportsMultipleDisplays())
    266     return;
    267 
    268   UpdateDisplay("500x500,500x500");
    269 
    270   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    271   // Emulate virtual screen coordinate system.
    272   root_windows[0]->SetBounds(gfx::Rect(0, 0, 500, 500));
    273   root_windows[1]->SetBounds(gfx::Rect(500, 0, 500, 500));
    274 
    275   views::Widget* normal = CreateTestWidget(gfx::Rect(300, 10, 100, 100));
    276   EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
    277   EXPECT_TRUE(wm::IsActiveWindow(normal->GetNativeView()));
    278 
    279   views::Widget* modal = CreateModalWidget(gfx::Rect(650, 10, 100, 100));
    280   EXPECT_EQ(root_windows[1], modal->GetNativeView()->GetRootWindow());
    281   EXPECT_TRUE(GetModalContainer(root_windows[1])->Contains(
    282       modal->GetNativeView()));
    283   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
    284 
    285   ui::test::EventGenerator generator_1st(root_windows[0]);
    286   generator_1st.ClickLeftButton();
    287   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
    288 
    289   UpdateDisplay("500x500");
    290   EXPECT_EQ(root_windows[0], modal->GetNativeView()->GetRootWindow());
    291   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
    292   generator_1st.ClickLeftButton();
    293   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
    294 }
    295 
    296 TEST_F(RootWindowControllerTest, ModalContainer) {
    297   UpdateDisplay("600x600");
    298   Shell* shell = Shell::GetInstance();
    299   RootWindowController* controller = shell->GetPrimaryRootWindowController();
    300   EXPECT_EQ(user::LOGGED_IN_USER,
    301             shell->system_tray_delegate()->GetUserLoginStatus());
    302   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    303                 ->layout_manager(),
    304             controller->GetSystemModalLayoutManager(NULL));
    305 
    306   views::Widget* session_modal_widget =
    307       CreateModalWidget(gfx::Rect(300, 10, 100, 100));
    308   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    309                 ->layout_manager(),
    310             controller->GetSystemModalLayoutManager(
    311                 session_modal_widget->GetNativeView()));
    312 
    313   shell->session_state_delegate()->LockScreen();
    314   EXPECT_EQ(user::LOGGED_IN_LOCKED,
    315             shell->system_tray_delegate()->GetUserLoginStatus());
    316   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    317                 ->layout_manager(),
    318             controller->GetSystemModalLayoutManager(NULL));
    319 
    320   aura::Window* lock_container =
    321       controller->GetContainer(kShellWindowId_LockScreenContainer);
    322   views::Widget* lock_modal_widget =
    323       CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
    324   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    325                 ->layout_manager(),
    326             controller->GetSystemModalLayoutManager(
    327                 lock_modal_widget->GetNativeView()));
    328   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    329                 ->layout_manager(),
    330             controller->GetSystemModalLayoutManager(
    331                 session_modal_widget->GetNativeView()));
    332 
    333   shell->session_state_delegate()->UnlockScreen();
    334 }
    335 
    336 TEST_F(RootWindowControllerTest, ModalContainerNotLoggedInLoggedIn) {
    337   UpdateDisplay("600x600");
    338   Shell* shell = Shell::GetInstance();
    339 
    340   // Configure login screen environment.
    341   SetUserLoggedIn(false);
    342   EXPECT_EQ(user::LOGGED_IN_NONE,
    343             shell->system_tray_delegate()->GetUserLoginStatus());
    344   EXPECT_EQ(0, shell->session_state_delegate()->NumberOfLoggedInUsers());
    345   EXPECT_FALSE(shell->session_state_delegate()->IsActiveUserSessionStarted());
    346 
    347   RootWindowController* controller = shell->GetPrimaryRootWindowController();
    348   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    349                 ->layout_manager(),
    350             controller->GetSystemModalLayoutManager(NULL));
    351 
    352   aura::Window* lock_container =
    353       controller->GetContainer(kShellWindowId_LockScreenContainer);
    354   views::Widget* login_modal_widget =
    355       CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
    356   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    357                 ->layout_manager(),
    358             controller->GetSystemModalLayoutManager(
    359                 login_modal_widget->GetNativeView()));
    360   login_modal_widget->Close();
    361 
    362   // Configure user session environment.
    363   SetUserLoggedIn(true);
    364   SetSessionStarted(true);
    365   EXPECT_EQ(user::LOGGED_IN_USER,
    366             shell->system_tray_delegate()->GetUserLoginStatus());
    367   EXPECT_EQ(1, shell->session_state_delegate()->NumberOfLoggedInUsers());
    368   EXPECT_TRUE(shell->session_state_delegate()->IsActiveUserSessionStarted());
    369   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    370                 ->layout_manager(),
    371             controller->GetSystemModalLayoutManager(NULL));
    372 
    373   views::Widget* session_modal_widget =
    374         CreateModalWidget(gfx::Rect(300, 10, 100, 100));
    375   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    376                 ->layout_manager(),
    377             controller->GetSystemModalLayoutManager(
    378                 session_modal_widget->GetNativeView()));
    379 }
    380 
    381 TEST_F(RootWindowControllerTest, ModalContainerBlockedSession) {
    382   UpdateDisplay("600x600");
    383   Shell* shell = Shell::GetInstance();
    384   RootWindowController* controller = shell->GetPrimaryRootWindowController();
    385   aura::Window* lock_container =
    386       controller->GetContainer(kShellWindowId_LockScreenContainer);
    387   for (int block_reason = FIRST_BLOCK_REASON;
    388        block_reason < NUMBER_OF_BLOCK_REASONS;
    389        ++block_reason) {
    390     views::Widget* session_modal_widget =
    391           CreateModalWidget(gfx::Rect(300, 10, 100, 100));
    392     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    393                   ->layout_manager(),
    394               controller->GetSystemModalLayoutManager(
    395                   session_modal_widget->GetNativeView()));
    396     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    397                   ->layout_manager(),
    398               controller->GetSystemModalLayoutManager(NULL));
    399     session_modal_widget->Close();
    400 
    401     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
    402 
    403     EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    404                   ->layout_manager(),
    405               controller->GetSystemModalLayoutManager(NULL));
    406 
    407     views::Widget* lock_modal_widget =
    408         CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100),
    409                                     lock_container);
    410     EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
    411                   ->layout_manager(),
    412               controller->GetSystemModalLayoutManager(
    413                   lock_modal_widget->GetNativeView()));
    414 
    415     session_modal_widget =
    416           CreateModalWidget(gfx::Rect(300, 10, 100, 100));
    417     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
    418                   ->layout_manager(),
    419               controller->GetSystemModalLayoutManager(
    420                   session_modal_widget->GetNativeView()));
    421     session_modal_widget->Close();
    422 
    423     lock_modal_widget->Close();
    424     UnblockUserSession();
    425   }
    426 }
    427 
    428 TEST_F(RootWindowControllerTest, GetWindowForFullscreenMode) {
    429   UpdateDisplay("600x600");
    430   RootWindowController* controller =
    431       Shell::GetInstance()->GetPrimaryRootWindowController();
    432 
    433   Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
    434   w1->Maximize();
    435   Widget* w2 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
    436   w2->SetFullscreen(true);
    437   // |w3| is a transient child of |w2|.
    438   Widget* w3 = Widget::CreateWindowWithParentAndBounds(NULL,
    439       w2->GetNativeWindow(), gfx::Rect(0, 0, 100, 100));
    440 
    441   // Test that GetWindowForFullscreenMode() finds the fullscreen window when one
    442   // of its transient children is active.
    443   w3->Activate();
    444   EXPECT_EQ(w2->GetNativeWindow(), controller->GetWindowForFullscreenMode());
    445 
    446   // If the topmost window is not fullscreen, it returns NULL.
    447   w1->Activate();
    448   EXPECT_EQ(NULL, controller->GetWindowForFullscreenMode());
    449   w1->Close();
    450   w3->Close();
    451 
    452   // Only w2 remains, if minimized GetWindowForFullscreenMode should return
    453   // NULL.
    454   w2->Activate();
    455   EXPECT_EQ(w2->GetNativeWindow(), controller->GetWindowForFullscreenMode());
    456   w2->Minimize();
    457   EXPECT_EQ(NULL, controller->GetWindowForFullscreenMode());
    458 }
    459 
    460 TEST_F(RootWindowControllerTest, MultipleDisplaysGetWindowForFullscreenMode) {
    461   if (!SupportsMultipleDisplays())
    462     return;
    463 
    464   UpdateDisplay("600x600,600x600");
    465   Shell::RootWindowControllerList controllers =
    466       Shell::GetInstance()->GetAllRootWindowControllers();
    467 
    468   Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
    469   w1->Maximize();
    470   Widget* w2 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
    471   w2->SetFullscreen(true);
    472   Widget* w3 = CreateTestWidget(gfx::Rect(600, 0, 100, 100));
    473 
    474   EXPECT_EQ(w1->GetNativeWindow()->GetRootWindow(),
    475             controllers[0]->GetRootWindow());
    476   EXPECT_EQ(w2->GetNativeWindow()->GetRootWindow(),
    477             controllers[0]->GetRootWindow());
    478   EXPECT_EQ(w3->GetNativeWindow()->GetRootWindow(),
    479             controllers[1]->GetRootWindow());
    480 
    481   w1->Activate();
    482   EXPECT_EQ(NULL, controllers[0]->GetWindowForFullscreenMode());
    483   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
    484 
    485   w2->Activate();
    486   EXPECT_EQ(w2->GetNativeWindow(),
    487             controllers[0]->GetWindowForFullscreenMode());
    488   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
    489 
    490   // Verify that the first root window controller remains in fullscreen mode
    491   // when a window on the other display is activated.
    492   w3->Activate();
    493   EXPECT_EQ(w2->GetNativeWindow(),
    494             controllers[0]->GetWindowForFullscreenMode());
    495   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
    496 }
    497 
    498 // Test that user session window can't be focused if user session blocked by
    499 // some overlapping UI.
    500 TEST_F(RootWindowControllerTest, FocusBlockedWindow) {
    501   UpdateDisplay("600x600");
    502   RootWindowController* controller =
    503       Shell::GetInstance()->GetPrimaryRootWindowController();
    504   aura::Window* lock_container =
    505       controller->GetContainer(kShellWindowId_LockScreenContainer);
    506   aura::Window* lock_window = Widget::CreateWindowWithParentAndBounds(NULL,
    507       lock_container, gfx::Rect(0, 0, 100, 100))->GetNativeView();
    508   lock_window->Show();
    509   aura::Window* session_window =
    510       CreateTestWidget(gfx::Rect(0, 0, 100, 100))->GetNativeView();
    511   session_window->Show();
    512 
    513   for (int block_reason = FIRST_BLOCK_REASON;
    514        block_reason < NUMBER_OF_BLOCK_REASONS;
    515        ++block_reason) {
    516     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
    517     lock_window->Focus();
    518     EXPECT_TRUE(lock_window->HasFocus());
    519     session_window->Focus();
    520     EXPECT_FALSE(session_window->HasFocus());
    521     UnblockUserSession();
    522   }
    523 }
    524 
    525 // Tracks whether OnWindowDestroying() has been invoked.
    526 class DestroyedWindowObserver : public aura::WindowObserver {
    527  public:
    528   DestroyedWindowObserver() : destroyed_(false), window_(NULL) {}
    529   virtual ~DestroyedWindowObserver() {
    530     Shutdown();
    531   }
    532 
    533   void SetWindow(Window* window) {
    534     window_ = window;
    535     window->AddObserver(this);
    536   }
    537 
    538   bool destroyed() const { return destroyed_; }
    539 
    540   // WindowObserver overrides:
    541   virtual void OnWindowDestroying(Window* window) OVERRIDE {
    542     destroyed_ = true;
    543     Shutdown();
    544   }
    545 
    546  private:
    547   void Shutdown() {
    548     if (!window_)
    549       return;
    550     window_->RemoveObserver(this);
    551     window_ = NULL;
    552   }
    553 
    554   bool destroyed_;
    555   Window* window_;
    556 
    557   DISALLOW_COPY_AND_ASSIGN(DestroyedWindowObserver);
    558 };
    559 
    560 // Verifies shutdown doesn't delete windows that are not owned by the parent.
    561 TEST_F(RootWindowControllerTest, DontDeleteWindowsNotOwnedByParent) {
    562   DestroyedWindowObserver observer1;
    563   aura::test::TestWindowDelegate delegate1;
    564   aura::Window* window1 = new aura::Window(&delegate1);
    565   window1->SetType(ui::wm::WINDOW_TYPE_CONTROL);
    566   window1->set_owned_by_parent(false);
    567   observer1.SetWindow(window1);
    568   window1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
    569   aura::client::ParentWindowWithContext(
    570       window1, Shell::GetInstance()->GetPrimaryRootWindow(), gfx::Rect());
    571 
    572   DestroyedWindowObserver observer2;
    573   aura::Window* window2 = new aura::Window(NULL);
    574   window2->set_owned_by_parent(false);
    575   observer2.SetWindow(window2);
    576   window2->Init(aura::WINDOW_LAYER_NOT_DRAWN);
    577   Shell::GetInstance()->GetPrimaryRootWindow()->AddChild(window2);
    578 
    579   Shell::GetInstance()->GetPrimaryRootWindowController()->CloseChildWindows();
    580 
    581   ASSERT_FALSE(observer1.destroyed());
    582   delete window1;
    583 
    584   ASSERT_FALSE(observer2.destroyed());
    585   delete window2;
    586 }
    587 
    588 typedef test::NoSessionAshTestBase NoSessionRootWindowControllerTest;
    589 
    590 // Make sure that an event handler exists for entire display area.
    591 TEST_F(NoSessionRootWindowControllerTest, Event) {
    592   // Hide the shelf since it might otherwise get an event target.
    593   RootWindowController* controller = Shell::GetPrimaryRootWindowController();
    594   ShelfLayoutManager* shelf_layout_manager =
    595       controller->GetShelfLayoutManager();
    596   shelf_layout_manager->SetAutoHideBehavior(
    597       ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
    598 
    599   aura::Window* root = Shell::GetPrimaryRootWindow();
    600   const gfx::Size size = root->bounds().size();
    601   aura::Window* event_target = root->GetEventHandlerForPoint(gfx::Point(0, 0));
    602   EXPECT_TRUE(event_target);
    603   EXPECT_EQ(event_target,
    604             root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
    605   EXPECT_EQ(event_target,
    606             root->GetEventHandlerForPoint(gfx::Point(size.width() - 1, 0)));
    607   EXPECT_EQ(event_target,
    608             root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
    609   EXPECT_EQ(event_target,
    610             root->GetEventHandlerForPoint(
    611                 gfx::Point(size.width() - 1, size.height() - 1)));
    612 }
    613 
    614 class VirtualKeyboardRootWindowControllerTest
    615     : public RootWindowControllerTest {
    616  public:
    617   VirtualKeyboardRootWindowControllerTest() {};
    618   virtual ~VirtualKeyboardRootWindowControllerTest() {};
    619 
    620   virtual void SetUp() OVERRIDE {
    621     CommandLine::ForCurrentProcess()->AppendSwitch(
    622         keyboard::switches::kEnableVirtualKeyboard);
    623     test::AshTestBase::SetUp();
    624     Shell::GetPrimaryRootWindowController()->ActivateKeyboard(
    625         keyboard::KeyboardController::GetInstance());
    626   }
    627 
    628  private:
    629   DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardRootWindowControllerTest);
    630 };
    631 
    632 class MockTextInputClient : public ui::DummyTextInputClient {
    633  public:
    634   MockTextInputClient() :
    635       ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT) {}
    636 
    637   virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {
    638     visible_rect_ = rect;
    639   }
    640 
    641   const gfx::Rect& visible_rect() const {
    642     return visible_rect_;
    643   }
    644 
    645  private:
    646   gfx::Rect visible_rect_;
    647 
    648   DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
    649 };
    650 
    651 class TargetHitTestEventHandler : public ui::test::TestEventHandler {
    652  public:
    653   TargetHitTestEventHandler() {}
    654 
    655   // ui::test::TestEventHandler overrides.
    656   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
    657     if (event->type() == ui::ET_MOUSE_PRESSED)
    658       ui::test::TestEventHandler::OnMouseEvent(event);
    659     event->StopPropagation();
    660   }
    661 
    662  private:
    663   DISALLOW_COPY_AND_ASSIGN(TargetHitTestEventHandler);
    664 };
    665 
    666 // Test for http://crbug.com/297858. Virtual keyboard container should only show
    667 // on primary root window.
    668 TEST_F(VirtualKeyboardRootWindowControllerTest,
    669        VirtualKeyboardOnPrimaryRootWindowOnly) {
    670   if (!SupportsMultipleDisplays())
    671     return;
    672 
    673   UpdateDisplay("500x500,500x500");
    674 
    675   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    676   aura::Window* primary_root_window = Shell::GetPrimaryRootWindow();
    677   aura::Window* secondary_root_window =
    678       root_windows[0] == primary_root_window ?
    679           root_windows[1] : root_windows[0];
    680 
    681   ASSERT_TRUE(Shell::GetContainer(primary_root_window,
    682                                   kShellWindowId_VirtualKeyboardContainer));
    683   ASSERT_FALSE(Shell::GetContainer(secondary_root_window,
    684                                    kShellWindowId_VirtualKeyboardContainer));
    685 }
    686 
    687 // Test for http://crbug.com/263599. Virtual keyboard should be able to receive
    688 // events at blocked user session.
    689 TEST_F(VirtualKeyboardRootWindowControllerTest,
    690        ClickVirtualKeyboardInBlockedWindow) {
    691   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    692   aura::Window* keyboard_container =
    693       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    694   ASSERT_TRUE(keyboard_container);
    695   keyboard_container->Show();
    696 
    697   aura::Window* keyboard_window = keyboard::KeyboardController::GetInstance()->
    698       proxy()->GetKeyboardWindow();
    699   keyboard_container->AddChild(keyboard_window);
    700   keyboard_window->set_owned_by_parent(false);
    701   keyboard_window->SetBounds(gfx::Rect());
    702   keyboard_window->Show();
    703 
    704   ui::test::TestEventHandler handler;
    705   root_window->AddPreTargetHandler(&handler);
    706 
    707   ui::test::EventGenerator event_generator(root_window, keyboard_window);
    708   event_generator.ClickLeftButton();
    709   int expected_mouse_presses = 1;
    710   EXPECT_EQ(expected_mouse_presses, handler.num_mouse_events() / 2);
    711 
    712   for (int block_reason = FIRST_BLOCK_REASON;
    713        block_reason < NUMBER_OF_BLOCK_REASONS;
    714        ++block_reason) {
    715     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
    716     event_generator.ClickLeftButton();
    717     expected_mouse_presses++;
    718     EXPECT_EQ(expected_mouse_presses, handler.num_mouse_events() / 2);
    719     UnblockUserSession();
    720   }
    721   root_window->RemovePreTargetHandler(&handler);
    722 }
    723 
    724 // Test for http://crbug.com/299787. RootWindowController should delete
    725 // the old container since the keyboard controller creates a new window in
    726 // GetWindowContainer().
    727 TEST_F(VirtualKeyboardRootWindowControllerTest,
    728        DeleteOldContainerOnVirtualKeyboardInit) {
    729   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    730   aura::Window* keyboard_container =
    731       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    732   ASSERT_TRUE(keyboard_container);
    733   // Track the keyboard container window.
    734   aura::WindowTracker tracker;
    735   tracker.Add(keyboard_container);
    736   // Mock a login user profile change to reinitialize the keyboard.
    737   ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
    738   // keyboard_container should no longer be present.
    739   EXPECT_FALSE(tracker.Contains(keyboard_container));
    740 }
    741 
    742 // Test for crbug.com/342524. After user login, the work space should restore to
    743 // full screen.
    744 TEST_F(VirtualKeyboardRootWindowControllerTest, RestoreWorkspaceAfterLogin) {
    745   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    746   aura::Window* keyboard_container =
    747       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    748   keyboard_container->Show();
    749   keyboard::KeyboardController* controller =
    750       keyboard::KeyboardController::GetInstance();
    751   aura::Window* keyboard_window = controller->proxy()->GetKeyboardWindow();
    752   keyboard_container->AddChild(keyboard_window);
    753   keyboard_window->set_owned_by_parent(false);
    754   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
    755       keyboard_container->bounds(), 100));
    756   keyboard_window->Show();
    757 
    758   gfx::Rect before = ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
    759 
    760   // Notify keyboard bounds changing.
    761   controller->NotifyKeyboardBoundsChanging(
    762       controller->proxy()->GetKeyboardWindow()->bounds());
    763 
    764   if (!keyboard::IsKeyboardOverscrollEnabled()) {
    765     gfx::Rect after = ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
    766     EXPECT_LT(after, before);
    767   }
    768 
    769   // Mock a login user profile change to reinitialize the keyboard.
    770   ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
    771   EXPECT_EQ(ash::Shell::GetScreen()->GetPrimaryDisplay().work_area(), before);
    772 }
    773 
    774 // Ensure that system modal dialogs do not block events targeted at the virtual
    775 // keyboard.
    776 TEST_F(VirtualKeyboardRootWindowControllerTest, ClickWithActiveModalDialog) {
    777   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    778   aura::Window* keyboard_container =
    779       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    780   ASSERT_TRUE(keyboard_container);
    781   keyboard_container->Show();
    782 
    783   aura::Window* keyboard_window = keyboard::KeyboardController::GetInstance()->
    784       proxy()->GetKeyboardWindow();
    785   keyboard_container->AddChild(keyboard_window);
    786   keyboard_window->set_owned_by_parent(false);
    787   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
    788       keyboard_container->bounds(), 100));
    789 
    790   ui::test::TestEventHandler handler;
    791   root_window->AddPreTargetHandler(&handler);
    792   ui::test::EventGenerator root_window_event_generator(root_window);
    793   ui::test::EventGenerator keyboard_event_generator(root_window,
    794                                                     keyboard_window);
    795 
    796   views::Widget* modal_widget =
    797       CreateModalWidget(gfx::Rect(300, 10, 100, 100));
    798 
    799   // Verify that mouse events to the root window are block with a visble modal
    800   // dialog.
    801   root_window_event_generator.ClickLeftButton();
    802   EXPECT_EQ(0, handler.num_mouse_events());
    803 
    804   // Verify that event dispatch to the virtual keyboard is unblocked.
    805   keyboard_event_generator.ClickLeftButton();
    806   EXPECT_EQ(1, handler.num_mouse_events() / 2);
    807 
    808   modal_widget->Close();
    809 
    810   // Verify that mouse events are now unblocked to the root window.
    811   root_window_event_generator.ClickLeftButton();
    812   EXPECT_EQ(2, handler.num_mouse_events() / 2);
    813   root_window->RemovePreTargetHandler(&handler);
    814 }
    815 
    816 // Ensure that the visible area for scrolling the text caret excludes the
    817 // region occluded by the on-screen keyboard.
    818 TEST_F(VirtualKeyboardRootWindowControllerTest, EnsureCaretInWorkArea) {
    819   keyboard::KeyboardController* keyboard_controller =
    820       keyboard::KeyboardController::GetInstance();
    821   keyboard::KeyboardControllerProxy* proxy = keyboard_controller->proxy();
    822 
    823   MockTextInputClient text_input_client;
    824   ui::InputMethod* input_method = proxy->GetInputMethod();
    825   ASSERT_TRUE(input_method);
    826   if (switches::IsTextInputFocusManagerEnabled()) {
    827     ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(
    828         &text_input_client);
    829   } else {
    830     input_method->SetFocusedTextInputClient(&text_input_client);
    831   }
    832 
    833   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    834   aura::Window* keyboard_container =
    835       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    836   ASSERT_TRUE(keyboard_container);
    837   keyboard_container->Show();
    838 
    839   const int keyboard_height = 100;
    840   aura::Window* keyboard_window =proxy->GetKeyboardWindow();
    841   keyboard_container->AddChild(keyboard_window);
    842   keyboard_window->set_owned_by_parent(false);
    843   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
    844       keyboard_container->bounds(), keyboard_height));
    845 
    846   proxy->EnsureCaretInWorkArea();
    847   ASSERT_EQ(keyboard_container->bounds().width(),
    848             text_input_client.visible_rect().width());
    849   ASSERT_EQ(keyboard_container->bounds().height() - keyboard_height,
    850             text_input_client.visible_rect().height());
    851 
    852   if (switches::IsTextInputFocusManagerEnabled()) {
    853     ui::TextInputFocusManager::GetInstance()->BlurTextInputClient(
    854         &text_input_client);
    855   } else {
    856     input_method->SetFocusedTextInputClient(NULL);
    857   }
    858 }
    859 
    860 // Tests that the virtual keyboard does not block context menus. The virtual
    861 // keyboard should appear in front of most content, but not context menus. See
    862 // crbug/377180.
    863 TEST_F(VirtualKeyboardRootWindowControllerTest, ZOrderTest) {
    864   UpdateDisplay("800x600");
    865   keyboard::KeyboardController* keyboard_controller =
    866       keyboard::KeyboardController::GetInstance();
    867   keyboard::KeyboardControllerProxy* proxy = keyboard_controller->proxy();
    868 
    869   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    870   aura::Window* keyboard_container =
    871       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    872   ASSERT_TRUE(keyboard_container);
    873   keyboard_container->Show();
    874 
    875   const int keyboard_height = 200;
    876   aura::Window* keyboard_window = proxy->GetKeyboardWindow();
    877   keyboard_container->AddChild(keyboard_window);
    878   keyboard_window->set_owned_by_parent(false);
    879   gfx::Rect keyboard_bounds = keyboard::KeyboardBoundsFromWindowBounds(
    880       keyboard_container->bounds(), keyboard_height);
    881   keyboard_window->SetBounds(keyboard_bounds);
    882   keyboard_window->Show();
    883 
    884   ui::test::EventGenerator generator(root_window);
    885 
    886   // Cover the screen with two windows: a normal window on the left side and a
    887   // context menu on the right side. When the virtual keyboard is displayed it
    888   // partially occludes the normal window, but not the context menu. Compute
    889   // positions for generating synthetic click events to perform hit tests,
    890   // ensuring the correct window layering. 'top' is above the VK, whereas
    891   // 'bottom' lies within the VK. 'left' is centered in the normal window, and
    892   // 'right' is centered in the context menu.
    893   int window_height = keyboard_bounds.bottom();
    894   int window_width = keyboard_bounds.width() / 2;
    895   int left = window_width / 2;
    896   int right = 3 * window_width / 2;
    897   int top = keyboard_bounds.y() / 2;
    898   int bottom = window_height - keyboard_height / 2;
    899 
    900   // Normal window is partially occluded by the virtual keyboard.
    901   aura::test::TestWindowDelegate delegate;
    902   scoped_ptr<aura::Window> normal(CreateTestWindowInShellWithDelegateAndType(
    903       &delegate,
    904       ui::wm::WINDOW_TYPE_NORMAL,
    905       0,
    906       gfx::Rect(0, 0, window_width, window_height)));
    907   normal->set_owned_by_parent(false);
    908   normal->Show();
    909   TargetHitTestEventHandler normal_handler;
    910   normal->AddPreTargetHandler(&normal_handler);
    911 
    912   // Test that only the click on the top portion of the window is picked up. The
    913   // click on the bottom hits the virtual keyboard instead.
    914   generator.MoveMouseTo(left, top);
    915   generator.ClickLeftButton();
    916   EXPECT_EQ(1, normal_handler.num_mouse_events());
    917   generator.MoveMouseTo(left, bottom);
    918   generator.ClickLeftButton();
    919   EXPECT_EQ(1, normal_handler.num_mouse_events());
    920 
    921   // Menu overlaps virtual keyboard.
    922   aura::test::TestWindowDelegate delegate2;
    923   scoped_ptr<aura::Window> menu(CreateTestWindowInShellWithDelegateAndType(
    924       &delegate2,
    925       ui::wm::WINDOW_TYPE_MENU,
    926       0,
    927       gfx::Rect(window_width, 0, window_width, window_height)));
    928   menu->set_owned_by_parent(false);
    929   menu->Show();
    930   TargetHitTestEventHandler menu_handler;
    931   menu->AddPreTargetHandler(&menu_handler);
    932 
    933   // Test that both clicks register.
    934   generator.MoveMouseTo(right, top);
    935   generator.ClickLeftButton();
    936   EXPECT_EQ(1, menu_handler.num_mouse_events());
    937   generator.MoveMouseTo(right, bottom);
    938   generator.ClickLeftButton();
    939   EXPECT_EQ(2, menu_handler.num_mouse_events());
    940 
    941   // Cleanup to ensure that the test windows are destroyed before their
    942   // delegates.
    943   normal.reset();
    944   menu.reset();
    945 }
    946 
    947 // Resolution in UpdateDisplay is not being respected on Windows 8.
    948 #if defined(OS_WIN)
    949 #define MAYBE_DisplayRotation DISABLED_DisplayRotation
    950 #else
    951 #define MAYBE_DisplayRotation DisplayRotation
    952 #endif
    953 
    954 // Tests that the virtual keyboard correctly resizes with a change to display
    955 // orientation. See crbug/417612.
    956 TEST_F(VirtualKeyboardRootWindowControllerTest, MAYBE_DisplayRotation) {
    957   UpdateDisplay("800x600");
    958   aura::Window* root_window = Shell::GetPrimaryRootWindow();
    959   aura::Window* keyboard_container =
    960       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
    961   ASSERT_TRUE(keyboard_container);
    962   keyboard_container->Show();
    963   EXPECT_EQ("0,0 800x600", keyboard_container->bounds().ToString());
    964 
    965   UpdateDisplay("600x800");
    966   EXPECT_EQ("0,0 600x800", keyboard_container->bounds().ToString());
    967 }
    968 
    969 }  // namespace test
    970 }  // namespace ash
    971