Home | History | Annotate | Download | only in workspace
      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/workspace/workspace_layout_manager.h"
      6 
      7 #include <string>
      8 
      9 #include "ash/display/display_layout.h"
     10 #include "ash/display/display_manager.h"
     11 #include "ash/root_window_controller.h"
     12 #include "ash/screen_util.h"
     13 #include "ash/session/session_state_delegate.h"
     14 #include "ash/shelf/shelf_layout_manager.h"
     15 #include "ash/shell.h"
     16 #include "ash/shell_observer.h"
     17 #include "ash/shell_window_ids.h"
     18 #include "ash/test/ash_test_base.h"
     19 #include "ash/wm/maximize_mode/workspace_backdrop_delegate.h"
     20 #include "ash/wm/window_state.h"
     21 #include "ash/wm/window_util.h"
     22 #include "ash/wm/wm_event.h"
     23 #include "ash/wm/workspace/workspace_window_resizer.h"
     24 #include "base/basictypes.h"
     25 #include "base/compiler_specific.h"
     26 #include "ui/aura/client/aura_constants.h"
     27 #include "ui/aura/test/test_windows.h"
     28 #include "ui/aura/window.h"
     29 #include "ui/aura/window_event_dispatcher.h"
     30 #include "ui/base/ime/dummy_text_input_client.h"
     31 #include "ui/base/ime/input_method.h"
     32 #include "ui/base/ime/text_input_focus_manager.h"
     33 #include "ui/base/ui_base_switches_util.h"
     34 #include "ui/base/ui_base_types.h"
     35 #include "ui/gfx/insets.h"
     36 #include "ui/gfx/screen.h"
     37 #include "ui/views/widget/widget.h"
     38 #include "ui/views/widget/widget_delegate.h"
     39 #include "ui/wm/core/window_util.h"
     40 
     41 namespace ash {
     42 namespace {
     43 
     44 class MaximizeDelegateView : public views::WidgetDelegateView {
     45  public:
     46   explicit MaximizeDelegateView(const gfx::Rect& initial_bounds)
     47       : initial_bounds_(initial_bounds) {
     48   }
     49   virtual ~MaximizeDelegateView() {}
     50 
     51   virtual bool GetSavedWindowPlacement(
     52       const views::Widget* widget,
     53       gfx::Rect* bounds,
     54       ui::WindowShowState* show_state) const OVERRIDE {
     55     *bounds = initial_bounds_;
     56     *show_state = ui::SHOW_STATE_MAXIMIZED;
     57     return true;
     58   }
     59 
     60  private:
     61   const gfx::Rect initial_bounds_;
     62 
     63   DISALLOW_COPY_AND_ASSIGN(MaximizeDelegateView);
     64 };
     65 
     66 class TestShellObserver : public ShellObserver {
     67  public:
     68   TestShellObserver() : call_count_(0),
     69                         is_fullscreen_(false) {
     70     Shell::GetInstance()->AddShellObserver(this);
     71   }
     72 
     73   virtual ~TestShellObserver() {
     74     Shell::GetInstance()->RemoveShellObserver(this);
     75   }
     76 
     77   virtual void OnFullscreenStateChanged(bool is_fullscreen,
     78                                         aura::Window* root_window) OVERRIDE {
     79     call_count_++;
     80     is_fullscreen_ = is_fullscreen;
     81   }
     82 
     83   int call_count() const {
     84     return call_count_;
     85   }
     86 
     87   bool is_fullscreen() const {
     88     return is_fullscreen_;
     89   }
     90 
     91  private:
     92   int call_count_;
     93   bool is_fullscreen_;
     94 
     95   DISALLOW_COPY_AND_ASSIGN(TestShellObserver);
     96 };
     97 
     98 }  // namespace
     99 
    100 typedef test::AshTestBase WorkspaceLayoutManagerTest;
    101 
    102 // Verifies that a window containing a restore coordinate will be restored to
    103 // to the size prior to minimize, keeping the restore rectangle in tact (if
    104 // there is one).
    105 TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) {
    106   scoped_ptr<aura::Window> window(
    107       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
    108   gfx::Rect bounds(10, 15, 25, 35);
    109   window->SetBounds(bounds);
    110 
    111   wm::WindowState* window_state = wm::GetWindowState(window.get());
    112 
    113   // This will not be used for un-minimizing window.
    114   window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100));
    115   window_state->Minimize();
    116   window_state->Restore();
    117   EXPECT_EQ("0,0 100x100", window_state->GetRestoreBoundsInScreen().ToString());
    118   EXPECT_EQ("10,15 25x35", window.get()->bounds().ToString());
    119 
    120   if (!SupportsMultipleDisplays())
    121     return;
    122 
    123   UpdateDisplay("400x300,500x400");
    124   window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100),
    125                             ScreenUtil::GetSecondaryDisplay());
    126   EXPECT_EQ(Shell::GetAllRootWindows()[1], window->GetRootWindow());
    127   window_state->Minimize();
    128   // This will not be used for un-minimizing window.
    129   window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100));
    130   window_state->Restore();
    131   EXPECT_EQ("600,0 100x100", window->GetBoundsInScreen().ToString());
    132 
    133   // Make sure the unminimized window moves inside the display when
    134   // 2nd display is disconnected.
    135   window_state->Minimize();
    136   UpdateDisplay("400x300");
    137   window_state->Restore();
    138   EXPECT_EQ(Shell::GetPrimaryRootWindow(), window->GetRootWindow());
    139   EXPECT_TRUE(
    140       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
    141 }
    142 
    143 TEST_F(WorkspaceLayoutManagerTest, KeepMinimumVisibilityInDisplays) {
    144   if (!SupportsMultipleDisplays())
    145     return;
    146 
    147   UpdateDisplay("300x400,400x500");
    148   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    149 
    150   DisplayLayout layout(DisplayLayout::TOP, 0);
    151   Shell::GetInstance()->display_manager()->
    152       SetLayoutForCurrentDisplays(layout);
    153   EXPECT_EQ("0,-500 400x500", root_windows[1]->GetBoundsInScreen().ToString());
    154 
    155   scoped_ptr<aura::Window> window1(
    156       CreateTestWindowInShellWithBounds(gfx::Rect(10, -400, 200, 200)));
    157   EXPECT_EQ("10,-400 200x200", window1->GetBoundsInScreen().ToString());
    158 
    159   // Make sure the caption is visible.
    160   scoped_ptr<aura::Window> window2(
    161       CreateTestWindowInShellWithBounds(gfx::Rect(10, -600, 200, 200)));
    162   EXPECT_EQ("10,-500 200x200", window2->GetBoundsInScreen().ToString());
    163 }
    164 
    165 TEST_F(WorkspaceLayoutManagerTest, NoMinimumVisibilityForPopupWindows) {
    166   UpdateDisplay("300x400");
    167 
    168   // Create a popup window out of display boundaries and make sure it is not
    169   // moved to have minimum visibility.
    170   scoped_ptr<aura::Window> window(
    171       CreateTestWindowInShellWithDelegateAndType(NULL,
    172                                                  ui::wm::WINDOW_TYPE_POPUP,
    173                                                  0,
    174                                                  gfx::Rect(400, 100, 50, 50)));
    175   EXPECT_EQ("400,100 50x50", window->GetBoundsInScreen().ToString());
    176 }
    177 
    178 TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) {
    179   if (!SupportsHostWindowResize())
    180     return;
    181   scoped_ptr<aura::Window> window(
    182       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
    183   wm::WindowState* window_state = wm::GetWindowState(window.get());
    184 
    185   // Maximized -> Normal transition.
    186   window_state->Maximize();
    187   window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40));
    188   window_state->Restore();
    189   EXPECT_TRUE(
    190       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
    191   // Y bounds should not be negative.
    192   EXPECT_EQ("-20,0 30x40", window->bounds().ToString());
    193 
    194   // Minimized -> Normal transition.
    195   window->SetBounds(gfx::Rect(-100, -100, 30, 40));
    196   window_state->Minimize();
    197   EXPECT_FALSE(
    198       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
    199   EXPECT_EQ("-100,-100 30x40", window->bounds().ToString());
    200   window->Show();
    201   EXPECT_TRUE(
    202       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
    203   // Y bounds should not be negative.
    204   EXPECT_EQ("-20,0 30x40", window->bounds().ToString());
    205 
    206   // Fullscreen -> Normal transition.
    207   window->SetBounds(gfx::Rect(0, 0, 30, 40));  // reset bounds.
    208   ASSERT_EQ("0,0 30x40", window->bounds().ToString());
    209   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    210   EXPECT_EQ(window->bounds(), window->GetRootWindow()->bounds());
    211   window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40));
    212   window_state->Restore();
    213   EXPECT_TRUE(
    214       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
    215   // Y bounds should not be negative.
    216   EXPECT_EQ("-20,0 30x40", window->bounds().ToString());
    217 }
    218 
    219 TEST_F(WorkspaceLayoutManagerTest, MaximizeInDisplayToBeRestored) {
    220   if (!SupportsMultipleDisplays())
    221     return;
    222   UpdateDisplay("300x400,400x500");
    223 
    224   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    225 
    226   scoped_ptr<aura::Window> window(
    227       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
    228   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    229 
    230   wm::WindowState* window_state = wm::GetWindowState(window.get());
    231   window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40));
    232   // Maximize the window in 2nd display as the restore bounds
    233   // is inside 2nd display.
    234   window_state->Maximize();
    235   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    236   EXPECT_EQ("300,0 400x453", window->GetBoundsInScreen().ToString());
    237 
    238   window_state->Restore();
    239   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    240   EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString());
    241 
    242   // If the restore bounds intersects with the current display,
    243   // don't move.
    244   window_state->SetRestoreBoundsInScreen(gfx::Rect(280, 0, 30, 40));
    245   window_state->Maximize();
    246   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    247   EXPECT_EQ("300,0 400x453", window->GetBoundsInScreen().ToString());
    248 
    249   window_state->Restore();
    250   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    251   EXPECT_EQ("280,0 30x40", window->GetBoundsInScreen().ToString());
    252 
    253   // Restoring widget state.
    254   scoped_ptr<views::Widget> w1(new views::Widget);
    255   views::Widget::InitParams params;
    256   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    257   params.delegate = new MaximizeDelegateView(gfx::Rect(400, 0, 30, 40));
    258   params.context = root_windows[0];
    259   w1->Init(params);
    260   w1->Show();
    261   EXPECT_TRUE(w1->IsMaximized());
    262   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    263   EXPECT_EQ("300,0 400x453", w1->GetWindowBoundsInScreen().ToString());
    264   w1->Restore();
    265   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    266   EXPECT_EQ("400,0 30x40", w1->GetWindowBoundsInScreen().ToString());
    267 }
    268 
    269 TEST_F(WorkspaceLayoutManagerTest, FullscreenInDisplayToBeRestored) {
    270   if (!SupportsMultipleDisplays())
    271     return;
    272   UpdateDisplay("300x400,400x500");
    273 
    274   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    275 
    276   scoped_ptr<aura::Window> window(
    277       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
    278   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    279 
    280   wm::WindowState* window_state = wm::GetWindowState(window.get());
    281   window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40));
    282   // Maximize the window in 2nd display as the restore bounds
    283   // is inside 2nd display.
    284   window->SetProperty(aura::client::kShowStateKey,
    285                       ui::SHOW_STATE_FULLSCREEN);
    286   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    287   EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString());
    288 
    289   window_state->Restore();
    290   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    291   EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString());
    292 
    293   // If the restore bounds intersects with the current display,
    294   // don't move.
    295   window_state->SetRestoreBoundsInScreen(gfx::Rect(280, 0, 30, 40));
    296   window->SetProperty(aura::client::kShowStateKey,
    297                       ui::SHOW_STATE_FULLSCREEN);
    298   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    299   EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString());
    300 
    301   window_state->Restore();
    302   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    303   EXPECT_EQ("280,0 30x40", window->GetBoundsInScreen().ToString());
    304 }
    305 
    306 // WindowObserver implementation used by DontClobberRestoreBoundsWindowObserver.
    307 // This code mirrors what BrowserFrameAsh does. In particular when this code
    308 // sees the window was maximized it changes the bounds of a secondary
    309 // window. The secondary window mirrors the status window.
    310 class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver {
    311  public:
    312   DontClobberRestoreBoundsWindowObserver() : window_(NULL) {}
    313 
    314   void set_window(aura::Window* window) { window_ = window; }
    315 
    316   virtual void OnWindowPropertyChanged(aura::Window* window,
    317                                        const void* key,
    318                                        intptr_t old) OVERRIDE {
    319     if (!window_)
    320       return;
    321 
    322     if (wm::GetWindowState(window)->IsMaximized()) {
    323       aura::Window* w = window_;
    324       window_ = NULL;
    325 
    326       gfx::Rect shelf_bounds(Shell::GetPrimaryRootWindowController()->
    327                              GetShelfLayoutManager()->GetIdealBounds());
    328       const gfx::Rect& window_bounds(w->bounds());
    329       w->SetBounds(gfx::Rect(window_bounds.x(), shelf_bounds.y() - 1,
    330                              window_bounds.width(), window_bounds.height()));
    331     }
    332   }
    333 
    334  private:
    335   aura::Window* window_;
    336 
    337   DISALLOW_COPY_AND_ASSIGN(DontClobberRestoreBoundsWindowObserver);
    338 };
    339 
    340 // Creates a window, maximized the window and from within the maximized
    341 // notification sets the bounds of a window to overlap the shelf. Verifies this
    342 // doesn't effect the restore bounds.
    343 TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) {
    344   DontClobberRestoreBoundsWindowObserver window_observer;
    345   scoped_ptr<aura::Window> window(new aura::Window(NULL));
    346   window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
    347   window->Init(aura::WINDOW_LAYER_TEXTURED);
    348   window->SetBounds(gfx::Rect(10, 20, 30, 40));
    349   // NOTE: for this test to exercise the failure the observer needs to be added
    350   // before the parent set. This mimics what BrowserFrameAsh does.
    351   window->AddObserver(&window_observer);
    352   ParentWindowInPrimaryRootWindow(window.get());
    353   window->Show();
    354 
    355   wm::WindowState* window_state = wm::GetWindowState(window.get());
    356   window_state->Activate();
    357 
    358   scoped_ptr<aura::Window> window2(
    359       CreateTestWindowInShellWithBounds(gfx::Rect(12, 20, 30, 40)));
    360   ::wm::AddTransientChild(window.get(), window2.get());
    361   window2->Show();
    362 
    363   window_observer.set_window(window2.get());
    364   window_state->Maximize();
    365   EXPECT_EQ("10,20 30x40",
    366             window_state->GetRestoreBoundsInScreen().ToString());
    367   window->RemoveObserver(&window_observer);
    368 }
    369 
    370 // Verifies when a window is maximized all descendant windows have a size.
    371 TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) {
    372   scoped_ptr<aura::Window> window(
    373       CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 30, 40)));
    374   window->Show();
    375   wm::WindowState* window_state = wm::GetWindowState(window.get());
    376   window_state->Activate();
    377   scoped_ptr<aura::Window> child_window(
    378       aura::test::CreateTestWindowWithBounds(gfx::Rect(5, 6, 7, 8),
    379                                              window.get()));
    380   child_window->Show();
    381   window_state->Maximize();
    382   EXPECT_EQ("5,6 7x8", child_window->bounds().ToString());
    383 }
    384 
    385 // Verifies a window created with maximized state has the maximized
    386 // bounds.
    387 TEST_F(WorkspaceLayoutManagerTest, MaximizeWithEmptySize) {
    388   scoped_ptr<aura::Window> window(
    389       aura::test::CreateTestWindowWithBounds(gfx::Rect(0, 0, 0, 0),
    390                                              NULL));
    391   wm::GetWindowState(window.get())->Maximize();
    392   aura::Window* default_container = Shell::GetContainer(
    393       Shell::GetPrimaryRootWindow(), kShellWindowId_DefaultContainer);
    394   default_container->AddChild(window.get());
    395   window->Show();
    396   gfx::Rect work_area(
    397       Shell::GetScreen()->GetPrimaryDisplay().work_area());
    398   EXPECT_EQ(work_area.ToString(), window->GetBoundsInScreen().ToString());
    399 }
    400 
    401 TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) {
    402   // Normal window bounds shouldn't be changed.
    403   gfx::Rect window_bounds(100, 100, 200, 200);
    404   scoped_ptr<aura::Window> window(
    405       CreateTestWindowInShellWithBounds(window_bounds));
    406   EXPECT_EQ(window_bounds, window->bounds());
    407 
    408   // If the window is out of the workspace, it would be moved on screen.
    409   gfx::Rect root_window_bounds =
    410       Shell::GetInstance()->GetPrimaryRootWindow()->bounds();
    411   window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height());
    412   ASSERT_FALSE(window_bounds.Intersects(root_window_bounds));
    413   scoped_ptr<aura::Window> out_window(
    414       CreateTestWindowInShellWithBounds(window_bounds));
    415   EXPECT_EQ(window_bounds.size(), out_window->bounds().size());
    416   gfx::Rect bounds = out_window->bounds();
    417   bounds.Intersect(root_window_bounds);
    418 
    419   // 30% of the window edge must be visible.
    420   EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
    421   EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
    422 
    423   aura::Window* parent = out_window->parent();
    424   parent->RemoveChild(out_window.get());
    425   out_window->SetBounds(gfx::Rect(-200, -200, 200, 200));
    426   // UserHasChangedWindowPositionOrSize flag shouldn't turn off this behavior.
    427   wm::GetWindowState(window.get())->set_bounds_changed_by_user(true);
    428   parent->AddChild(out_window.get());
    429   EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
    430   EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
    431 
    432   // Make sure we always make more than 1/3 of the window edge visible even
    433   // if the initial bounds intersects with display.
    434   window_bounds.SetRect(-150, -150, 200, 200);
    435   bounds = window_bounds;
    436   bounds.Intersect(root_window_bounds);
    437 
    438   // Make sure that the initial bounds' visible area is less than 26%
    439   // so that the auto adjustment logic kicks in.
    440   ASSERT_LT(bounds.width(), out_window->bounds().width() * 0.26);
    441   ASSERT_LT(bounds.height(), out_window->bounds().height() * 0.26);
    442   ASSERT_TRUE(window_bounds.Intersects(root_window_bounds));
    443 
    444   scoped_ptr<aura::Window> partially_out_window(
    445       CreateTestWindowInShellWithBounds(window_bounds));
    446   EXPECT_EQ(window_bounds.size(), partially_out_window->bounds().size());
    447   bounds = partially_out_window->bounds();
    448   bounds.Intersect(root_window_bounds);
    449   EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
    450   EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
    451 
    452   // Make sure the window whose 30% width/height is bigger than display
    453   // will be placed correctly.
    454   window_bounds.SetRect(-1900, -1900, 3000, 3000);
    455   scoped_ptr<aura::Window> window_bigger_than_display(
    456       CreateTestWindowInShellWithBounds(window_bounds));
    457   EXPECT_GE(root_window_bounds.width(),
    458             window_bigger_than_display->bounds().width());
    459   EXPECT_GE(root_window_bounds.height(),
    460             window_bigger_than_display->bounds().height());
    461 
    462   bounds = window_bigger_than_display->bounds();
    463   bounds.Intersect(root_window_bounds);
    464   EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
    465   EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
    466 }
    467 
    468 // Verifies the size of a window is enforced to be smaller than the work area.
    469 TEST_F(WorkspaceLayoutManagerTest, SizeToWorkArea) {
    470   // Normal window bounds shouldn't be changed.
    471   gfx::Size work_area(
    472       Shell::GetScreen()->GetPrimaryDisplay().work_area().size());
    473   const gfx::Rect window_bounds(
    474       100, 101, work_area.width() + 1, work_area.height() + 2);
    475   scoped_ptr<aura::Window> window(
    476       CreateTestWindowInShellWithBounds(window_bounds));
    477   EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(),
    478       window->bounds().ToString());
    479 
    480   // Directly setting the bounds triggers a slightly different code path. Verify
    481   // that too.
    482   window->SetBounds(window_bounds);
    483   EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(),
    484       window->bounds().ToString());
    485 }
    486 
    487 TEST_F(WorkspaceLayoutManagerTest, NotifyFullscreenChanges) {
    488   TestShellObserver observer;
    489   scoped_ptr<aura::Window> window1(
    490       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
    491   scoped_ptr<aura::Window> window2(
    492       CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
    493   wm::WindowState* window_state1 = wm::GetWindowState(window1.get());
    494   wm::WindowState* window_state2 = wm::GetWindowState(window2.get());
    495   window_state2->Activate();
    496 
    497   const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
    498   window_state2->OnWMEvent(&toggle_fullscreen_event);
    499   EXPECT_EQ(1, observer.call_count());
    500   EXPECT_TRUE(observer.is_fullscreen());
    501 
    502   // When window1 moves to the front the fullscreen state should change.
    503   window_state1->Activate();
    504   EXPECT_EQ(2, observer.call_count());
    505   EXPECT_FALSE(observer.is_fullscreen());
    506 
    507   // It should change back if window2 becomes active again.
    508   window_state2->Activate();
    509   EXPECT_EQ(3, observer.call_count());
    510   EXPECT_TRUE(observer.is_fullscreen());
    511 
    512   window_state2->OnWMEvent(&toggle_fullscreen_event);
    513   EXPECT_EQ(4, observer.call_count());
    514   EXPECT_FALSE(observer.is_fullscreen());
    515 
    516   window_state2->OnWMEvent(&toggle_fullscreen_event);
    517   EXPECT_EQ(5, observer.call_count());
    518   EXPECT_TRUE(observer.is_fullscreen());
    519 
    520   // Closing the window should change the fullscreen state.
    521   window2.reset();
    522   EXPECT_EQ(6, observer.call_count());
    523   EXPECT_FALSE(observer.is_fullscreen());
    524 }
    525 
    526 // Following "Solo" tests were originally written for BaseLayoutManager.
    527 namespace {
    528 
    529 class WorkspaceLayoutManagerSoloTest : public test::AshTestBase {
    530  public:
    531   WorkspaceLayoutManagerSoloTest() {}
    532   virtual ~WorkspaceLayoutManagerSoloTest() {}
    533 
    534   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
    535     return CreateTestWindowInShellWithBounds(bounds);
    536   }
    537 
    538  private:
    539   DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerSoloTest);
    540 };
    541 
    542 }  // namespace
    543 
    544 // Tests normal->maximize->normal.
    545 TEST_F(WorkspaceLayoutManagerSoloTest, Maximize) {
    546   gfx::Rect bounds(100, 100, 200, 200);
    547   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
    548   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    549   // Maximized window fills the work area, not the whole display.
    550   EXPECT_EQ(
    551       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString(),
    552       window->bounds().ToString());
    553   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    554   EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
    555 }
    556 
    557 // Tests normal->minimize->normal.
    558 TEST_F(WorkspaceLayoutManagerSoloTest, Minimize) {
    559   gfx::Rect bounds(100, 100, 200, 200);
    560   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
    561   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    562   // Note: Currently minimize doesn't do anything except set the state.
    563   // See crbug.com/104571.
    564   EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
    565   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    566   EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
    567 }
    568 
    569 // A WindowDelegate which sets the focus when the window
    570 // becomes visible.
    571 class FocusDelegate : public aura::test::TestWindowDelegate {
    572  public:
    573   FocusDelegate()
    574       : window_(NULL),
    575         show_state_(ui::SHOW_STATE_END) {
    576   }
    577   virtual ~FocusDelegate() {}
    578 
    579   void set_window(aura::Window* window) { window_ = window; }
    580 
    581   // aura::test::TestWindowDelegate overrides:
    582   virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {
    583     if (window_) {
    584       if (visible)
    585         window_->Focus();
    586       show_state_ = window_->GetProperty(aura::client::kShowStateKey);
    587     }
    588   }
    589 
    590   ui::WindowShowState GetShowStateAndReset() {
    591     ui::WindowShowState ret = show_state_;
    592     show_state_ = ui::SHOW_STATE_END;
    593     return ret;
    594   }
    595 
    596  private:
    597   aura::Window* window_;
    598   ui::WindowShowState show_state_;
    599 
    600   DISALLOW_COPY_AND_ASSIGN(FocusDelegate);
    601 };
    602 
    603 // Make sure that the window's show state is correct in
    604 // |WindowDelegate::OnWindowTargetVisibilityChanged|, and setting
    605 // focus in this callback doesn't cause DCHECK error.  See
    606 // crbug.com/168383.
    607 TEST_F(WorkspaceLayoutManagerSoloTest, FocusDuringUnminimize) {
    608   FocusDelegate delegate;
    609   scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
    610       &delegate, 0, gfx::Rect(100, 100, 100, 100)));
    611   delegate.set_window(window.get());
    612   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    613   EXPECT_FALSE(window->IsVisible());
    614   EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, delegate.GetShowStateAndReset());
    615   window->Show();
    616   EXPECT_TRUE(window->IsVisible());
    617   EXPECT_EQ(ui::SHOW_STATE_NORMAL, delegate.GetShowStateAndReset());
    618 }
    619 
    620 // Tests maximized window size during root window resize.
    621 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeRootWindowResize) {
    622   gfx::Rect bounds(100, 100, 200, 200);
    623   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
    624   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    625   gfx::Rect initial_work_area_bounds =
    626       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get());
    627   EXPECT_EQ(initial_work_area_bounds.ToString(), window->bounds().ToString());
    628   // Enlarge the root window.  We should still match the work area size.
    629   UpdateDisplay("900x700");
    630   EXPECT_EQ(
    631       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString(),
    632       window->bounds().ToString());
    633   EXPECT_NE(
    634       initial_work_area_bounds.ToString(),
    635       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString());
    636 }
    637 
    638 // Tests normal->fullscreen->normal.
    639 TEST_F(WorkspaceLayoutManagerSoloTest, Fullscreen) {
    640   gfx::Rect bounds(100, 100, 200, 200);
    641   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
    642   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    643   // Fullscreen window fills the whole display.
    644   EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
    645                 window.get()).bounds().ToString(),
    646             window->bounds().ToString());
    647   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    648   EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
    649 }
    650 
    651 // Tests fullscreen window size during root window resize.
    652 TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenRootWindowResize) {
    653   gfx::Rect bounds(100, 100, 200, 200);
    654   scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
    655   // Fullscreen window fills the whole display.
    656   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    657   EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
    658                 window.get()).bounds().ToString(),
    659             window->bounds().ToString());
    660   // Enlarge the root window.  We should still match the display size.
    661   UpdateDisplay("800x600");
    662   EXPECT_EQ(Shell::GetScreen()->GetDisplayNearestWindow(
    663                 window.get()).bounds().ToString(),
    664             window->bounds().ToString());
    665 }
    666 
    667 // Tests that when the screen gets smaller the windows aren't bigger than
    668 // the screen.
    669 TEST_F(WorkspaceLayoutManagerSoloTest, RootWindowResizeShrinksWindows) {
    670   scoped_ptr<aura::Window> window(
    671       CreateTestWindow(gfx::Rect(10, 20, 500, 400)));
    672   gfx::Rect work_area = Shell::GetScreen()->GetDisplayNearestWindow(
    673       window.get()).work_area();
    674   // Invariant: Window is smaller than work area.
    675   EXPECT_LE(window->bounds().width(), work_area.width());
    676   EXPECT_LE(window->bounds().height(), work_area.height());
    677 
    678   // Make the root window narrower than our window.
    679   UpdateDisplay("300x400");
    680   work_area = Shell::GetScreen()->GetDisplayNearestWindow(
    681       window.get()).work_area();
    682   EXPECT_LE(window->bounds().width(), work_area.width());
    683   EXPECT_LE(window->bounds().height(), work_area.height());
    684 
    685   // Make the root window shorter than our window.
    686   UpdateDisplay("300x200");
    687   work_area = Shell::GetScreen()->GetDisplayNearestWindow(
    688       window.get()).work_area();
    689   EXPECT_LE(window->bounds().width(), work_area.width());
    690   EXPECT_LE(window->bounds().height(), work_area.height());
    691 
    692   // Enlarging the root window does not change the window bounds.
    693   gfx::Rect old_bounds = window->bounds();
    694   UpdateDisplay("800x600");
    695   EXPECT_EQ(old_bounds.width(), window->bounds().width());
    696   EXPECT_EQ(old_bounds.height(), window->bounds().height());
    697 }
    698 
    699 // Verifies maximizing sets the restore bounds, and restoring
    700 // restores the bounds.
    701 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeSetsRestoreBounds) {
    702   scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(10, 20, 30, 40)));
    703   wm::WindowState* window_state = wm::GetWindowState(window.get());
    704 
    705   // Maximize it, which will keep the previous restore bounds.
    706   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    707   EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInParent().ToString());
    708 
    709   // Restore it, which should restore bounds and reset restore bounds.
    710   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    711   EXPECT_EQ("10,20 30x40", window->bounds().ToString());
    712   EXPECT_FALSE(window_state->HasRestoreBounds());
    713 }
    714 
    715 // Verifies maximizing keeps the restore bounds if set.
    716 TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeResetsRestoreBounds) {
    717   scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
    718 
    719   wm::WindowState* window_state = wm::GetWindowState(window.get());
    720   window_state->SetRestoreBoundsInParent(gfx::Rect(10, 11, 12, 13));
    721 
    722   // Maximize it, which will keep the previous restore bounds.
    723   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    724   EXPECT_EQ("10,11 12x13", window_state->GetRestoreBoundsInParent().ToString());
    725 }
    726 
    727 // Verifies that the restore bounds do not get reset when restoring to a
    728 // maximzied state from a minimized state.
    729 TEST_F(WorkspaceLayoutManagerSoloTest,
    730        BoundsAfterRestoringToMaximizeFromMinimize) {
    731   scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
    732   gfx::Rect bounds(10, 15, 25, 35);
    733   window->SetBounds(bounds);
    734 
    735   wm::WindowState* window_state = wm::GetWindowState(window.get());
    736   // Maximize it, which should reset restore bounds.
    737   window_state->Maximize();
    738   EXPECT_EQ(bounds.ToString(),
    739             window_state->GetRestoreBoundsInParent().ToString());
    740   // Minimize the window. The restore bounds should not change.
    741   window_state->Minimize();
    742   EXPECT_EQ(bounds.ToString(),
    743             window_state->GetRestoreBoundsInParent().ToString());
    744 
    745   // Show the window again. The window should be maximized, and the restore
    746   // bounds should not change.
    747   window->Show();
    748   EXPECT_EQ(bounds.ToString(),
    749             window_state->GetRestoreBoundsInParent().ToString());
    750   EXPECT_TRUE(window_state->IsMaximized());
    751 
    752   window_state->Restore();
    753   EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
    754 }
    755 
    756 // Verify if the window is not resized during screen lock. See: crbug.com/173127
    757 TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) {
    758   SetCanLockScreen(true);
    759   scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
    760   // window with AlwaysOnTop will be managed by BaseLayoutManager.
    761   window->SetProperty(aura::client::kAlwaysOnTopKey, true);
    762   window->Show();
    763 
    764   ShelfLayoutManager* shelf = ShelfLayoutManager::ForShelf(window.get());
    765   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    766 
    767   window->SetBounds(ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()));
    768   gfx::Rect window_bounds = window->bounds();
    769   EXPECT_EQ(
    770       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString(),
    771       window_bounds.ToString());
    772 
    773   Shell::GetInstance()->session_state_delegate()->LockScreen();
    774   shelf->UpdateVisibilityState();
    775   EXPECT_NE(
    776       ScreenUtil::GetMaximizedWindowBoundsInParent(window.get()).ToString(),
    777       window_bounds.ToString());
    778 
    779   Shell::GetInstance()->session_state_delegate()->UnlockScreen();
    780   shelf->UpdateVisibilityState();
    781   EXPECT_EQ(window_bounds.ToString(), window->bounds().ToString());
    782 }
    783 
    784 // Following tests are written to test the backdrop functionality.
    785 
    786 namespace {
    787 
    788 class WorkspaceLayoutManagerBackdropTest : public test::AshTestBase {
    789  public:
    790   WorkspaceLayoutManagerBackdropTest() {}
    791   virtual ~WorkspaceLayoutManagerBackdropTest() {}
    792 
    793   virtual void SetUp() OVERRIDE {
    794     test::AshTestBase::SetUp();
    795     UpdateDisplay("800x600");
    796     default_container_ = Shell::GetContainer(Shell::GetPrimaryRootWindow(),
    797                                              kShellWindowId_DefaultContainer);
    798   }
    799 
    800   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
    801     aura::Window* window = CreateTestWindowInShellWithBounds(bounds);
    802     return window;
    803   }
    804 
    805   // Turn the top window back drop on / off.
    806   void ShowTopWindowBackdrop(bool show) {
    807     scoped_ptr<ash::WorkspaceLayoutManagerDelegate> backdrop;
    808     if (show) {
    809       backdrop.reset(new ash::WorkspaceBackdropDelegate(default_container_));
    810     }
    811     (static_cast<WorkspaceLayoutManager*>(default_container_->layout_manager()))
    812         ->SetMaximizeBackdropDelegate(backdrop.Pass());
    813     // Closing and / or opening can be a delayed operation.
    814     base::MessageLoop::current()->RunUntilIdle();
    815   }
    816 
    817   // Return the default container.
    818   aura::Window* default_container() { return default_container_; }
    819 
    820   // Return the order of windows (top most first) as they are in the default
    821   // container. If the window is visible it will be a big letter, otherwise a
    822   // small one. The backdrop will be an X and unknown windows will be shown as
    823   // '!'.
    824   std::string GetWindowOrderAsString(aura::Window* backdrop,
    825                                      aura::Window* wa,
    826                                      aura::Window* wb,
    827                                      aura::Window* wc) {
    828     std::string result;
    829     for (int i = static_cast<int>(default_container()->children().size()) - 1;
    830          i >= 0;
    831          --i) {
    832       if (!result.empty())
    833         result += ",";
    834       if (default_container()->children()[i] == wa)
    835         result += default_container()->children()[i]->IsVisible() ? "A" : "a";
    836       else if (default_container()->children()[i] == wb)
    837         result += default_container()->children()[i]->IsVisible() ? "B" : "b";
    838       else if (default_container()->children()[i] == wc)
    839         result += default_container()->children()[i]->IsVisible() ? "C" : "c";
    840       else if (default_container()->children()[i] == backdrop)
    841         result += default_container()->children()[i]->IsVisible() ? "X" : "x";
    842       else
    843         result += "!";
    844     }
    845     return result;
    846   }
    847 
    848  private:
    849   // The default container.
    850   aura::Window* default_container_;
    851 
    852   DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerBackdropTest);
    853 };
    854 
    855 }  // namespace
    856 
    857 // Check that creating the BackDrop without destroying it does not lead into
    858 // a crash.
    859 TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) {
    860   ShowTopWindowBackdrop(true);
    861 }
    862 
    863 // Verify basic assumptions about the backdrop.
    864 TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) {
    865   // Create a backdrop and see that there is one window (the backdrop) and
    866   // that the size is the same as the default container as well as that it is
    867   // not visible.
    868   ShowTopWindowBackdrop(true);
    869   ASSERT_EQ(1U, default_container()->children().size());
    870   EXPECT_FALSE(default_container()->children()[0]->IsVisible());
    871 
    872   {
    873     // Add a window and make sure that the backdrop is the second child.
    874     scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
    875     window->Show();
    876     ASSERT_EQ(2U, default_container()->children().size());
    877     EXPECT_TRUE(default_container()->children()[0]->IsVisible());
    878     EXPECT_TRUE(default_container()->children()[1]->IsVisible());
    879     EXPECT_EQ(window.get(), default_container()->children()[1]);
    880     EXPECT_EQ(default_container()->bounds().ToString(),
    881               default_container()->children()[0]->bounds().ToString());
    882   }
    883 
    884   // With the window gone the backdrop should be invisible again.
    885   ASSERT_EQ(1U, default_container()->children().size());
    886   EXPECT_FALSE(default_container()->children()[0]->IsVisible());
    887 
    888   // Destroying the Backdrop should empty the container.
    889   ShowTopWindowBackdrop(false);
    890   ASSERT_EQ(0U, default_container()->children().size());
    891 }
    892 
    893 // Verify that the backdrop gets properly created and placed.
    894 TEST_F(WorkspaceLayoutManagerBackdropTest, VerifyBackdropAndItsStacking) {
    895   scoped_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(1, 2, 3, 4)));
    896   window1->Show();
    897 
    898   // Get the default container and check that only a single window is in there.
    899   ASSERT_EQ(1U, default_container()->children().size());
    900   EXPECT_EQ(window1.get(), default_container()->children()[0]);
    901   EXPECT_EQ("A", GetWindowOrderAsString(NULL, window1.get(), NULL, NULL));
    902 
    903   // Create 2 more windows and check that they are also in the container.
    904   scoped_ptr<aura::Window> window2(CreateTestWindow(gfx::Rect(10, 2, 3, 4)));
    905   scoped_ptr<aura::Window> window3(CreateTestWindow(gfx::Rect(20, 2, 3, 4)));
    906   window2->Show();
    907   window3->Show();
    908 
    909   aura::Window* backdrop = NULL;
    910   EXPECT_EQ("C,B,A",
    911             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    912                                    window3.get()));
    913 
    914   // Turn on the backdrop mode and check that the window shows up where it
    915   // should be (second highest number).
    916   ShowTopWindowBackdrop(true);
    917   backdrop = default_container()->children()[2];
    918   EXPECT_EQ("C,X,B,A",
    919             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    920                                    window3.get()));
    921 
    922   // Switch the order of windows and check that it still remains in that
    923   // location.
    924   default_container()->StackChildAtTop(window2.get());
    925   EXPECT_EQ("B,X,C,A",
    926             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    927                                    window3.get()));
    928 
    929   // Make the top window invisible and check.
    930   window2.get()->Hide();
    931   EXPECT_EQ("b,C,X,A",
    932             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    933                                    window3.get()));
    934   // Then delete window after window and see that everything is in order.
    935   window1.reset();
    936   EXPECT_EQ("b,C,X",
    937             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    938                                    window3.get()));
    939   window3.reset();
    940   EXPECT_EQ("b,x",
    941             GetWindowOrderAsString(backdrop, window1.get(), window2.get(),
    942                                    window3.get()));
    943   ShowTopWindowBackdrop(false);
    944   EXPECT_EQ("b",
    945             GetWindowOrderAsString(NULL, window1.get(), window2.get(),
    946                                    window3.get()));
    947 }
    948 
    949 // Tests that when hidding the shelf, that the backdrop resizes to fill the
    950 // entire workspace area.
    951 TEST_F(WorkspaceLayoutManagerBackdropTest, ShelfVisibilityChangesBounds) {
    952   ShelfLayoutManager* shelf_layout_manager =
    953       Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    954   ShowTopWindowBackdrop(true);
    955   RunAllPendingInMessageLoop();
    956 
    957   ASSERT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
    958   gfx::Rect initial_bounds = default_container()->children()[0]->bounds();
    959   shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
    960   shelf_layout_manager->UpdateVisibilityState();
    961 
    962   // When the shelf is re-shown WorkspaceLayoutManager shrinks all children
    963   // including the backdrop.
    964   shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
    965   shelf_layout_manager->UpdateVisibilityState();
    966   gfx::Rect reduced_bounds = default_container()->children()[0]->bounds();
    967   EXPECT_LT(reduced_bounds.height(), initial_bounds.height());
    968 
    969   shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
    970   shelf_layout_manager->UpdateVisibilityState();
    971 
    972   EXPECT_GT(default_container()->children()[0]->bounds().height(),
    973             reduced_bounds.height());
    974 }
    975 
    976 class WorkspaceLayoutManagerKeyboardTest : public test::AshTestBase {
    977  public:
    978   WorkspaceLayoutManagerKeyboardTest() {}
    979   virtual ~WorkspaceLayoutManagerKeyboardTest() {}
    980 
    981   virtual void SetUp() OVERRIDE {
    982     test::AshTestBase::SetUp();
    983     UpdateDisplay("800x600");
    984     aura::Window* default_container = Shell::GetContainer(
    985         Shell::GetPrimaryRootWindow(), kShellWindowId_DefaultContainer);
    986     layout_manager_ = static_cast<WorkspaceLayoutManager*>(
    987         default_container->layout_manager());
    988   }
    989 
    990   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
    991     return CreateTestWindowInShellWithBounds(bounds);
    992   }
    993 
    994   void ShowKeyboard() {
    995     layout_manager_->OnKeyboardBoundsChanging(keyboard_bounds_);
    996     restore_work_area_insets_ = Shell::GetScreen()->GetPrimaryDisplay().
    997         GetWorkAreaInsets();
    998     Shell::GetInstance()->SetDisplayWorkAreaInsets(
    999         Shell::GetPrimaryRootWindow(),
   1000         gfx::Insets(0, 0, keyboard_bounds_.height(), 0));
   1001   }
   1002 
   1003   void HideKeyboard() {
   1004     Shell::GetInstance()->SetDisplayWorkAreaInsets(
   1005         Shell::GetPrimaryRootWindow(),
   1006         restore_work_area_insets_);
   1007     layout_manager_->OnKeyboardBoundsChanging(gfx::Rect());
   1008   }
   1009 
   1010   void SetKeyboardBounds(const gfx::Rect& bounds) {
   1011     keyboard_bounds_ = bounds;
   1012   }
   1013 
   1014   void Focus(ui::TextInputClient* text_input_client) {
   1015     if (switches::IsTextInputFocusManagerEnabled()) {
   1016       ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(
   1017           text_input_client);
   1018     } else {
   1019       aura::Window* root_window =
   1020           ash::Shell::GetInstance()->GetPrimaryRootWindow();
   1021       ui::InputMethod* input_method =
   1022           root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
   1023       input_method->SetFocusedTextInputClient(text_input_client);
   1024     }
   1025   }
   1026 
   1027   void Blur(ui::TextInputClient* text_input_client) {
   1028     if (switches::IsTextInputFocusManagerEnabled()) {
   1029       ui::TextInputFocusManager::GetInstance()->BlurTextInputClient(
   1030           text_input_client);
   1031     } else {
   1032       aura::Window* root_window =
   1033           ash::Shell::GetInstance()->GetPrimaryRootWindow();
   1034       ui::InputMethod* input_method =
   1035           root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
   1036       input_method->SetFocusedTextInputClient(NULL);
   1037     }
   1038   }
   1039 
   1040  private:
   1041   gfx::Insets restore_work_area_insets_;
   1042   gfx::Rect keyboard_bounds_;
   1043   WorkspaceLayoutManager* layout_manager_;
   1044 
   1045   DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerKeyboardTest);
   1046 };
   1047 
   1048 class FakeTextInputClient : public ui::DummyTextInputClient {
   1049  public:
   1050   explicit FakeTextInputClient(gfx::NativeWindow window) : window_(window) {}
   1051   virtual ~FakeTextInputClient() {}
   1052 
   1053   virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE {
   1054     return window_;
   1055   }
   1056 
   1057  private:
   1058   gfx::NativeWindow window_;
   1059 
   1060   DISALLOW_COPY_AND_ASSIGN(FakeTextInputClient);
   1061 };
   1062 
   1063 // Tests that when a child window gains focus the top level window containing it
   1064 // is resized to fit the remaining workspace area.
   1065 TEST_F(WorkspaceLayoutManagerKeyboardTest, ChildWindowFocused) {
   1066   gfx::Rect work_area(
   1067       Shell::GetScreen()->GetPrimaryDisplay().work_area());
   1068   gfx::Rect keyboard_bounds(work_area.x(),
   1069                             work_area.y() + work_area.height() / 2,
   1070                             work_area.width(),
   1071                             work_area.height() / 2);
   1072 
   1073   SetKeyboardBounds(keyboard_bounds);
   1074 
   1075   aura::test::TestWindowDelegate delegate1;
   1076   scoped_ptr<aura::Window> parent_window(CreateTestWindowInShellWithDelegate(
   1077       &delegate1, -1, work_area));
   1078   aura::test::TestWindowDelegate delegate2;
   1079   scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
   1080       &delegate2, -1, work_area));
   1081   parent_window->AddChild(window.get());
   1082 
   1083   FakeTextInputClient text_input_client(window.get());
   1084   Focus(&text_input_client);
   1085 
   1086   int available_height =
   1087       Shell::GetScreen()->GetPrimaryDisplay().bounds().height() -
   1088       keyboard_bounds.height();
   1089 
   1090   gfx::Rect initial_window_bounds(50, 50, 100, 500);
   1091   parent_window->SetBounds(initial_window_bounds);
   1092   EXPECT_EQ(initial_window_bounds.ToString(),
   1093             parent_window->bounds().ToString());
   1094   ShowKeyboard();
   1095   EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(),
   1096             parent_window->bounds().ToString());
   1097   HideKeyboard();
   1098   EXPECT_EQ(initial_window_bounds.ToString(),
   1099             parent_window->bounds().ToString());
   1100 
   1101   Blur(&text_input_client);
   1102 }
   1103 
   1104 TEST_F(WorkspaceLayoutManagerKeyboardTest, AdjustWindowForA11yKeyboard) {
   1105   gfx::Rect work_area(
   1106       Shell::GetScreen()->GetPrimaryDisplay().work_area());
   1107   gfx::Rect keyboard_bounds(work_area.x(),
   1108                             work_area.y() + work_area.height() / 2,
   1109                             work_area.width(),
   1110                             work_area.height() / 2);
   1111 
   1112   SetKeyboardBounds(keyboard_bounds);
   1113 
   1114   aura::test::TestWindowDelegate delegate;
   1115   scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
   1116       &delegate, -1, work_area));
   1117 
   1118   FakeTextInputClient text_input_client(window.get());
   1119   Focus(&text_input_client);
   1120 
   1121   int available_height =
   1122       Shell::GetScreen()->GetPrimaryDisplay().bounds().height() -
   1123       keyboard_bounds.height();
   1124 
   1125   EXPECT_EQ(gfx::Rect(work_area).ToString(), window->bounds().ToString());
   1126   ShowKeyboard();
   1127   EXPECT_EQ(gfx::Rect(work_area.origin(),
   1128             gfx::Size(work_area.width(), available_height)).ToString(),
   1129             window->bounds().ToString());
   1130   HideKeyboard();
   1131   EXPECT_EQ(gfx::Rect(work_area).ToString(), window->bounds().ToString());
   1132 
   1133   gfx::Rect small_window_bound(50, 50, 100, 500);
   1134   window->SetBounds(small_window_bound);
   1135   EXPECT_EQ(small_window_bound.ToString(), window->bounds().ToString());
   1136   ShowKeyboard();
   1137   EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(),
   1138             window->bounds().ToString());
   1139   HideKeyboard();
   1140   EXPECT_EQ(small_window_bound.ToString(), window->bounds().ToString());
   1141 
   1142   gfx::Rect occluded_window_bounds(50,
   1143       keyboard_bounds.y() + keyboard_bounds.height()/2, 50,
   1144       keyboard_bounds.height()/2);
   1145   window->SetBounds(occluded_window_bounds);
   1146   EXPECT_EQ(occluded_window_bounds.ToString(),
   1147       occluded_window_bounds.ToString());
   1148   ShowKeyboard();
   1149   EXPECT_EQ(gfx::Rect(50,
   1150                       keyboard_bounds.y() - keyboard_bounds.height()/2,
   1151                       occluded_window_bounds.width(),
   1152                       occluded_window_bounds.height()).ToString(),
   1153             window->bounds().ToString());
   1154   HideKeyboard();
   1155   EXPECT_EQ(occluded_window_bounds.ToString(), window->bounds().ToString());
   1156 
   1157   Blur(&text_input_client);
   1158 }
   1159 
   1160 }  // namespace ash
   1161