Home | History | Annotate | Download | only in wm
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ash/wm/workspace_controller.h"
      6 
      7 #include <map>
      8 
      9 #include "ash/ash_switches.h"
     10 #include "ash/root_window_controller.h"
     11 #include "ash/screen_ash.h"
     12 #include "ash/shelf/shelf_layout_manager.h"
     13 #include "ash/shelf/shelf_widget.h"
     14 #include "ash/shell.h"
     15 #include "ash/shell_window_ids.h"
     16 #include "ash/system/status_area_widget.h"
     17 #include "ash/test/ash_test_base.h"
     18 #include "ash/test/shell_test_api.h"
     19 #include "ash/wm/window_state.h"
     20 #include "ash/wm/window_util.h"
     21 #include "base/command_line.h"
     22 #include "base/strings/string_number_conversions.h"
     23 #include "ui/aura/client/aura_constants.h"
     24 #include "ui/aura/root_window.h"
     25 #include "ui/aura/test/event_generator.h"
     26 #include "ui/aura/test/test_window_delegate.h"
     27 #include "ui/aura/test/test_windows.h"
     28 #include "ui/aura/window.h"
     29 #include "ui/base/hit_test.h"
     30 #include "ui/base/ui_base_types.h"
     31 #include "ui/compositor/layer.h"
     32 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
     33 #include "ui/gfx/screen.h"
     34 #include "ui/views/corewm/window_animations.h"
     35 #include "ui/views/widget/widget.h"
     36 
     37 using aura::Window;
     38 
     39 namespace ash {
     40 namespace internal {
     41 
     42 // Returns a string containing the names of all the children of |window| (in
     43 // order). Each entry is separated by a space.
     44 std::string GetWindowNames(const aura::Window* window) {
     45   std::string result;
     46   for (size_t i = 0; i < window->children().size(); ++i) {
     47     if (i != 0)
     48       result += " ";
     49     result += window->children()[i]->name();
     50   }
     51   return result;
     52 }
     53 
     54 // Returns a string containing the names of windows corresponding to each of the
     55 // child layers of |window|'s layer. Any layers that don't correspond to a child
     56 // Window of |window| are ignored. The result is ordered based on the layer
     57 // ordering.
     58 std::string GetLayerNames(const aura::Window* window) {
     59   typedef std::map<const ui::Layer*, std::string> LayerToWindowNameMap;
     60   LayerToWindowNameMap window_names;
     61   for (size_t i = 0; i < window->children().size(); ++i) {
     62     window_names[window->children()[i]->layer()] =
     63         window->children()[i]->name();
     64   }
     65 
     66   std::string result;
     67   const std::vector<ui::Layer*>& layers(window->layer()->children());
     68   for (size_t i = 0; i < layers.size(); ++i) {
     69     LayerToWindowNameMap::iterator layer_i =
     70         window_names.find(layers[i]);
     71     if (layer_i != window_names.end()) {
     72       if (!result.empty())
     73         result += " ";
     74       result += layer_i->second;
     75     }
     76   }
     77   return result;
     78 }
     79 
     80 class WorkspaceControllerTest : public test::AshTestBase {
     81  public:
     82   WorkspaceControllerTest() {}
     83   virtual ~WorkspaceControllerTest() {}
     84 
     85   aura::Window* CreateTestWindowUnparented() {
     86     aura::Window* window = new aura::Window(NULL);
     87     window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
     88     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     89     window->Init(ui::LAYER_TEXTURED);
     90     return window;
     91   }
     92 
     93   aura::Window* CreateTestWindow() {
     94     aura::Window* window = new aura::Window(NULL);
     95     window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
     96     window->SetType(aura::client::WINDOW_TYPE_NORMAL);
     97     window->Init(ui::LAYER_TEXTURED);
     98     ParentWindowInPrimaryRootWindow(window);
     99     return window;
    100   }
    101 
    102   aura::Window* CreateBrowserLikeWindow(const gfx::Rect& bounds) {
    103     aura::Window* window = CreateTestWindow();
    104     window->SetBounds(bounds);
    105     wm::WindowState* window_state = wm::GetWindowState(window);
    106     window_state->set_window_position_managed(true);
    107     window->Show();
    108     return window;
    109   }
    110 
    111   aura::Window* CreatePopupLikeWindow(const gfx::Rect& bounds) {
    112     aura::Window* window = CreateTestWindowInShellWithBounds(bounds);
    113     window->Show();
    114     return window;
    115   }
    116 
    117   aura::Window* GetDesktop() {
    118     return Shell::GetContainer(Shell::GetPrimaryRootWindow(),
    119                                kShellWindowId_DefaultContainer);
    120   }
    121 
    122   gfx::Rect GetFullscreenBounds(aura::Window* window) {
    123     return Shell::GetScreen()->GetDisplayNearestWindow(window).bounds();
    124   }
    125 
    126   ShelfWidget* shelf_widget() {
    127     return Shell::GetPrimaryRootWindowController()->shelf();
    128   }
    129 
    130   ShelfLayoutManager* shelf_layout_manager() {
    131     return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    132   }
    133 
    134   bool GetWindowOverlapsShelf() {
    135     return shelf_layout_manager()->window_overlaps_shelf();
    136   }
    137 
    138  private:
    139   DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest);
    140 };
    141 
    142 // Assertions around adding a normal window.
    143 TEST_F(WorkspaceControllerTest, AddNormalWindowWhenEmpty) {
    144   scoped_ptr<Window> w1(CreateTestWindow());
    145   w1->SetBounds(gfx::Rect(0, 0, 250, 251));
    146 
    147   wm::WindowState* window_state = wm::GetWindowState(w1.get());
    148 
    149   EXPECT_FALSE(window_state->HasRestoreBounds());
    150 
    151   w1->Show();
    152 
    153   EXPECT_FALSE(window_state->HasRestoreBounds());
    154 
    155   ASSERT_TRUE(w1->layer() != NULL);
    156   EXPECT_TRUE(w1->layer()->visible());
    157 
    158   EXPECT_EQ("0,0 250x251", w1->bounds().ToString());
    159 
    160   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    161 }
    162 
    163 // Assertions around maximizing/unmaximizing.
    164 TEST_F(WorkspaceControllerTest, SingleMaximizeWindow) {
    165   scoped_ptr<Window> w1(CreateTestWindow());
    166   w1->SetBounds(gfx::Rect(0, 0, 250, 251));
    167 
    168   w1->Show();
    169   wm::ActivateWindow(w1.get());
    170 
    171   EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
    172 
    173   ASSERT_TRUE(w1->layer() != NULL);
    174   EXPECT_TRUE(w1->layer()->visible());
    175 
    176   EXPECT_EQ("0,0 250x251", w1->bounds().ToString());
    177 
    178   // Maximize the window.
    179   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    180 
    181   EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
    182 
    183   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    184   EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w1.get()).width(),
    185             w1->bounds().width());
    186   EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w1.get()).height(),
    187             w1->bounds().height());
    188 
    189   // Restore the window.
    190   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    191 
    192   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    193   EXPECT_EQ("0,0 250x251", w1->bounds().ToString());
    194 }
    195 
    196 // Assertions around two windows and toggling one to be fullscreen.
    197 TEST_F(WorkspaceControllerTest, FullscreenWithNormalWindow) {
    198   scoped_ptr<Window> w1(CreateTestWindow());
    199   scoped_ptr<Window> w2(CreateTestWindow());
    200   w1->SetBounds(gfx::Rect(0, 0, 250, 251));
    201   w1->Show();
    202 
    203   ASSERT_TRUE(w1->layer() != NULL);
    204   EXPECT_TRUE(w1->layer()->visible());
    205 
    206   w2->SetBounds(gfx::Rect(0, 0, 50, 51));
    207   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    208   w2->Show();
    209   wm::ActivateWindow(w2.get());
    210 
    211   // Both windows should be in the same workspace.
    212   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    213   EXPECT_EQ(w2.get(), GetDesktop()->children()[1]);
    214 
    215   gfx::Rect work_area(
    216       ScreenAsh::GetMaximizedWindowBoundsInParent(w1.get()));
    217   EXPECT_EQ(work_area.width(), w2->bounds().width());
    218   EXPECT_EQ(work_area.height(), w2->bounds().height());
    219 
    220   // Restore w2, which should then go back to one workspace.
    221   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    222   EXPECT_EQ(50, w2->bounds().width());
    223   EXPECT_EQ(51, w2->bounds().height());
    224   EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
    225 }
    226 
    227 // Makes sure requests to change the bounds of a normal window go through.
    228 TEST_F(WorkspaceControllerTest, ChangeBoundsOfNormalWindow) {
    229   scoped_ptr<Window> w1(CreateTestWindow());
    230   w1->Show();
    231 
    232   // Setting the bounds should go through since the window is in the normal
    233   // workspace.
    234   w1->SetBounds(gfx::Rect(0, 0, 200, 500));
    235   EXPECT_EQ(200, w1->bounds().width());
    236   EXPECT_EQ(500, w1->bounds().height());
    237 }
    238 
    239 // Verifies the bounds is not altered when showing and grid is enabled.
    240 TEST_F(WorkspaceControllerTest, SnapToGrid) {
    241   scoped_ptr<Window> w1(CreateTestWindowUnparented());
    242   w1->SetBounds(gfx::Rect(1, 6, 25, 30));
    243   ParentWindowInPrimaryRootWindow(w1.get());
    244   // We are not aligning this anymore this way. When the window gets shown
    245   // the window is expected to be handled differently, but this cannot be
    246   // tested with this test. So the result of this test should be that the
    247   // bounds are exactly as passed in.
    248   EXPECT_EQ("1,6 25x30", w1->bounds().ToString());
    249 }
    250 
    251 // Assertions around a fullscreen window.
    252 TEST_F(WorkspaceControllerTest, SingleFullscreenWindow) {
    253   scoped_ptr<Window> w1(CreateTestWindow());
    254   w1->SetBounds(gfx::Rect(0, 0, 250, 251));
    255   // Make the window fullscreen.
    256   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    257   w1->Show();
    258   wm::ActivateWindow(w1.get());
    259 
    260   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    261   EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width());
    262   EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height());
    263 
    264   // Restore the window. Use SHOW_STATE_DEFAULT as that is what we'll end up
    265   // with when using views::Widget.
    266   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_DEFAULT);
    267   EXPECT_EQ("0,0 250x251", w1->bounds().ToString());
    268 
    269   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    270   EXPECT_EQ(250, w1->bounds().width());
    271   EXPECT_EQ(251, w1->bounds().height());
    272 
    273   // Back to fullscreen.
    274   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    275   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    276   EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width());
    277   EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height());
    278   wm::WindowState* window_state = wm::GetWindowState(w1.get());
    279 
    280   ASSERT_TRUE(window_state->HasRestoreBounds());
    281   EXPECT_EQ("0,0 250x251", window_state->GetRestoreBoundsInScreen().ToString());
    282 }
    283 
    284 // Assertions around minimizing a single window.
    285 TEST_F(WorkspaceControllerTest, MinimizeSingleWindow) {
    286   scoped_ptr<Window> w1(CreateTestWindow());
    287 
    288   w1->Show();
    289 
    290   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    291   EXPECT_FALSE(w1->layer()->IsDrawn());
    292 
    293   // Show the window.
    294   w1->Show();
    295   EXPECT_TRUE(wm::GetWindowState(w1.get())->IsNormalShowState());
    296   EXPECT_TRUE(w1->layer()->IsDrawn());
    297 }
    298 
    299 // Assertions around minimizing a fullscreen window.
    300 TEST_F(WorkspaceControllerTest, MinimizeFullscreenWindow) {
    301   // Two windows, w1 normal, w2 fullscreen.
    302   scoped_ptr<Window> w1(CreateTestWindow());
    303   scoped_ptr<Window> w2(CreateTestWindow());
    304   w1->Show();
    305   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    306   w2->Show();
    307 
    308   wm::WindowState* w1_state = wm::GetWindowState(w1.get());
    309   wm::WindowState* w2_state = wm::GetWindowState(w2.get());
    310 
    311   w2_state->Activate();
    312 
    313   // Minimize w2.
    314   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    315   EXPECT_TRUE(w1->layer()->IsDrawn());
    316   EXPECT_FALSE(w2->layer()->IsDrawn());
    317 
    318   // Show the window, which should trigger unminimizing.
    319   w2->Show();
    320   w2_state->Activate();
    321 
    322   EXPECT_TRUE(w2_state->IsFullscreen());
    323   EXPECT_TRUE(w1->layer()->IsDrawn());
    324   EXPECT_TRUE(w2->layer()->IsDrawn());
    325 
    326   // Minimize the window, which should hide the window.
    327   EXPECT_TRUE(w2_state->IsActive());
    328   w2_state->Minimize();
    329   EXPECT_FALSE(w2_state->IsActive());
    330   EXPECT_FALSE(w2->layer()->IsDrawn());
    331   EXPECT_TRUE(w1_state->IsActive());
    332 
    333   // Make the window normal.
    334   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    335   EXPECT_EQ(w1.get(), GetDesktop()->children()[0]);
    336   EXPECT_EQ(w2.get(), GetDesktop()->children()[1]);
    337   EXPECT_TRUE(w2->layer()->IsDrawn());
    338 }
    339 
    340 // Verifies ShelfLayoutManager's visibility/auto-hide state is correctly
    341 // updated.
    342 TEST_F(WorkspaceControllerTest, ShelfStateUpdated) {
    343   // Since ShelfLayoutManager queries for mouse location, move the mouse so
    344   // it isn't over the shelf.
    345   aura::test::EventGenerator generator(
    346       Shell::GetPrimaryRootWindow(), gfx::Point());
    347   generator.MoveMouseTo(0, 0);
    348 
    349   scoped_ptr<Window> w1(CreateTestWindow());
    350   const gfx::Rect w1_bounds(0, 1, 101, 102);
    351   ShelfLayoutManager* shelf = shelf_layout_manager();
    352   shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    353   const gfx::Rect touches_shelf_bounds(
    354       0, shelf->GetIdealBounds().y() - 10, 101, 102);
    355   // Move |w1| to overlap the shelf.
    356   w1->SetBounds(touches_shelf_bounds);
    357   EXPECT_FALSE(GetWindowOverlapsShelf());
    358 
    359   // A visible ignored window should not trigger the overlap.
    360   scoped_ptr<Window> w_ignored(CreateTestWindow());
    361   w_ignored->SetBounds(touches_shelf_bounds);
    362   wm::GetWindowState(&(*w_ignored))->set_ignored_by_shelf(true);
    363   w_ignored->Show();
    364   EXPECT_FALSE(GetWindowOverlapsShelf());
    365 
    366   // Make it visible, since visible shelf overlaps should be true.
    367   w1->Show();
    368   EXPECT_TRUE(GetWindowOverlapsShelf());
    369 
    370   wm::ActivateWindow(w1.get());
    371   w1->SetBounds(w1_bounds);
    372   w1->Show();
    373   wm::ActivateWindow(w1.get());
    374 
    375   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    376 
    377   // Maximize the window.
    378   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    379   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    380   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
    381 
    382   // Restore.
    383   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    384   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    385   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    386 
    387   // Fullscreen.
    388   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    389   EXPECT_EQ(SHELF_HIDDEN, shelf->visibility_state());
    390 
    391   // Normal.
    392   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    393   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    394   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    395   EXPECT_FALSE(GetWindowOverlapsShelf());
    396 
    397   // Move window so it obscures shelf.
    398   w1->SetBounds(touches_shelf_bounds);
    399   EXPECT_TRUE(GetWindowOverlapsShelf());
    400 
    401   // Move it back.
    402   w1->SetBounds(w1_bounds);
    403   EXPECT_FALSE(GetWindowOverlapsShelf());
    404 
    405   // Maximize again.
    406   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    407   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    408   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
    409 
    410   // Minimize.
    411   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    412   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    413 
    414   // Since the restore from minimize will restore to the pre-minimize
    415   // state (tested elsewhere), we abandon the current size and restore
    416   // rect and set them to the window.
    417   wm::WindowState* window_state = wm::GetWindowState(w1.get());
    418 
    419   gfx::Rect restore = window_state->GetRestoreBoundsInScreen();
    420   EXPECT_EQ("0,0 800x597", w1->bounds().ToString());
    421   EXPECT_EQ("0,1 101x102", restore.ToString());
    422   window_state->ClearRestoreBounds();
    423   w1->SetBounds(restore);
    424 
    425   // Restore.
    426   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    427   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    428   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    429 
    430   // Create another window, maximized.
    431   scoped_ptr<Window> w2(CreateTestWindow());
    432   w2->SetBounds(gfx::Rect(10, 11, 250, 251));
    433   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    434   w2->Show();
    435   wm::ActivateWindow(w2.get());
    436   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    437   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
    438   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    439 
    440   // Switch to w1.
    441   wm::ActivateWindow(w1.get());
    442   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    443   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    444   EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(
    445                 w2->parent()).ToString(),
    446             w2->bounds().ToString());
    447 
    448   // Switch to w2.
    449   wm::ActivateWindow(w2.get());
    450   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
    451   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
    452   EXPECT_EQ("0,1 101x102", w1->bounds().ToString());
    453   EXPECT_EQ(ScreenAsh::GetMaximizedWindowBoundsInParent(w2.get()).ToString(),
    454             w2->bounds().ToString());
    455 
    456   // Turn off auto-hide, switch back to w2 (maximized) and verify overlap.
    457   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
    458   wm::ActivateWindow(w2.get());
    459   EXPECT_FALSE(GetWindowOverlapsShelf());
    460 
    461   // Move w1 to overlap shelf, it shouldn't change window overlaps shelf since
    462   // the window isn't in the visible workspace.
    463   w1->SetBounds(touches_shelf_bounds);
    464   EXPECT_FALSE(GetWindowOverlapsShelf());
    465 
    466   // Activate w1. Although w1 is visible, the overlap state is still false since
    467   // w2 is maximized.
    468   wm::ActivateWindow(w1.get());
    469   EXPECT_FALSE(GetWindowOverlapsShelf());
    470 
    471   // Restore w2.
    472   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    473   EXPECT_TRUE(GetWindowOverlapsShelf());
    474 }
    475 
    476 // Verifies going from maximized to minimized sets the right state for painting
    477 // the background of the launcher.
    478 TEST_F(WorkspaceControllerTest, MinimizeResetsVisibility) {
    479   scoped_ptr<Window> w1(CreateTestWindow());
    480   w1->Show();
    481   wm::ActivateWindow(w1.get());
    482   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    483   EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, shelf_widget()->GetBackgroundType());
    484 
    485   w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
    486   EXPECT_EQ(SHELF_VISIBLE,
    487             shelf_layout_manager()->visibility_state());
    488   EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, shelf_widget()->GetBackgroundType());
    489 }
    490 
    491 // Verifies window visibility during various workspace changes.
    492 TEST_F(WorkspaceControllerTest, VisibilityTests) {
    493   scoped_ptr<Window> w1(CreateTestWindow());
    494   w1->Show();
    495   EXPECT_TRUE(w1->IsVisible());
    496   EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity());
    497 
    498   // Create another window, activate it and make it fullscreen.
    499   scoped_ptr<Window> w2(CreateTestWindow());
    500   w2->Show();
    501   wm::ActivateWindow(w2.get());
    502   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    503   EXPECT_TRUE(w2->IsVisible());
    504   EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity());
    505   EXPECT_TRUE(w1->IsVisible());
    506 
    507   // Switch to w1. |w1| should be visible on top of |w2|.
    508   wm::ActivateWindow(w1.get());
    509   EXPECT_TRUE(w1->IsVisible());
    510   EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity());
    511   EXPECT_TRUE(w2->IsVisible());
    512 
    513   // Switch back to |w2|.
    514   wm::ActivateWindow(w2.get());
    515   EXPECT_TRUE(w2->IsVisible());
    516   EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity());
    517   EXPECT_TRUE(w1->IsVisible());
    518 
    519   // Restore |w2|, both windows should be visible.
    520   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    521   EXPECT_TRUE(w1->IsVisible());
    522   EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity());
    523   EXPECT_TRUE(w2->IsVisible());
    524   EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity());
    525 
    526   // Make |w2| fullscreen again, then close it.
    527   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    528   w2->Hide();
    529   EXPECT_FALSE(w2->IsVisible());
    530   EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity());
    531   EXPECT_TRUE(w1->IsVisible());
    532 
    533   // Create |w2| and maximize it.
    534   w2.reset(CreateTestWindow());
    535   w2->Show();
    536   wm::ActivateWindow(w2.get());
    537   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    538   EXPECT_TRUE(w2->IsVisible());
    539   EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity());
    540   EXPECT_TRUE(w1->IsVisible());
    541 
    542   // Close |w2|.
    543   w2.reset();
    544   EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity());
    545   EXPECT_TRUE(w1->IsVisible());
    546 }
    547 
    548 // Verifies windows that are offscreen don't move when switching workspaces.
    549 TEST_F(WorkspaceControllerTest, DontMoveOnSwitch) {
    550   aura::test::EventGenerator generator(
    551       Shell::GetPrimaryRootWindow(), gfx::Point());
    552   generator.MoveMouseTo(0, 0);
    553 
    554   scoped_ptr<Window> w1(CreateTestWindow());
    555   ShelfLayoutManager* shelf = shelf_layout_manager();
    556   const gfx::Rect touches_shelf_bounds(
    557       0, shelf->GetIdealBounds().y() - 10, 101, 102);
    558   // Move |w1| to overlap the shelf.
    559   w1->SetBounds(touches_shelf_bounds);
    560   w1->Show();
    561   wm::ActivateWindow(w1.get());
    562 
    563   // Create another window and maximize it.
    564   scoped_ptr<Window> w2(CreateTestWindow());
    565   w2->SetBounds(gfx::Rect(10, 11, 250, 251));
    566   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    567   w2->Show();
    568   wm::ActivateWindow(w2.get());
    569 
    570   // Switch to w1.
    571   wm::ActivateWindow(w1.get());
    572   EXPECT_EQ(touches_shelf_bounds.ToString(), w1->bounds().ToString());
    573 }
    574 
    575 // Verifies that windows that are completely offscreen move when switching
    576 // workspaces.
    577 TEST_F(WorkspaceControllerTest, MoveOnSwitch) {
    578   aura::test::EventGenerator generator(
    579       Shell::GetPrimaryRootWindow(), gfx::Point());
    580   generator.MoveMouseTo(0, 0);
    581 
    582   scoped_ptr<Window> w1(CreateTestWindow());
    583   ShelfLayoutManager* shelf = shelf_layout_manager();
    584   const gfx::Rect w1_bounds(0, shelf->GetIdealBounds().y(), 100, 200);
    585   // Move |w1| so that the top edge is the same as the top edge of the shelf.
    586   w1->SetBounds(w1_bounds);
    587   w1->Show();
    588   wm::ActivateWindow(w1.get());
    589   EXPECT_EQ(w1_bounds.ToString(), w1->bounds().ToString());
    590 
    591   // Create another window and maximize it.
    592   scoped_ptr<Window> w2(CreateTestWindow());
    593   w2->SetBounds(gfx::Rect(10, 11, 250, 251));
    594   w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
    595   w2->Show();
    596   wm::ActivateWindow(w2.get());
    597 
    598   // Increase the size of the WorkAreaInsets. This would make |w1| fall
    599   // completely out of the display work area.
    600   gfx::Insets insets =
    601       Shell::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets();
    602   insets.Set(0, 0, insets.bottom() + 30, 0);
    603   Shell::GetInstance()->SetDisplayWorkAreaInsets(w1.get(), insets);
    604 
    605   // Switch to w1. The window should have moved.
    606   wm::ActivateWindow(w1.get());
    607   EXPECT_NE(w1_bounds.ToString(), w1->bounds().ToString());
    608 }
    609 
    610 namespace {
    611 
    612 // WindowDelegate used by DontCrashOnChangeAndActivate.
    613 class DontCrashOnChangeAndActivateDelegate
    614     : public aura::test::TestWindowDelegate {
    615  public:
    616   DontCrashOnChangeAndActivateDelegate() : window_(NULL) {}
    617 
    618   void set_window(aura::Window* window) { window_ = window; }
    619 
    620   // WindowDelegate overrides:
    621   virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
    622                                const gfx::Rect& new_bounds) OVERRIDE {
    623     if (window_) {
    624       wm::ActivateWindow(window_);
    625       window_ = NULL;
    626     }
    627   }
    628 
    629  private:
    630   aura::Window* window_;
    631 
    632   DISALLOW_COPY_AND_ASSIGN(DontCrashOnChangeAndActivateDelegate);
    633 };
    634 
    635 }  // namespace
    636 
    637 // Exercises possible crash in W2. Here's the sequence:
    638 // . minimize a maximized window.
    639 // . remove the window (which happens when switching displays).
    640 // . add the window back.
    641 // . show the window and during the bounds change activate it.
    642 TEST_F(WorkspaceControllerTest, DontCrashOnChangeAndActivate) {
    643   // Force the shelf
    644   ShelfLayoutManager* shelf = shelf_layout_manager();
    645   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
    646 
    647   DontCrashOnChangeAndActivateDelegate delegate;
    648   scoped_ptr<Window> w1(CreateTestWindowInShellWithDelegate(
    649       &delegate, 1000, gfx::Rect(10, 11, 250, 251)));
    650 
    651   w1->Show();
    652   wm::WindowState* w1_state = wm::GetWindowState(w1.get());
    653   w1_state->Activate();
    654   w1_state->Maximize();
    655   w1_state->Minimize();
    656 
    657   w1->parent()->RemoveChild(w1.get());
    658 
    659   // Do this so that when we Show() the window a resize occurs and we make the
    660   // window active.
    661   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    662 
    663   ParentWindowInPrimaryRootWindow(w1.get());
    664   delegate.set_window(w1.get());
    665   w1->Show();
    666 }
    667 
    668 // Verifies a window with a transient parent not managed by workspace works.
    669 TEST_F(WorkspaceControllerTest, TransientParent) {
    670   // Normal window with no transient parent.
    671   scoped_ptr<Window> w2(CreateTestWindow());
    672   w2->SetBounds(gfx::Rect(10, 11, 250, 251));
    673   w2->Show();
    674   wm::ActivateWindow(w2.get());
    675 
    676   // Window with a transient parent. We set the transient parent to the root,
    677   // which would never happen but is enough to exercise the bug.
    678   scoped_ptr<Window> w1(CreateTestWindowUnparented());
    679   Shell::GetInstance()->GetPrimaryRootWindow()->AddTransientChild(w1.get());
    680   w1->SetBounds(gfx::Rect(10, 11, 250, 251));
    681   ParentWindowInPrimaryRootWindow(w1.get());
    682   w1->Show();
    683   wm::ActivateWindow(w1.get());
    684 
    685   // The window with the transient parent should get added to the same parent as
    686   // the normal window.
    687   EXPECT_EQ(w2->parent(), w1->parent());
    688 }
    689 
    690 // Test the placement of newly created windows.
    691 TEST_F(WorkspaceControllerTest, BasicAutoPlacingOnCreate) {
    692   if (!SupportsHostWindowResize())
    693     return;
    694   UpdateDisplay("1600x1200");
    695   // Creating a popup handler here to make sure it does not interfere with the
    696   // existing windows.
    697   gfx::Rect source_browser_bounds(16, 32, 640, 320);
    698   scoped_ptr<aura::Window> browser_window(CreateBrowserLikeWindow(
    699       source_browser_bounds));
    700 
    701   // Creating a popup to make sure it does not interfere with the positioning.
    702   scoped_ptr<aura::Window> browser_popup(CreatePopupLikeWindow(
    703       gfx::Rect(16, 32, 128, 256)));
    704 
    705   browser_window->Show();
    706   browser_popup->Show();
    707 
    708   { // With a shown window it's size should get returned.
    709     scoped_ptr<aura::Window> new_browser_window(CreateBrowserLikeWindow(
    710         source_browser_bounds));
    711     // The position should be right flush.
    712     EXPECT_EQ("960,32 640x320", new_browser_window->bounds().ToString());
    713   }
    714 
    715   { // With the window shown - but more on the right side then on the left
    716     // side (and partially out of the screen), it should default to the other
    717     // side and inside the screen.
    718     gfx::Rect source_browser_bounds(gfx::Rect(1000, 600, 640, 320));
    719     browser_window->SetBounds(source_browser_bounds);
    720 
    721     scoped_ptr<aura::Window> new_browser_window(CreateBrowserLikeWindow(
    722         source_browser_bounds));
    723     // The position should be left & bottom flush.
    724     EXPECT_EQ("0,600 640x320", new_browser_window->bounds().ToString());
    725 
    726     // If the other window was already beyond the point to get right flush
    727     // it will remain where it is.
    728     EXPECT_EQ("1000,600 640x320", browser_window->bounds().ToString());
    729   }
    730 
    731   { // Make sure that popups do not get changed.
    732     scoped_ptr<aura::Window> new_popup_window(CreatePopupLikeWindow(
    733         gfx::Rect(50, 100, 300, 150)));
    734     EXPECT_EQ("50,100 300x150", new_popup_window->bounds().ToString());
    735   }
    736 
    737   browser_window->Hide();
    738   { // If a window is there but not shown the default should be centered.
    739     scoped_ptr<aura::Window> new_browser_window(CreateBrowserLikeWindow(
    740         gfx::Rect(50, 100, 300, 150)));
    741     EXPECT_EQ("650,100 300x150", new_browser_window->bounds().ToString());
    742   }
    743 }
    744 
    745 // Test the basic auto placement of one and or two windows in a "simulated
    746 // session" of sequential window operations.
    747 TEST_F(WorkspaceControllerTest, BasicAutoPlacingOnShowHide) {
    748   // Test 1: In case there is no manageable window, no window should shift.
    749 
    750   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
    751   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
    752   gfx::Rect desktop_area = window1->parent()->bounds();
    753 
    754   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
    755   // Trigger the auto window placement function by making it visible.
    756   // Note that the bounds are getting changed while it is invisible.
    757   window2->Hide();
    758   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
    759   window2->Show();
    760 
    761   // Check the initial position of the windows is unchanged.
    762   EXPECT_EQ("16,32 640x320", window1->bounds().ToString());
    763   EXPECT_EQ("32,48 256x512", window2->bounds().ToString());
    764 
    765   // Remove the second window and make sure that the first window
    766   // does NOT get centered.
    767   window2.reset();
    768   EXPECT_EQ("16,32 640x320", window1->bounds().ToString());
    769 
    770   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
    771   // Test 2: Set up two managed windows and check their auto positioning.
    772   window1_state->set_window_position_managed(true);
    773 
    774   scoped_ptr<aura::Window> window3(CreateTestWindowInShellWithId(2));
    775   wm::GetWindowState(window3.get())->set_window_position_managed(true);
    776   // To avoid any auto window manager changes due to SetBounds, the window
    777   // gets first hidden and then shown again.
    778   window3->Hide();
    779   window3->SetBounds(gfx::Rect(32, 48, 256, 512));
    780   window3->Show();
    781   // |window1| should be flush left and |window3| flush right.
    782   EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
    783   EXPECT_EQ(base::IntToString(
    784                 desktop_area.width() - window3->bounds().width()) +
    785             ",48 256x512", window3->bounds().ToString());
    786 
    787   // After removing |window3|, |window1| should be centered again.
    788   window3.reset();
    789   EXPECT_EQ(
    790       base::IntToString(
    791           (desktop_area.width() - window1->bounds().width()) / 2) +
    792       ",32 640x320", window1->bounds().ToString());
    793 
    794   // Test 3: Set up a manageable and a non manageable window and check
    795   // positioning.
    796   scoped_ptr<aura::Window> window4(CreateTestWindowInShellWithId(3));
    797   // To avoid any auto window manager changes due to SetBounds, the window
    798   // gets first hidden and then shown again.
    799   window1->Hide();
    800   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
    801   window4->SetBounds(gfx::Rect(32, 48, 256, 512));
    802   window1->Show();
    803   // |window1| should be centered and |window4| untouched.
    804   EXPECT_EQ(
    805       base::IntToString(
    806           (desktop_area.width() - window1->bounds().width()) / 2) +
    807       ",32 640x320", window1->bounds().ToString());
    808   EXPECT_EQ("32,48 256x512", window4->bounds().ToString());
    809 
    810   // Test4: A single manageable window should get centered.
    811   window4.reset();
    812   window1_state->set_bounds_changed_by_user(false);
    813   // Trigger the auto window placement function by showing (and hiding) it.
    814   window1->Hide();
    815   window1->Show();
    816   // |window1| should be centered.
    817   EXPECT_EQ(
    818       base::IntToString(
    819           (desktop_area.width() - window1->bounds().width()) / 2) +
    820       ",32 640x320", window1->bounds().ToString());
    821 }
    822 
    823 // Test the proper usage of user window movement interaction.
    824 TEST_F(WorkspaceControllerTest, TestUserMovedWindowRepositioning) {
    825   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
    826   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
    827   gfx::Rect desktop_area = window1->parent()->bounds();
    828   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
    829   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
    830   window1->Hide();
    831   window2->Hide();
    832   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
    833   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
    834 
    835   window1_state->set_window_position_managed(true);
    836   window2_state->set_window_position_managed(true);
    837   EXPECT_FALSE(window1_state->bounds_changed_by_user());
    838   EXPECT_FALSE(window2_state->bounds_changed_by_user());
    839 
    840   // Check that the current location gets preserved if the user has
    841   // positioned it previously.
    842   window1_state->set_bounds_changed_by_user(true);
    843   window1->Show();
    844   EXPECT_EQ("16,32 640x320", window1->bounds().ToString());
    845   // Flag should be still set.
    846   EXPECT_TRUE(window1_state->bounds_changed_by_user());
    847   EXPECT_FALSE(window2_state->bounds_changed_by_user());
    848 
    849   // Turn on the second window and make sure that both windows are now
    850   // positionable again (user movement cleared).
    851   window2->Show();
    852 
    853   // |window1| should be flush left and |window2| flush right.
    854   EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
    855   EXPECT_EQ(
    856       base::IntToString(desktop_area.width() - window2->bounds().width()) +
    857       ",48 256x512", window2->bounds().ToString());
    858   // FLag should now be reset.
    859   EXPECT_FALSE(window1_state->bounds_changed_by_user());
    860   EXPECT_FALSE(window2_state->bounds_changed_by_user());
    861 
    862   // Going back to one shown window should keep the state.
    863   window1_state->set_bounds_changed_by_user(true);
    864   window2->Hide();
    865   EXPECT_EQ("0,32 640x320", window1->bounds().ToString());
    866   EXPECT_TRUE(window1_state->bounds_changed_by_user());
    867 }
    868 
    869 // Test if the single window will be restored at original position.
    870 TEST_F(WorkspaceControllerTest, TestSingleWindowsRestoredBounds) {
    871   scoped_ptr<aura::Window> window1(
    872       CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
    873   scoped_ptr<aura::Window> window2(
    874       CreateTestWindowInShellWithBounds(gfx::Rect(110, 110, 100, 100)));
    875   scoped_ptr<aura::Window> window3(
    876       CreateTestWindowInShellWithBounds(gfx::Rect(120, 120, 100, 100)));
    877   window1->Hide();
    878   window2->Hide();
    879   window3->Hide();
    880   wm::GetWindowState(window1.get())->set_window_position_managed(true);
    881   wm::GetWindowState(window2.get())->set_window_position_managed(true);
    882   wm::GetWindowState(window3.get())->set_window_position_managed(true);
    883 
    884   window1->Show();
    885   wm::ActivateWindow(window1.get());
    886   window2->Show();
    887   wm::ActivateWindow(window2.get());
    888   window3->Show();
    889   wm::ActivateWindow(window3.get());
    890   EXPECT_EQ(0, window1->bounds().x());
    891   EXPECT_EQ(window2->GetRootWindow()->bounds().right(),
    892             window2->bounds().right());
    893   EXPECT_EQ(0, window3->bounds().x());
    894 
    895   window1->Hide();
    896   EXPECT_EQ(window2->GetRootWindow()->bounds().right(),
    897             window2->bounds().right());
    898   EXPECT_EQ(0, window3->bounds().x());
    899 
    900   // Being a single window will retore the original location.
    901   window3->Hide();
    902   wm::ActivateWindow(window2.get());
    903   EXPECT_EQ("110,110 100x100", window2->bounds().ToString());
    904 
    905   // Showing the 3rd will push the 2nd window left.
    906   window3->Show();
    907   wm::ActivateWindow(window3.get());
    908   EXPECT_EQ(0, window2->bounds().x());
    909   EXPECT_EQ(window3->GetRootWindow()->bounds().right(),
    910             window3->bounds().right());
    911 
    912   // Being a single window will retore the original location.
    913   window2->Hide();
    914   EXPECT_EQ("120,120 100x100", window3->bounds().ToString());
    915 }
    916 
    917 // Test that user placed windows go back to their user placement after the user
    918 // closes all other windows.
    919 TEST_F(WorkspaceControllerTest, TestUserHandledWindowRestore) {
    920   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
    921   gfx::Rect user_pos = gfx::Rect(16, 42, 640, 320);
    922   window1->SetBounds(user_pos);
    923   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
    924 
    925   window1_state->SetPreAutoManageWindowBounds(user_pos);
    926   gfx::Rect desktop_area = window1->parent()->bounds();
    927 
    928   // Create a second window to let the auto manager kick in.
    929   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
    930   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
    931   window1->Hide();
    932   window2->Hide();
    933   wm::GetWindowState(window1.get())->set_window_position_managed(true);
    934   wm::GetWindowState(window2.get())->set_window_position_managed(true);
    935   window1->Show();
    936   EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString());
    937   window2->Show();
    938 
    939   // |window1| should be flush left and |window2| flush right.
    940   EXPECT_EQ("0," + base::IntToString(user_pos.y()) +
    941             " 640x320", window1->bounds().ToString());
    942   EXPECT_EQ(
    943       base::IntToString(desktop_area.width() - window2->bounds().width()) +
    944       ",48 256x512", window2->bounds().ToString());
    945   window2->Hide();
    946 
    947   // After the other window get hidden the window has to move back to the
    948   // previous position and the bounds should still be set and unchanged.
    949   EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString());
    950   ASSERT_TRUE(window1_state->pre_auto_manage_window_bounds());
    951   EXPECT_EQ(user_pos.ToString(),
    952             window1_state->pre_auto_manage_window_bounds()->ToString());
    953 }
    954 
    955 // Test that a window from normal to minimize will repos the remaining.
    956 TEST_F(WorkspaceControllerTest, ToMinimizeRepositionsRemaining) {
    957   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
    958   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
    959   window1_state->set_window_position_managed(true);
    960   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
    961   gfx::Rect desktop_area = window1->parent()->bounds();
    962 
    963   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
    964   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
    965   window2_state->set_window_position_managed(true);
    966   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
    967 
    968   window1_state->Minimize();
    969 
    970   // |window2| should be centered now.
    971   EXPECT_TRUE(window2->IsVisible());
    972   EXPECT_TRUE(window2_state->IsNormalShowState());
    973   EXPECT_EQ(base::IntToString(
    974                 (desktop_area.width() - window2->bounds().width()) / 2) +
    975             ",48 256x512", window2->bounds().ToString());
    976 
    977   window1_state->Restore();
    978   // |window1| should be flush right and |window3| flush left.
    979   EXPECT_EQ(base::IntToString(
    980                 desktop_area.width() - window1->bounds().width()) +
    981             ",32 640x320", window1->bounds().ToString());
    982   EXPECT_EQ("0,48 256x512", window2->bounds().ToString());
    983 }
    984 
    985 // Test that minimizing an initially maximized window will repos the remaining.
    986 TEST_F(WorkspaceControllerTest, MaxToMinRepositionsRemaining) {
    987   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
    988   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
    989   window1_state->set_window_position_managed(true);
    990   gfx::Rect desktop_area = window1->parent()->bounds();
    991 
    992   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
    993   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
    994   window2_state->set_window_position_managed(true);
    995   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
    996 
    997   window1_state->Maximize();
    998   window1_state->Minimize();
    999 
   1000   // |window2| should be centered now.
   1001   EXPECT_TRUE(window2->IsVisible());
   1002   EXPECT_TRUE(window2_state->IsNormalShowState());
   1003   EXPECT_EQ(base::IntToString(
   1004                 (desktop_area.width() - window2->bounds().width()) / 2) +
   1005             ",48 256x512", window2->bounds().ToString());
   1006 }
   1007 
   1008 // Test that nomral, maximize, minimizing will repos the remaining.
   1009 TEST_F(WorkspaceControllerTest, NormToMaxToMinRepositionsRemaining) {
   1010   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   1011   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   1012   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
   1013   window1_state->set_window_position_managed(true);
   1014   gfx::Rect desktop_area = window1->parent()->bounds();
   1015 
   1016   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   1017   wm::WindowState* window2_state = wm::GetWindowState(window2.get());
   1018   window2_state->set_window_position_managed(true);
   1019   window2->SetBounds(gfx::Rect(32, 40, 256, 512));
   1020 
   1021   // Trigger the auto window placement function by showing (and hiding) it.
   1022   window1->Hide();
   1023   window1->Show();
   1024 
   1025   // |window1| should be flush right and |window3| flush left.
   1026   EXPECT_EQ(base::IntToString(
   1027                 desktop_area.width() - window1->bounds().width()) +
   1028             ",32 640x320", window1->bounds().ToString());
   1029   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
   1030 
   1031   window1_state->Maximize();
   1032   window1_state->Minimize();
   1033 
   1034   // |window2| should be centered now.
   1035   EXPECT_TRUE(window2->IsVisible());
   1036   EXPECT_TRUE(window2_state->IsNormalShowState());
   1037   EXPECT_EQ(base::IntToString(
   1038                 (desktop_area.width() - window2->bounds().width()) / 2) +
   1039             ",40 256x512", window2->bounds().ToString());
   1040 }
   1041 
   1042 // Test that nomral, maximize, normal will repos the remaining.
   1043 TEST_F(WorkspaceControllerTest, NormToMaxToNormRepositionsRemaining) {
   1044   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   1045   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   1046   wm::WindowState* window1_state = wm::GetWindowState(window1.get());
   1047   window1_state->set_window_position_managed(true);
   1048   gfx::Rect desktop_area = window1->parent()->bounds();
   1049 
   1050   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   1051   wm::GetWindowState(window2.get())->set_window_position_managed(true);
   1052   window2->SetBounds(gfx::Rect(32, 40, 256, 512));
   1053 
   1054   // Trigger the auto window placement function by showing (and hiding) it.
   1055   window1->Hide();
   1056   window1->Show();
   1057 
   1058   // |window1| should be flush right and |window3| flush left.
   1059   EXPECT_EQ(base::IntToString(
   1060                 desktop_area.width() - window1->bounds().width()) +
   1061             ",32 640x320", window1->bounds().ToString());
   1062   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
   1063 
   1064   window1_state->Maximize();
   1065   window1_state->Restore();
   1066 
   1067   // |window1| should be flush right and |window2| flush left.
   1068   EXPECT_EQ(base::IntToString(
   1069                 desktop_area.width() - window1->bounds().width()) +
   1070             ",32 640x320", window1->bounds().ToString());
   1071   EXPECT_EQ("0,40 256x512", window2->bounds().ToString());
   1072 }
   1073 
   1074 // Test that animations are triggered.
   1075 TEST_F(WorkspaceControllerTest, AnimatedNormToMaxToNormRepositionsRemaining) {
   1076   ui::ScopedAnimationDurationScaleMode normal_duration_mode(
   1077       ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
   1078   scoped_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   1079   window1->Hide();
   1080   window1->SetBounds(gfx::Rect(16, 32, 640, 320));
   1081   gfx::Rect desktop_area = window1->parent()->bounds();
   1082   scoped_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   1083   window2->Hide();
   1084   window2->SetBounds(gfx::Rect(32, 48, 256, 512));
   1085 
   1086   wm::GetWindowState(window1.get())->set_window_position_managed(true);
   1087   wm::GetWindowState(window2.get())->set_window_position_managed(true);
   1088   // Make sure nothing is animating.
   1089   window1->layer()->GetAnimator()->StopAnimating();
   1090   window2->layer()->GetAnimator()->StopAnimating();
   1091   window2->Show();
   1092 
   1093   // The second window should now animate.
   1094   EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating());
   1095   EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
   1096   window2->layer()->GetAnimator()->StopAnimating();
   1097 
   1098   window1->Show();
   1099   EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
   1100   EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
   1101 
   1102   window1->layer()->GetAnimator()->StopAnimating();
   1103   window2->layer()->GetAnimator()->StopAnimating();
   1104   // |window1| should be flush right and |window2| flush left.
   1105   EXPECT_EQ(base::IntToString(
   1106                 desktop_area.width() - window1->bounds().width()) +
   1107             ",32 640x320", window1->bounds().ToString());
   1108   EXPECT_EQ("0,48 256x512", window2->bounds().ToString());
   1109 }
   1110 
   1111 // This tests simulates a browser and an app and verifies the ordering of the
   1112 // windows and layers doesn't get out of sync as various operations occur. Its
   1113 // really testing code in FocusController, but easier to simulate here. Just as
   1114 // with a real browser the browser here has a transient child window
   1115 // (corresponds to the status bubble).
   1116 TEST_F(WorkspaceControllerTest, VerifyLayerOrdering) {
   1117   scoped_ptr<Window> browser(
   1118       aura::test::CreateTestWindowWithDelegate(
   1119           NULL,
   1120           aura::client::WINDOW_TYPE_NORMAL,
   1121           gfx::Rect(5, 6, 7, 8),
   1122           NULL));
   1123   browser->SetName("browser");
   1124   ParentWindowInPrimaryRootWindow(browser.get());
   1125   browser->Show();
   1126   wm::ActivateWindow(browser.get());
   1127 
   1128   // |status_bubble| is made a transient child of |browser| and as a result
   1129   // owned by |browser|.
   1130   aura::test::TestWindowDelegate* status_bubble_delegate =
   1131       aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate();
   1132   status_bubble_delegate->set_can_focus(false);
   1133   Window* status_bubble =
   1134       aura::test::CreateTestWindowWithDelegate(
   1135           status_bubble_delegate,
   1136           aura::client::WINDOW_TYPE_POPUP,
   1137           gfx::Rect(5, 6, 7, 8),
   1138           NULL);
   1139   browser->AddTransientChild(status_bubble);
   1140   ParentWindowInPrimaryRootWindow(status_bubble);
   1141   status_bubble->SetName("status_bubble");
   1142 
   1143   scoped_ptr<Window> app(
   1144       aura::test::CreateTestWindowWithDelegate(
   1145           NULL,
   1146           aura::client::WINDOW_TYPE_NORMAL,
   1147           gfx::Rect(5, 6, 7, 8),
   1148           NULL));
   1149   app->SetName("app");
   1150   ParentWindowInPrimaryRootWindow(app.get());
   1151 
   1152   aura::Window* parent = browser->parent();
   1153 
   1154   app->Show();
   1155   wm::ActivateWindow(app.get());
   1156   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1157 
   1158   // Minimize the app, focus should go the browser.
   1159   app->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
   1160   EXPECT_TRUE(wm::IsActiveWindow(browser.get()));
   1161   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1162 
   1163   // Minimize the browser (neither windows are focused).
   1164   browser->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
   1165   EXPECT_FALSE(wm::IsActiveWindow(browser.get()));
   1166   EXPECT_FALSE(wm::IsActiveWindow(app.get()));
   1167   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1168 
   1169   // Show the browser (which should restore it).
   1170   browser->Show();
   1171   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1172 
   1173   // Activate the browser.
   1174   ash::wm::ActivateWindow(browser.get());
   1175   EXPECT_TRUE(wm::IsActiveWindow(browser.get()));
   1176   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1177 
   1178   // Restore the app. This differs from above code for |browser| as internally
   1179   // the app code does this. Restoring this way or using Show() should not make
   1180   // a difference.
   1181   app->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
   1182   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1183 
   1184   // Activate the app.
   1185   ash::wm::ActivateWindow(app.get());
   1186   EXPECT_TRUE(wm::IsActiveWindow(app.get()));
   1187   EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent));
   1188 }
   1189 
   1190 namespace {
   1191 
   1192 // Used by DragMaximizedNonTrackedWindow to track how many times the window
   1193 // hierarchy changes affecting the specified window.
   1194 class DragMaximizedNonTrackedWindowObserver
   1195     : public aura::WindowObserver {
   1196  public:
   1197   DragMaximizedNonTrackedWindowObserver(aura::Window* window)
   1198   : change_count_(0),
   1199     window_(window) {
   1200   }
   1201 
   1202   // Number of times OnWindowHierarchyChanged() has been received.
   1203   void clear_change_count() { change_count_ = 0; }
   1204   int change_count() const {
   1205     return change_count_;
   1206   }
   1207 
   1208   // aura::WindowObserver overrides:
   1209   // Counts number of times a window is reparented. Ignores reparenting into and
   1210   // from a docked container which is expected when a tab is dragged.
   1211   virtual void OnWindowHierarchyChanged(
   1212       const HierarchyChangeParams& params) OVERRIDE {
   1213     if (params.target != window_ ||
   1214         (params.old_parent->id() == kShellWindowId_DefaultContainer &&
   1215          params.new_parent->id() == kShellWindowId_DockedContainer) ||
   1216         (params.old_parent->id() == kShellWindowId_DockedContainer &&
   1217          params.new_parent->id() == kShellWindowId_DefaultContainer)) {
   1218       return;
   1219     }
   1220     change_count_++;
   1221   }
   1222 
   1223  private:
   1224   int change_count_;
   1225   aura::Window* window_;
   1226 
   1227   DISALLOW_COPY_AND_ASSIGN(DragMaximizedNonTrackedWindowObserver);
   1228 };
   1229 
   1230 }  // namespace
   1231 
   1232 // Verifies that a new maximized window becomes visible after its activation
   1233 // is requested, even though it does not become activated because a system
   1234 // modal window is active.
   1235 TEST_F(WorkspaceControllerTest, SwitchFromModal) {
   1236   scoped_ptr<Window> modal_window(CreateTestWindowUnparented());
   1237   modal_window->SetBounds(gfx::Rect(10, 11, 21, 22));
   1238   modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
   1239   ParentWindowInPrimaryRootWindow(modal_window.get());
   1240   modal_window->Show();
   1241   wm::ActivateWindow(modal_window.get());
   1242 
   1243   scoped_ptr<Window> maximized_window(CreateTestWindow());
   1244   maximized_window->SetProperty(
   1245       aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
   1246   maximized_window->Show();
   1247   wm::ActivateWindow(maximized_window.get());
   1248   EXPECT_TRUE(maximized_window->IsVisible());
   1249 }
   1250 
   1251 namespace {
   1252 
   1253 // Subclass of WorkspaceControllerTest that runs tests with docked windows
   1254 // enabled and disabled.
   1255 class WorkspaceControllerTestDragging
   1256     : public WorkspaceControllerTest,
   1257       public testing::WithParamInterface<bool> {
   1258  public:
   1259   WorkspaceControllerTestDragging() {}
   1260   virtual ~WorkspaceControllerTestDragging() {}
   1261 
   1262   // testing::Test:
   1263   virtual void SetUp() OVERRIDE {
   1264     WorkspaceControllerTest::SetUp();
   1265     if (docked_windows_enabled()) {
   1266       CommandLine::ForCurrentProcess()->AppendSwitch(
   1267           ash::switches::kAshEnableDockedWindows);
   1268     }
   1269   }
   1270 
   1271   bool docked_windows_enabled() const { return GetParam(); }
   1272 
   1273  private:
   1274   DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTestDragging);
   1275 };
   1276 
   1277 }  // namespace
   1278 
   1279 // Verifies that when dragging a window over the shelf overlap is detected
   1280 // during and after the drag.
   1281 TEST_P(WorkspaceControllerTestDragging, DragWindowOverlapShelf) {
   1282   aura::test::TestWindowDelegate delegate;
   1283   delegate.set_window_component(HTCAPTION);
   1284   scoped_ptr<Window> w1(
   1285       aura::test::CreateTestWindowWithDelegate(&delegate,
   1286                                                aura::client::WINDOW_TYPE_NORMAL,
   1287                                                gfx::Rect(5, 5, 100, 50),
   1288                                                NULL));
   1289   ParentWindowInPrimaryRootWindow(w1.get());
   1290 
   1291   ShelfLayoutManager* shelf = shelf_layout_manager();
   1292   shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
   1293 
   1294   // Drag near the shelf
   1295   aura::test::EventGenerator generator(
   1296       Shell::GetPrimaryRootWindow(), gfx::Point());
   1297   generator.MoveMouseTo(10, 10);
   1298   generator.PressLeftButton();
   1299   generator.MoveMouseTo(100, shelf->GetIdealBounds().y() - 70);
   1300 
   1301   // Shelf should not be in overlapped state.
   1302   EXPECT_FALSE(GetWindowOverlapsShelf());
   1303 
   1304   generator.MoveMouseTo(100, shelf->GetIdealBounds().y() - 20);
   1305 
   1306   // Shelf should detect overlap. Overlap state stays after mouse is released.
   1307   EXPECT_TRUE(GetWindowOverlapsShelf());
   1308   generator.ReleaseLeftButton();
   1309   EXPECT_TRUE(GetWindowOverlapsShelf());
   1310 }
   1311 
   1312 INSTANTIATE_TEST_CASE_P(DockedOrNot, WorkspaceControllerTestDragging,
   1313                         ::testing::Bool());
   1314 
   1315 }  // namespace internal
   1316 }  // namespace ash
   1317