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/panels/panel_layout_manager.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/root_window_controller.h" 9 #include "ash/screen_util.h" 10 #include "ash/shelf/shelf.h" 11 #include "ash/shelf/shelf_button.h" 12 #include "ash/shelf/shelf_layout_manager.h" 13 #include "ash/shelf/shelf_model.h" 14 #include "ash/shelf/shelf_types.h" 15 #include "ash/shelf/shelf_util.h" 16 #include "ash/shelf/shelf_view.h" 17 #include "ash/shelf/shelf_widget.h" 18 #include "ash/shell.h" 19 #include "ash/shell_window_ids.h" 20 #include "ash/test/ash_test_base.h" 21 #include "ash/test/shelf_test_api.h" 22 #include "ash/test/shelf_view_test_api.h" 23 #include "ash/test/shell_test_api.h" 24 #include "ash/test/test_shelf_delegate.h" 25 #include "ash/wm/mru_window_tracker.h" 26 #include "ash/wm/window_state.h" 27 #include "ash/wm/window_util.h" 28 #include "base/basictypes.h" 29 #include "base/command_line.h" 30 #include "base/compiler_specific.h" 31 #include "base/i18n/rtl.h" 32 #include "base/run_loop.h" 33 #include "ui/aura/client/aura_constants.h" 34 #include "ui/aura/test/test_windows.h" 35 #include "ui/aura/window.h" 36 #include "ui/aura/window_event_dispatcher.h" 37 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/events/event_utils.h" 39 #include "ui/events/test/event_generator.h" 40 #include "ui/views/widget/widget.h" 41 42 namespace ash { 43 44 using aura::test::WindowIsAbove; 45 46 class PanelLayoutManagerTest : public test::AshTestBase { 47 public: 48 PanelLayoutManagerTest() {} 49 virtual ~PanelLayoutManagerTest() {} 50 51 virtual void SetUp() OVERRIDE { 52 test::AshTestBase::SetUp(); 53 ASSERT_TRUE(test::TestShelfDelegate::instance()); 54 55 shelf_view_test_.reset(new test::ShelfViewTestAPI( 56 GetShelfView(Shelf::ForPrimaryDisplay()))); 57 shelf_view_test_->SetAnimationDuration(1); 58 } 59 60 aura::Window* CreateNormalWindow(const gfx::Rect& bounds) { 61 return CreateTestWindowInShellWithBounds(bounds); 62 } 63 64 aura::Window* CreatePanelWindowWithDelegate(aura::WindowDelegate* delegate, 65 const gfx::Rect& bounds) { 66 aura::Window* window = CreateTestWindowInShellWithDelegateAndType( 67 delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds); 68 test::TestShelfDelegate* shelf_delegate = 69 test::TestShelfDelegate::instance(); 70 shelf_delegate->AddShelfItem(window); 71 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 72 return window; 73 } 74 75 aura::Window* CreatePanelWindow(const gfx::Rect& bounds) { 76 return CreatePanelWindowWithDelegate(NULL, bounds); 77 } 78 79 aura::Window* GetPanelContainer(aura::Window* panel) { 80 return Shell::GetContainer(panel->GetRootWindow(), 81 kShellWindowId_PanelContainer); 82 } 83 84 views::Widget* GetCalloutWidgetForPanel(aura::Window* panel) { 85 PanelLayoutManager* manager = 86 static_cast<PanelLayoutManager*>(GetPanelContainer(panel)-> 87 layout_manager()); 88 DCHECK(manager); 89 PanelLayoutManager::PanelList::iterator found = std::find( 90 manager->panel_windows_.begin(), manager->panel_windows_.end(), 91 panel); 92 DCHECK(found != manager->panel_windows_.end()); 93 DCHECK(found->callout_widget); 94 return reinterpret_cast<views::Widget*>(found->callout_widget); 95 } 96 97 void PanelInScreen(aura::Window* panel) { 98 gfx::Rect panel_bounds = panel->GetBoundsInRootWindow(); 99 gfx::Point root_point = gfx::Point(panel_bounds.x(), panel_bounds.y()); 100 gfx::Display display = ScreenUtil::FindDisplayContainingPoint(root_point); 101 102 gfx::Rect panel_bounds_in_screen = panel->GetBoundsInScreen(); 103 gfx::Point screen_bottom_right = gfx::Point( 104 panel_bounds_in_screen.right(), 105 panel_bounds_in_screen.bottom()); 106 gfx::Rect display_bounds = display.bounds(); 107 EXPECT_TRUE(screen_bottom_right.x() < display_bounds.width() && 108 screen_bottom_right.y() < display_bounds.height()); 109 } 110 111 void PanelsNotOverlapping(aura::Window* panel1, aura::Window* panel2) { 112 // Waits until all shelf view animations are done. 113 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 114 gfx::Rect window1_bounds = panel1->GetBoundsInRootWindow(); 115 gfx::Rect window2_bounds = panel2->GetBoundsInRootWindow(); 116 117 EXPECT_FALSE(window1_bounds.Intersects(window2_bounds)); 118 } 119 120 void IsPanelAboveLauncherIcon(const aura::Window* panel) { 121 // Waits until all shelf view animations are done. 122 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 123 124 Shelf* shelf = RootWindowController::ForShelf(panel)->shelf()->shelf(); 125 gfx::Rect icon_bounds = shelf->GetScreenBoundsOfItemIconForWindow(panel); 126 ASSERT_FALSE(icon_bounds.width() == 0 && icon_bounds.height() == 0); 127 128 gfx::Rect window_bounds = panel->GetBoundsInScreen(); 129 ASSERT_LT(icon_bounds.width(), window_bounds.width()); 130 ASSERT_LT(icon_bounds.height(), window_bounds.height()); 131 gfx::Rect shelf_bounds = shelf->shelf_widget()->GetWindowBoundsInScreen(); 132 ShelfAlignment alignment = GetAlignment(panel->GetRootWindow()); 133 134 if (IsHorizontal(alignment)) { 135 // The horizontal bounds of the panel window should contain the bounds of 136 // the shelf icon. 137 EXPECT_LE(window_bounds.x(), icon_bounds.x()); 138 EXPECT_GE(window_bounds.right(), icon_bounds.right()); 139 } else { 140 // The vertical bounds of the panel window should contain the bounds of 141 // the shelf icon. 142 EXPECT_LE(window_bounds.y(), icon_bounds.y()); 143 EXPECT_GE(window_bounds.bottom(), icon_bounds.bottom()); 144 } 145 146 switch (alignment) { 147 case SHELF_ALIGNMENT_BOTTOM: 148 EXPECT_EQ(shelf_bounds.y(), window_bounds.bottom()); 149 break; 150 case SHELF_ALIGNMENT_LEFT: 151 EXPECT_EQ(shelf_bounds.right(), window_bounds.x()); 152 break; 153 case SHELF_ALIGNMENT_RIGHT: 154 EXPECT_EQ(shelf_bounds.x(), window_bounds.right()); 155 break; 156 case SHELF_ALIGNMENT_TOP: 157 EXPECT_EQ(shelf_bounds.bottom(), window_bounds.y()); 158 break; 159 } 160 } 161 162 void IsCalloutAboveLauncherIcon(aura::Window* panel) { 163 // Flush the message loop, since callout updates use a delayed task. 164 base::RunLoop().RunUntilIdle(); 165 views::Widget* widget = GetCalloutWidgetForPanel(panel); 166 167 Shelf* shelf = RootWindowController::ForShelf(panel)->shelf()->shelf(); 168 gfx::Rect icon_bounds = shelf->GetScreenBoundsOfItemIconForWindow(panel); 169 ASSERT_FALSE(icon_bounds.IsEmpty()); 170 171 gfx::Rect panel_bounds = panel->GetBoundsInScreen(); 172 gfx::Rect callout_bounds = widget->GetWindowBoundsInScreen(); 173 ASSERT_FALSE(icon_bounds.IsEmpty()); 174 175 EXPECT_TRUE(widget->IsVisible()); 176 177 ShelfAlignment alignment = GetAlignment(panel->GetRootWindow()); 178 switch (alignment) { 179 case SHELF_ALIGNMENT_BOTTOM: 180 EXPECT_EQ(panel_bounds.bottom(), callout_bounds.y()); 181 break; 182 case SHELF_ALIGNMENT_LEFT: 183 EXPECT_EQ(panel_bounds.x(), callout_bounds.right()); 184 break; 185 case SHELF_ALIGNMENT_RIGHT: 186 EXPECT_EQ(panel_bounds.right(), callout_bounds.x()); 187 break; 188 case SHELF_ALIGNMENT_TOP: 189 EXPECT_EQ(panel_bounds.y(), callout_bounds.bottom()); 190 break; 191 } 192 193 if (IsHorizontal(alignment)) { 194 EXPECT_NEAR(icon_bounds.CenterPoint().x(), 195 widget->GetWindowBoundsInScreen().CenterPoint().x(), 196 1); 197 } else { 198 EXPECT_NEAR(icon_bounds.CenterPoint().y(), 199 widget->GetWindowBoundsInScreen().CenterPoint().y(), 200 1); 201 } 202 } 203 204 bool IsPanelCalloutVisible(aura::Window* panel) { 205 views::Widget* widget = GetCalloutWidgetForPanel(panel); 206 return widget->IsVisible(); 207 } 208 209 test::ShelfViewTestAPI* shelf_view_test() { 210 return shelf_view_test_.get(); 211 } 212 213 // Clicks the shelf items on |shelf_view| that is associated with given 214 // |window|. 215 void ClickShelfItemForWindow(ShelfView* shelf_view, aura::Window* window) { 216 test::ShelfViewTestAPI test_api(shelf_view); 217 test_api.SetAnimationDuration(1); 218 test_api.RunMessageLoopUntilAnimationsDone(); 219 ShelfModel* model = test::ShellTestApi(Shell::GetInstance()).shelf_model(); 220 int index = model->ItemIndexByID(GetShelfIDForWindow(window)); 221 gfx::Rect bounds = test_api.GetButton(index)->GetBoundsInScreen(); 222 223 ui::test::EventGenerator& event_generator = GetEventGenerator(); 224 event_generator.MoveMouseTo(bounds.CenterPoint()); 225 event_generator.ClickLeftButton(); 226 227 test_api.RunMessageLoopUntilAnimationsDone(); 228 } 229 230 void SetAlignment(aura::Window* root_window, ShelfAlignment alignment) { 231 ash::Shell* shell = ash::Shell::GetInstance(); 232 shell->SetShelfAlignment(alignment, root_window); 233 } 234 235 ShelfAlignment GetAlignment(const aura::Window* root_window) { 236 ash::Shell* shell = ash::Shell::GetInstance(); 237 return shell->GetShelfAlignment(root_window); 238 } 239 240 void SetShelfAutoHideBehavior(aura::Window* window, 241 ShelfAutoHideBehavior behavior) { 242 ShelfLayoutManager* shelf = RootWindowController::ForWindow(window) 243 ->shelf() 244 ->shelf_layout_manager(); 245 shelf->SetAutoHideBehavior(behavior); 246 ShelfView* shelf_view = GetShelfView(Shelf::ForWindow(window)); 247 test::ShelfViewTestAPI test_api(shelf_view); 248 test_api.RunMessageLoopUntilAnimationsDone(); 249 } 250 251 void SetShelfVisibilityState(aura::Window* window, 252 ShelfVisibilityState visibility_state) { 253 ShelfLayoutManager* shelf = RootWindowController::ForWindow(window) 254 ->shelf() 255 ->shelf_layout_manager(); 256 shelf->SetState(visibility_state); 257 } 258 259 ShelfView* GetShelfView(Shelf* shelf) { 260 return test::ShelfTestAPI(shelf).shelf_view(); 261 } 262 263 private: 264 scoped_ptr<test::ShelfViewTestAPI> shelf_view_test_; 265 266 bool IsHorizontal(ShelfAlignment alignment) { 267 return alignment == SHELF_ALIGNMENT_BOTTOM || 268 alignment == SHELF_ALIGNMENT_TOP; 269 } 270 271 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTest); 272 }; 273 274 class PanelLayoutManagerTextDirectionTest 275 : public PanelLayoutManagerTest, 276 public testing::WithParamInterface<bool> { 277 public: 278 PanelLayoutManagerTextDirectionTest() : is_rtl_(GetParam()) {} 279 virtual ~PanelLayoutManagerTextDirectionTest() {} 280 281 virtual void SetUp() OVERRIDE { 282 original_locale = l10n_util::GetApplicationLocale(std::string()); 283 if (is_rtl_) 284 base::i18n::SetICUDefaultLocale("he"); 285 PanelLayoutManagerTest::SetUp(); 286 ASSERT_EQ(is_rtl_, base::i18n::IsRTL()); 287 } 288 289 virtual void TearDown() OVERRIDE { 290 if (is_rtl_) 291 base::i18n::SetICUDefaultLocale(original_locale); 292 PanelLayoutManagerTest::TearDown(); 293 } 294 295 private: 296 bool is_rtl_; 297 std::string original_locale; 298 299 DISALLOW_COPY_AND_ASSIGN(PanelLayoutManagerTextDirectionTest); 300 }; 301 302 // Tests that a created panel window is above the shelf icon in LTR and RTL. 303 TEST_P(PanelLayoutManagerTextDirectionTest, AddOnePanel) { 304 gfx::Rect bounds(0, 0, 201, 201); 305 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 306 EXPECT_EQ(GetPanelContainer(window.get()), window->parent()); 307 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get())); 308 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(window.get())); 309 } 310 311 // Tests that a created panel window is successfully aligned over a hidden 312 // shelf icon. 313 TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIcon) { 314 gfx::Rect bounds(0, 0, 201, 201); 315 SetShelfAutoHideBehavior(Shell::GetPrimaryRootWindow(), 316 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 317 scoped_ptr<aura::Window> normal_window(CreateNormalWindow(bounds)); 318 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 319 EXPECT_EQ(GetPanelContainer(window.get()), window->parent()); 320 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(window.get())); 321 } 322 323 TEST_F(PanelLayoutManagerTest, PanelAlignsToHiddenLauncherIconSecondDisplay) { 324 if (!SupportsMultipleDisplays()) 325 return; 326 327 // Keep the displays wide so that shelves have enough space for shelves 328 // buttons. 329 UpdateDisplay("400x400,600x400"); 330 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 331 332 scoped_ptr<aura::Window> normal_window( 333 CreateNormalWindow(gfx::Rect(450, 0, 100, 100))); 334 scoped_ptr<aura::Window> panel(CreatePanelWindow(gfx::Rect(400, 0, 50, 50))); 335 EXPECT_EQ(root_windows[1], panel->GetRootWindow()); 336 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get())); 337 gfx::Rect shelf_visible_position = panel->GetBoundsInScreen(); 338 339 SetShelfAutoHideBehavior(root_windows[1], 340 SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 341 // Expect the panel X position to remain the same after the shelf is hidden 342 // but the Y to move down. 343 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(panel.get())); 344 EXPECT_EQ(shelf_visible_position.x(), panel->GetBoundsInScreen().x()); 345 EXPECT_GT(panel->GetBoundsInScreen().y(), shelf_visible_position.y()); 346 } 347 348 // Tests interactions between multiple panels 349 TEST_F(PanelLayoutManagerTest, MultiplePanelsAreAboveIcons) { 350 gfx::Rect odd_bounds(0, 0, 201, 201); 351 gfx::Rect even_bounds(0, 0, 200, 200); 352 353 scoped_ptr<aura::Window> w1(CreatePanelWindow(odd_bounds)); 354 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 355 356 scoped_ptr<aura::Window> w2(CreatePanelWindow(even_bounds)); 357 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 358 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 359 360 scoped_ptr<aura::Window> w3(CreatePanelWindow(odd_bounds)); 361 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 362 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 363 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 364 } 365 366 TEST_F(PanelLayoutManagerTest, MultiplePanelStacking) { 367 gfx::Rect bounds(0, 0, 201, 201); 368 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 369 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 370 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 371 372 // Default stacking order. 373 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 374 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 375 376 // Changing the active window should update the stacking order. 377 wm::ActivateWindow(w1.get()); 378 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 379 EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get())); 380 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 381 382 wm::ActivateWindow(w2.get()); 383 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 384 EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get())); 385 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 386 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 387 388 wm::ActivateWindow(w3.get()); 389 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 390 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 391 } 392 393 TEST_F(PanelLayoutManagerTest, MultiplePanelStackingVertical) { 394 // Set shelf to be aligned on the right. 395 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT); 396 397 // Size panels in such a way that ordering them by X coordinate would cause 398 // stacking order to be incorrect. Test that stacking order is based on Y. 399 scoped_ptr<aura::Window> w1(CreatePanelWindow(gfx::Rect(0, 0, 210, 201))); 400 scoped_ptr<aura::Window> w2(CreatePanelWindow(gfx::Rect(0, 0, 220, 201))); 401 scoped_ptr<aura::Window> w3(CreatePanelWindow(gfx::Rect(0, 0, 200, 201))); 402 403 // Default stacking order. 404 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 405 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 406 407 // Changing the active window should update the stacking order. 408 wm::ActivateWindow(w1.get()); 409 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 410 EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get())); 411 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 412 413 wm::ActivateWindow(w2.get()); 414 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 415 EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get())); 416 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 417 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 418 419 wm::ActivateWindow(w3.get()); 420 EXPECT_TRUE(WindowIsAbove(w3.get(), w2.get())); 421 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 422 } 423 424 TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) { 425 gfx::Rect bounds(0, 0, 200, 200); 426 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 427 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 428 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 429 scoped_ptr<aura::Window> w4(CreateNormalWindow(gfx::Rect())); 430 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 431 EXPECT_TRUE(IsPanelCalloutVisible(w1.get())); 432 EXPECT_TRUE(IsPanelCalloutVisible(w2.get())); 433 EXPECT_TRUE(IsPanelCalloutVisible(w3.get())); 434 wm::ActivateWindow(w1.get()); 435 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w1.get())); 436 wm::ActivateWindow(w2.get()); 437 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); 438 wm::ActivateWindow(w3.get()); 439 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); 440 wm::ActivateWindow(w4.get()); 441 wm::ActivateWindow(w3.get()); 442 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); 443 w3.reset(); 444 EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); 445 } 446 447 // Tests removing panels. 448 TEST_F(PanelLayoutManagerTest, RemoveLeftPanel) { 449 gfx::Rect bounds(0, 0, 201, 201); 450 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 451 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 452 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 453 454 // At this point, windows should be stacked with 1 < 2 < 3 455 wm::ActivateWindow(w1.get()); 456 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 457 // Now, windows should be stacked 1 > 2 > 3 458 w1.reset(); 459 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 460 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 461 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 462 } 463 464 TEST_F(PanelLayoutManagerTest, RemoveMiddlePanel) { 465 gfx::Rect bounds(0, 0, 201, 201); 466 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 467 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 468 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 469 470 // At this point, windows should be stacked with 1 < 2 < 3 471 wm::ActivateWindow(w2.get()); 472 // Windows should be stacked 1 < 2 > 3 473 w2.reset(); 474 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 475 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 476 EXPECT_TRUE(WindowIsAbove(w3.get(), w1.get())); 477 } 478 479 TEST_F(PanelLayoutManagerTest, RemoveRightPanel) { 480 gfx::Rect bounds(0, 0, 201, 201); 481 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 482 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 483 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 484 485 // At this point, windows should be stacked with 1 < 2 < 3 486 wm::ActivateWindow(w3.get()); 487 // Order shouldn't change. 488 w3.reset(); 489 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w1.get())); 490 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 491 EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get())); 492 } 493 494 TEST_F(PanelLayoutManagerTest, RemoveNonActivePanel) { 495 gfx::Rect bounds(0, 0, 201, 201); 496 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 497 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 498 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 499 500 // At this point, windows should be stacked with 1 < 2 < 3 501 wm::ActivateWindow(w2.get()); 502 // Windows should be stacked 1 < 2 > 3 503 w1.reset(); 504 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w2.get())); 505 EXPECT_NO_FATAL_FAILURE(IsPanelAboveLauncherIcon(w3.get())); 506 EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get())); 507 } 508 509 TEST_F(PanelLayoutManagerTest, SplitView) { 510 gfx::Rect bounds(0, 0, 90, 201); 511 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 512 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 513 514 EXPECT_NO_FATAL_FAILURE(PanelsNotOverlapping(w1.get(), w2.get())); 515 } 516 517 #if defined(OS_WIN) 518 // RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962 519 #define MAYBE_SplitViewOverlapWhenLarge DISABLED_SplitViewOverlapWhenLarge 520 #else 521 #define MAYBE_SplitViewOverlapWhenLarge SplitViewOverlapWhenLarge 522 #endif 523 524 TEST_F(PanelLayoutManagerTest, MAYBE_SplitViewOverlapWhenLarge) { 525 gfx::Rect bounds(0, 0, 600, 201); 526 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 527 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 528 529 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w1.get())); 530 EXPECT_NO_FATAL_FAILURE(PanelInScreen(w2.get())); 531 } 532 533 TEST_F(PanelLayoutManagerTest, FanWindows) { 534 gfx::Rect bounds(0, 0, 201, 201); 535 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 536 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 537 scoped_ptr<aura::Window> w3(CreatePanelWindow(bounds)); 538 539 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 540 int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x(); 541 int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x(); 542 int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x(); 543 Shelf* shelf = Shelf::ForPrimaryDisplay(); 544 int icon_x1 = shelf->GetScreenBoundsOfItemIconForWindow(w1.get()).x(); 545 int icon_x2 = shelf->GetScreenBoundsOfItemIconForWindow(w2.get()).x(); 546 EXPECT_EQ(window_x2 - window_x1, window_x3 - window_x2); 547 int spacing = window_x2 - window_x1; 548 EXPECT_GT(spacing, icon_x2 - icon_x1); 549 } 550 551 TEST_F(PanelLayoutManagerTest, FanLargeWindow) { 552 gfx::Rect small_bounds(0, 0, 201, 201); 553 gfx::Rect large_bounds(0, 0, 501, 201); 554 scoped_ptr<aura::Window> w1(CreatePanelWindow(small_bounds)); 555 scoped_ptr<aura::Window> w2(CreatePanelWindow(large_bounds)); 556 scoped_ptr<aura::Window> w3(CreatePanelWindow(small_bounds)); 557 558 shelf_view_test()->RunMessageLoopUntilAnimationsDone(); 559 int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x(); 560 int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x(); 561 int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x(); 562 // The distances may not be equidistant with a large panel but the panels 563 // should be in the correct order with respect to their midpoints. 564 EXPECT_GT(window_x2, window_x1); 565 EXPECT_GT(window_x3, window_x2); 566 } 567 568 TEST_F(PanelLayoutManagerTest, MinimizeRestorePanel) { 569 gfx::Rect bounds(0, 0, 201, 201); 570 scoped_ptr<aura::Window> window(CreatePanelWindow(bounds)); 571 // Activate the window, ensure callout is visible. 572 wm::ActivateWindow(window.get()); 573 RunAllPendingInMessageLoop(); 574 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 575 // Minimize the panel, callout should be hidden. 576 wm::GetWindowState(window.get())->Minimize(); 577 RunAllPendingInMessageLoop(); 578 EXPECT_FALSE(IsPanelCalloutVisible(window.get())); 579 // Restore the panel; panel should not be activated by default but callout 580 // should be visible. 581 wm::GetWindowState(window.get())->Unminimize(); 582 RunAllPendingInMessageLoop(); 583 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 584 // Activate the window, ensure callout is visible. 585 wm::ActivateWindow(window.get()); 586 RunAllPendingInMessageLoop(); 587 EXPECT_TRUE(IsPanelCalloutVisible(window.get())); 588 } 589 590 TEST_F(PanelLayoutManagerTest, PanelMoveBetweenMultipleDisplays) { 591 if (!SupportsMultipleDisplays()) 592 return; 593 594 // Keep the displays wide so that shelves have enough space for launcher 595 // buttons. 596 UpdateDisplay("600x400,600x400"); 597 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 598 599 scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 600 scoped_ptr<aura::Window> p2_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 601 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 602 scoped_ptr<aura::Window> p2_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 603 604 ShelfView* shelf_view_1st = GetShelfView(Shelf::ForPrimaryDisplay()); 605 ShelfView* shelf_view_2nd = 606 GetShelfView(Shelf::ForWindow(root_windows[1])); 607 608 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 609 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 610 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 611 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 612 613 EXPECT_EQ(kShellWindowId_PanelContainer, p1_d1->parent()->id()); 614 EXPECT_EQ(kShellWindowId_PanelContainer, p2_d1->parent()->id()); 615 EXPECT_EQ(kShellWindowId_PanelContainer, p1_d2->parent()->id()); 616 EXPECT_EQ(kShellWindowId_PanelContainer, p2_d2->parent()->id()); 617 618 // Test a panel on 1st display. 619 // Clicking on the same display has no effect. 620 ClickShelfItemForWindow(shelf_view_1st, p1_d1.get()); 621 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 622 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 623 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 624 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 625 EXPECT_FALSE(root_windows[1]->GetBoundsInScreen().Contains( 626 p1_d1->GetBoundsInScreen())); 627 628 // Test if clicking on another display moves the panel to 629 // that display. 630 ClickShelfItemForWindow(shelf_view_2nd, p1_d1.get()); 631 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 632 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 633 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 634 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 635 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains( 636 p1_d1->GetBoundsInScreen())); 637 638 // Test a panel on 2nd display. 639 // Clicking on the same display has no effect. 640 ClickShelfItemForWindow(shelf_view_2nd, p1_d2.get()); 641 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 642 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 643 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 644 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 645 EXPECT_TRUE(root_windows[1]->GetBoundsInScreen().Contains( 646 p1_d2->GetBoundsInScreen())); 647 648 // Test if clicking on another display moves the panel to 649 // that display. 650 ClickShelfItemForWindow(shelf_view_1st, p1_d2.get()); 651 EXPECT_EQ(root_windows[1], p1_d1->GetRootWindow()); 652 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 653 EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow()); 654 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 655 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains( 656 p1_d2->GetBoundsInScreen())); 657 658 // Test if clicking on a previously moved window moves the 659 // panel back to the original display. 660 ClickShelfItemForWindow(shelf_view_1st, p1_d1.get()); 661 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 662 EXPECT_EQ(root_windows[0], p2_d1->GetRootWindow()); 663 EXPECT_EQ(root_windows[0], p1_d2->GetRootWindow()); 664 EXPECT_EQ(root_windows[1], p2_d2->GetRootWindow()); 665 EXPECT_TRUE(root_windows[0]->GetBoundsInScreen().Contains( 666 p1_d1->GetBoundsInScreen())); 667 } 668 669 TEST_F(PanelLayoutManagerTest, PanelAttachPositionMultipleDisplays) { 670 if (!SupportsMultipleDisplays()) 671 return; 672 673 // Keep the displays wide so that shelves have enough space for shelf buttons. 674 // Use differently sized displays so the shelf is in a different 675 // position on second display. 676 UpdateDisplay("600x400,600x600"); 677 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 678 679 scoped_ptr<aura::Window> p1_d1(CreatePanelWindow(gfx::Rect(0, 0, 50, 50))); 680 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 681 682 EXPECT_EQ(root_windows[0], p1_d1->GetRootWindow()); 683 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 684 685 IsPanelAboveLauncherIcon(p1_d1.get()); 686 IsCalloutAboveLauncherIcon(p1_d1.get()); 687 IsPanelAboveLauncherIcon(p1_d2.get()); 688 IsCalloutAboveLauncherIcon(p1_d2.get()); 689 } 690 691 TEST_F(PanelLayoutManagerTest, PanelAlignmentSecondDisplay) { 692 if (!SupportsMultipleDisplays()) 693 return; 694 695 UpdateDisplay("600x400,600x400"); 696 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 697 698 scoped_ptr<aura::Window> p1_d2(CreatePanelWindow(gfx::Rect(600, 0, 50, 50))); 699 EXPECT_EQ(root_windows[1], p1_d2->GetRootWindow()); 700 701 IsPanelAboveLauncherIcon(p1_d2.get()); 702 IsCalloutAboveLauncherIcon(p1_d2.get()); 703 704 SetAlignment(root_windows[1], SHELF_ALIGNMENT_RIGHT); 705 IsPanelAboveLauncherIcon(p1_d2.get()); 706 IsCalloutAboveLauncherIcon(p1_d2.get()); 707 SetAlignment(root_windows[1], SHELF_ALIGNMENT_LEFT); 708 IsPanelAboveLauncherIcon(p1_d2.get()); 709 IsCalloutAboveLauncherIcon(p1_d2.get()); 710 SetAlignment(root_windows[1], SHELF_ALIGNMENT_TOP); 711 IsPanelAboveLauncherIcon(p1_d2.get()); 712 IsCalloutAboveLauncherIcon(p1_d2.get()); 713 } 714 715 TEST_F(PanelLayoutManagerTest, AlignmentLeft) { 716 gfx::Rect bounds(0, 0, 201, 201); 717 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 718 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT); 719 IsPanelAboveLauncherIcon(w.get()); 720 IsCalloutAboveLauncherIcon(w.get()); 721 } 722 723 TEST_F(PanelLayoutManagerTest, AlignmentRight) { 724 gfx::Rect bounds(0, 0, 201, 201); 725 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 726 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT); 727 IsPanelAboveLauncherIcon(w.get()); 728 IsCalloutAboveLauncherIcon(w.get()); 729 } 730 731 TEST_F(PanelLayoutManagerTest, AlignmentTop) { 732 gfx::Rect bounds(0, 0, 201, 201); 733 scoped_ptr<aura::Window> w(CreatePanelWindow(bounds)); 734 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP); 735 IsPanelAboveLauncherIcon(w.get()); 736 IsCalloutAboveLauncherIcon(w.get()); 737 } 738 739 // Tests that panels will hide and restore their state with the shelf visibility 740 // state. This ensures that entering full-screen mode will hide your panels 741 // until you leave it. 742 TEST_F(PanelLayoutManagerTest, PanelsHideAndRestoreWithShelf) { 743 gfx::Rect bounds(0, 0, 201, 201); 744 745 scoped_ptr<aura::Window> w1(CreatePanelWindow(bounds)); 746 scoped_ptr<aura::Window> w2(CreatePanelWindow(bounds)); 747 scoped_ptr<aura::Window> w3; 748 // Minimize w2. 749 wm::GetWindowState(w2.get())->Minimize(); 750 RunAllPendingInMessageLoop(); 751 EXPECT_TRUE(w1->IsVisible()); 752 EXPECT_FALSE(w2->IsVisible()); 753 754 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_HIDDEN); 755 RunAllPendingInMessageLoop(); 756 757 // w3 is created while in full-screen mode, should only become visible when 758 // we exit fullscreen mode. 759 w3.reset(CreatePanelWindow(bounds)); 760 761 EXPECT_FALSE(w1->IsVisible()); 762 EXPECT_FALSE(w2->IsVisible()); 763 EXPECT_FALSE(w3->IsVisible()); 764 765 // While in full-screen mode, the panel windows should still be in the 766 // switchable window list - http://crbug.com/313919. 767 MruWindowTracker::WindowList switchable_window_list = 768 Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList(); 769 EXPECT_EQ(3u, switchable_window_list.size()); 770 EXPECT_NE(switchable_window_list.end(), 771 std::find(switchable_window_list.begin(), switchable_window_list.end(), 772 w1.get())); 773 EXPECT_NE(switchable_window_list.end(), 774 std::find(switchable_window_list.begin(), switchable_window_list.end(), 775 w2.get())); 776 EXPECT_NE(switchable_window_list.end(), 777 std::find(switchable_window_list.begin(), switchable_window_list.end(), 778 w3.get())); 779 780 SetShelfVisibilityState(Shell::GetPrimaryRootWindow(), SHELF_VISIBLE); 781 RunAllPendingInMessageLoop(); 782 783 // Windows should be restored to their prior state. 784 EXPECT_TRUE(w1->IsVisible()); 785 EXPECT_FALSE(w2->IsVisible()); 786 EXPECT_TRUE(w3->IsVisible()); 787 } 788 789 // Verifies that touches along the attached edge of a panel do not 790 // target the panel itself. 791 TEST_F(PanelLayoutManagerTest, TouchHitTestPanel) { 792 aura::test::TestWindowDelegate delegate; 793 scoped_ptr<aura::Window> w( 794 CreatePanelWindowWithDelegate(&delegate, gfx::Rect(0, 0, 200, 200))); 795 ui::EventTarget* root = w->GetRootWindow(); 796 ui::EventTargeter* targeter = root->GetEventTargeter(); 797 798 // Note that the constants used in the touch locations below are 799 // arbitrarily-selected small numbers which will ensure the point is 800 // within the default extended region surrounding the panel. This value 801 // is calculated as 802 // kResizeOutsideBoundsSize * kResizeOutsideBoundsScaleForTouch 803 // in src/ash/root_window_controller.cc. 804 805 // Hit test outside the right edge with a bottom-aligned shelf. 806 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_BOTTOM); 807 gfx::Rect bounds(w->bounds()); 808 ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, 809 gfx::Point(bounds.right() + 3, bounds.y() + 2), 810 0, ui::EventTimeForNow()); 811 ui::EventTarget* target = targeter->FindTargetForEvent(root, &touch); 812 EXPECT_EQ(w.get(), target); 813 814 // Hit test outside the bottom edge with a bottom-aligned shelf. 815 touch.set_location(gfx::Point(bounds.x() + 6, bounds.bottom() + 5)); 816 target = targeter->FindTargetForEvent(root, &touch); 817 EXPECT_NE(w.get(), target); 818 819 // Hit test outside the bottom edge with a right-aligned shelf. 820 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_RIGHT); 821 bounds = w->bounds(); 822 touch.set_location(gfx::Point(bounds.x() + 6, bounds.bottom() + 5)); 823 target = targeter->FindTargetForEvent(root, &touch); 824 EXPECT_EQ(w.get(), target); 825 826 // Hit test outside the right edge with a right-aligned shelf. 827 touch.set_location(gfx::Point(bounds.right() + 3, bounds.y() + 2)); 828 target = targeter->FindTargetForEvent(root, &touch); 829 EXPECT_NE(w.get(), target); 830 831 // Hit test outside the top edge with a left-aligned shelf. 832 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_LEFT); 833 bounds = w->bounds(); 834 touch.set_location(gfx::Point(bounds.x() + 4, bounds.y() - 6)); 835 target = targeter->FindTargetForEvent(root, &touch); 836 EXPECT_EQ(w.get(), target); 837 838 // Hit test outside the left edge with a left-aligned shelf. 839 touch.set_location(gfx::Point(bounds.x() - 1, bounds.y() + 5)); 840 target = targeter->FindTargetForEvent(root, &touch); 841 EXPECT_NE(w.get(), target); 842 843 // Hit test outside the left edge with a top-aligned shelf. 844 SetAlignment(Shell::GetPrimaryRootWindow(), SHELF_ALIGNMENT_TOP); 845 bounds = w->bounds(); 846 touch.set_location(gfx::Point(bounds.x() - 1, bounds.y() + 5)); 847 target = targeter->FindTargetForEvent(root, &touch); 848 EXPECT_EQ(w.get(), target); 849 850 // Hit test outside the top edge with a top-aligned shelf. 851 touch.set_location(gfx::Point(bounds.x() + 4, bounds.y() - 6)); 852 target = targeter->FindTargetForEvent(root, &touch); 853 EXPECT_NE(w.get(), target); 854 } 855 856 INSTANTIATE_TEST_CASE_P(LtrRtl, PanelLayoutManagerTextDirectionTest, 857 testing::Bool()); 858 859 } // namespace ash 860