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/system_modal_container_layout_manager.h" 6 7 #include "ash/root_window_controller.h" 8 #include "ash/session/session_state_delegate.h" 9 #include "ash/shell.h" 10 #include "ash/shell_window_ids.h" 11 #include "ash/test/ash_test_base.h" 12 #include "ash/wm/window_util.h" 13 #include "base/command_line.h" 14 #include "base/compiler_specific.h" 15 #include "base/run_loop.h" 16 #include "ui/aura/window.h" 17 #include "ui/aura/window_event_dispatcher.h" 18 #include "ui/compositor/layer.h" 19 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 20 #include "ui/compositor/test/layer_animator_test_controller.h" 21 #include "ui/events/test/event_generator.h" 22 #include "ui/gfx/screen.h" 23 #include "ui/keyboard/keyboard_controller.h" 24 #include "ui/keyboard/keyboard_controller_proxy.h" 25 #include "ui/keyboard/keyboard_switches.h" 26 #include "ui/keyboard/keyboard_util.h" 27 #include "ui/views/test/capture_tracking_view.h" 28 #include "ui/views/widget/widget.h" 29 #include "ui/views/widget/widget_delegate.h" 30 #include "ui/wm/core/window_util.h" 31 32 namespace ash { 33 namespace test { 34 35 namespace { 36 37 aura::Window* GetModalContainer() { 38 return Shell::GetPrimaryRootWindowController()->GetContainer( 39 ash::kShellWindowId_SystemModalContainer); 40 } 41 42 bool AllRootWindowsHaveModalBackgroundsForContainer(int container_id) { 43 std::vector<aura::Window*> containers = 44 Shell::GetContainersFromAllRootWindows(container_id, NULL); 45 bool has_modal_screen = !containers.empty(); 46 for (std::vector<aura::Window*>::iterator iter = containers.begin(); 47 iter != containers.end(); ++iter) { 48 has_modal_screen &= static_cast<SystemModalContainerLayoutManager*>( 49 (*iter)->layout_manager())->has_modal_background(); 50 } 51 return has_modal_screen; 52 } 53 54 bool AllRootWindowsHaveLockedModalBackgrounds() { 55 return AllRootWindowsHaveModalBackgroundsForContainer( 56 kShellWindowId_LockSystemModalContainer); 57 } 58 59 bool AllRootWindowsHaveModalBackgrounds() { 60 return AllRootWindowsHaveModalBackgroundsForContainer( 61 kShellWindowId_SystemModalContainer); 62 } 63 64 class TestWindow : public views::WidgetDelegateView { 65 public: 66 explicit TestWindow(bool modal) : modal_(modal) {} 67 virtual ~TestWindow() {} 68 69 // The window needs be closed from widget in order for 70 // aura::client::kModalKey property to be reset. 71 static void CloseTestWindow(aura::Window* window) { 72 views::Widget::GetWidgetForNativeWindow(window)->Close(); 73 } 74 75 // Overridden from views::View: 76 virtual gfx::Size GetPreferredSize() const OVERRIDE { 77 return gfx::Size(50, 50); 78 } 79 80 // Overridden from views::WidgetDelegate: 81 virtual views::View* GetContentsView() OVERRIDE { 82 return this; 83 } 84 virtual ui::ModalType GetModalType() const OVERRIDE { 85 return modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE; 86 } 87 88 private: 89 bool modal_; 90 91 DISALLOW_COPY_AND_ASSIGN(TestWindow); 92 }; 93 94 class EventTestWindow : public TestWindow { 95 public: 96 explicit EventTestWindow(bool modal) : TestWindow(modal), 97 mouse_presses_(0) {} 98 virtual ~EventTestWindow() {} 99 100 aura::Window* OpenTestWindowWithContext(aura::Window* context) { 101 views::Widget* widget = 102 views::Widget::CreateWindowWithContext(this, context); 103 widget->Show(); 104 return widget->GetNativeView(); 105 } 106 107 aura::Window* OpenTestWindowWithParent(aura::Window* parent) { 108 DCHECK(parent); 109 views::Widget* widget = 110 views::Widget::CreateWindowWithParent(this, parent); 111 widget->Show(); 112 return widget->GetNativeView(); 113 } 114 115 // Overridden from views::View: 116 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE { 117 mouse_presses_++; 118 return false; 119 } 120 121 int mouse_presses() const { return mouse_presses_; } 122 private: 123 int mouse_presses_; 124 125 DISALLOW_COPY_AND_ASSIGN(EventTestWindow); 126 }; 127 128 class TransientWindowObserver : public aura::WindowObserver { 129 public: 130 TransientWindowObserver() : destroyed_(false) {} 131 virtual ~TransientWindowObserver() {} 132 133 bool destroyed() const { return destroyed_; } 134 135 // Overridden from aura::WindowObserver: 136 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 137 destroyed_ = true; 138 } 139 140 private: 141 bool destroyed_; 142 143 DISALLOW_COPY_AND_ASSIGN(TransientWindowObserver); 144 }; 145 146 } // namespace 147 148 class SystemModalContainerLayoutManagerTest : public AshTestBase { 149 public: 150 virtual void SetUp() OVERRIDE { 151 // Allow a virtual keyboard (and initialize it per default). 152 CommandLine::ForCurrentProcess()->AppendSwitch( 153 keyboard::switches::kEnableVirtualKeyboard); 154 AshTestBase::SetUp(); 155 Shell::GetPrimaryRootWindowController()->ActivateKeyboard( 156 keyboard::KeyboardController::GetInstance()); 157 } 158 159 virtual void TearDown() OVERRIDE { 160 Shell::GetPrimaryRootWindowController()->DeactivateKeyboard( 161 keyboard::KeyboardController::GetInstance()); 162 AshTestBase::TearDown(); 163 } 164 165 aura::Window* OpenToplevelTestWindow(bool modal) { 166 views::Widget* widget = views::Widget::CreateWindowWithContext( 167 new TestWindow(modal), CurrentContext()); 168 widget->Show(); 169 return widget->GetNativeView(); 170 } 171 172 aura::Window* OpenTestWindowWithParent(aura::Window* parent, bool modal) { 173 views::Widget* widget = 174 views::Widget::CreateWindowWithParent(new TestWindow(modal), parent); 175 widget->Show(); 176 return widget->GetNativeView(); 177 } 178 179 // Show or hide the keyboard. 180 void ShowKeyboard(bool show) { 181 keyboard::KeyboardController* keyboard = 182 keyboard::KeyboardController::GetInstance(); 183 ASSERT_TRUE(keyboard); 184 if (show == keyboard->keyboard_visible()) 185 return; 186 187 if (show) { 188 keyboard->ShowKeyboard(true); 189 if (keyboard->proxy()->GetKeyboardWindow()->bounds().height() == 0) { 190 keyboard->proxy()->GetKeyboardWindow()->SetBounds( 191 keyboard::KeyboardBoundsFromWindowBounds( 192 keyboard->GetContainerWindow()->bounds(), 100)); 193 } 194 } else { 195 keyboard->HideKeyboard(keyboard::KeyboardController::HIDE_REASON_MANUAL); 196 } 197 198 DCHECK_EQ(show, keyboard->keyboard_visible()); 199 } 200 201 }; 202 203 TEST_F(SystemModalContainerLayoutManagerTest, NonModalTransient) { 204 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 205 aura::Window* transient = OpenTestWindowWithParent(parent.get(), false); 206 TransientWindowObserver destruction_observer; 207 transient->AddObserver(&destruction_observer); 208 209 EXPECT_EQ(parent.get(), ::wm::GetTransientParent(transient)); 210 EXPECT_EQ(parent->parent(), transient->parent()); 211 212 // The transient should be destroyed with its parent. 213 parent.reset(); 214 EXPECT_TRUE(destruction_observer.destroyed()); 215 } 216 217 TEST_F(SystemModalContainerLayoutManagerTest, ModalTransient) { 218 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 219 // parent should be active. 220 EXPECT_TRUE(wm::IsActiveWindow(parent.get())); 221 aura::Window* t1 = OpenTestWindowWithParent(parent.get(), true); 222 223 TransientWindowObserver do1; 224 t1->AddObserver(&do1); 225 226 EXPECT_EQ(parent.get(), ::wm::GetTransientParent(t1)); 227 EXPECT_EQ(GetModalContainer(), t1->parent()); 228 229 // t1 should now be active. 230 EXPECT_TRUE(wm::IsActiveWindow(t1)); 231 232 // Attempting to click the parent should result in no activation change. 233 ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get()); 234 e1.ClickLeftButton(); 235 EXPECT_TRUE(wm::IsActiveWindow(t1)); 236 237 // Now open another modal transient parented to the original modal transient. 238 aura::Window* t2 = OpenTestWindowWithParent(t1, true); 239 TransientWindowObserver do2; 240 t2->AddObserver(&do2); 241 242 EXPECT_TRUE(wm::IsActiveWindow(t2)); 243 244 EXPECT_EQ(t1, ::wm::GetTransientParent(t2)); 245 EXPECT_EQ(GetModalContainer(), t2->parent()); 246 247 // t2 should still be active, even after clicking on t1. 248 ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1); 249 e2.ClickLeftButton(); 250 EXPECT_TRUE(wm::IsActiveWindow(t2)); 251 252 // Both transients should be destroyed with parent. 253 parent.reset(); 254 EXPECT_TRUE(do1.destroyed()); 255 EXPECT_TRUE(do2.destroyed()); 256 } 257 258 TEST_F(SystemModalContainerLayoutManagerTest, ModalNonTransient) { 259 scoped_ptr<aura::Window> t1(OpenToplevelTestWindow(true)); 260 // parent should be active. 261 EXPECT_TRUE(wm::IsActiveWindow(t1.get())); 262 TransientWindowObserver do1; 263 t1->AddObserver(&do1); 264 265 EXPECT_EQ(NULL, ::wm::GetTransientParent(t1.get())); 266 EXPECT_EQ(GetModalContainer(), t1->parent()); 267 268 // t1 should now be active. 269 EXPECT_TRUE(wm::IsActiveWindow(t1.get())); 270 271 // Attempting to click the parent should result in no activation change. 272 ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), 273 Shell::GetPrimaryRootWindow()); 274 e1.ClickLeftButton(); 275 EXPECT_TRUE(wm::IsActiveWindow(t1.get())); 276 277 // Now open another modal transient parented to the original modal transient. 278 aura::Window* t2 = OpenTestWindowWithParent(t1.get(), true); 279 TransientWindowObserver do2; 280 t2->AddObserver(&do2); 281 282 EXPECT_TRUE(wm::IsActiveWindow(t2)); 283 284 EXPECT_EQ(t1, ::wm::GetTransientParent(t2)); 285 EXPECT_EQ(GetModalContainer(), t2->parent()); 286 287 // t2 should still be active, even after clicking on t1. 288 ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1.get()); 289 e2.ClickLeftButton(); 290 EXPECT_TRUE(wm::IsActiveWindow(t2)); 291 292 // Both transients should be destroyed with parent. 293 t1.reset(); 294 EXPECT_TRUE(do1.destroyed()); 295 EXPECT_TRUE(do2.destroyed()); 296 } 297 298 // Tests that we can activate an unrelated window after a modal window is closed 299 // for a window. 300 TEST_F(SystemModalContainerLayoutManagerTest, CanActivateAfterEndModalSession) { 301 scoped_ptr<aura::Window> unrelated(OpenToplevelTestWindow(false)); 302 unrelated->SetBounds(gfx::Rect(100, 100, 50, 50)); 303 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 304 // parent should be active. 305 EXPECT_TRUE(wm::IsActiveWindow(parent.get())); 306 307 scoped_ptr<aura::Window> transient( 308 OpenTestWindowWithParent(parent.get(), true)); 309 // t1 should now be active. 310 EXPECT_TRUE(wm::IsActiveWindow(transient.get())); 311 312 // Attempting to click the parent should result in no activation change. 313 ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get()); 314 e1.ClickLeftButton(); 315 EXPECT_TRUE(wm::IsActiveWindow(transient.get())); 316 317 // Now close the transient. 318 transient->Hide(); 319 TestWindow::CloseTestWindow(transient.release()); 320 321 base::RunLoop().RunUntilIdle(); 322 323 // parent should now be active again. 324 EXPECT_TRUE(wm::IsActiveWindow(parent.get())); 325 326 // Attempting to click unrelated should activate it. 327 ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), unrelated.get()); 328 e2.ClickLeftButton(); 329 EXPECT_TRUE(wm::IsActiveWindow(unrelated.get())); 330 } 331 332 TEST_F(SystemModalContainerLayoutManagerTest, EventFocusContainers) { 333 // Create a normal window and attempt to receive a click event. 334 EventTestWindow* main_delegate = new EventTestWindow(false); 335 scoped_ptr<aura::Window> main( 336 main_delegate->OpenTestWindowWithContext(CurrentContext())); 337 EXPECT_TRUE(wm::IsActiveWindow(main.get())); 338 ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), main.get()); 339 e1.ClickLeftButton(); 340 EXPECT_EQ(1, main_delegate->mouse_presses()); 341 342 // Create a modal window for the main window and verify that the main window 343 // no longer receives mouse events. 344 EventTestWindow* transient_delegate = new EventTestWindow(true); 345 aura::Window* transient = 346 transient_delegate->OpenTestWindowWithParent(main.get()); 347 EXPECT_TRUE(wm::IsActiveWindow(transient)); 348 e1.ClickLeftButton(); 349 EXPECT_EQ(1, transient_delegate->mouse_presses()); 350 351 for (int block_reason = FIRST_BLOCK_REASON; 352 block_reason < NUMBER_OF_BLOCK_REASONS; 353 ++block_reason) { 354 // Create a window in the lock screen container and ensure that it receives 355 // the mouse event instead of the modal window (crbug.com/110920). 356 BlockUserSession(static_cast<UserSessionBlockReason>(block_reason)); 357 EventTestWindow* lock_delegate = new EventTestWindow(false); 358 scoped_ptr<aura::Window> lock(lock_delegate->OpenTestWindowWithParent( 359 Shell::GetPrimaryRootWindowController()->GetContainer( 360 ash::kShellWindowId_LockScreenContainer))); 361 EXPECT_TRUE(wm::IsActiveWindow(lock.get())); 362 e1.ClickLeftButton(); 363 EXPECT_EQ(1, lock_delegate->mouse_presses()); 364 365 // Make sure that a modal container created by the lock screen can still 366 // receive mouse events. 367 EventTestWindow* lock_modal_delegate = new EventTestWindow(true); 368 aura::Window* lock_modal = 369 lock_modal_delegate->OpenTestWindowWithParent(lock.get()); 370 EXPECT_TRUE(wm::IsActiveWindow(lock_modal)); 371 e1.ClickLeftButton(); 372 // Verify that none of the other containers received any more mouse presses. 373 EXPECT_EQ(1, lock_modal_delegate->mouse_presses()); 374 EXPECT_EQ(1, lock_delegate->mouse_presses()); 375 EXPECT_EQ(1, main_delegate->mouse_presses()); 376 EXPECT_EQ(1, transient_delegate->mouse_presses()); 377 UnblockUserSession(); 378 } 379 } 380 381 // Makes sure we don't crash if a modal window is shown while the parent window 382 // is hidden. 383 TEST_F(SystemModalContainerLayoutManagerTest, ShowModalWhileHidden) { 384 // Hide the lock screen. 385 Shell::GetPrimaryRootWindowController() 386 ->GetContainer(kShellWindowId_SystemModalContainer) 387 ->layer() 388 ->SetOpacity(0); 389 390 // Create a modal window. 391 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 392 scoped_ptr<aura::Window> modal_window( 393 OpenTestWindowWithParent(parent.get(), true)); 394 parent->Show(); 395 modal_window->Show(); 396 } 397 398 // Verifies we generate a capture lost when showing a modal window. 399 TEST_F(SystemModalContainerLayoutManagerTest, ChangeCapture) { 400 views::Widget* widget = views::Widget::CreateWindowWithContext( 401 new TestWindow(false), CurrentContext()); 402 scoped_ptr<aura::Window> widget_window(widget->GetNativeView()); 403 views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView; 404 widget->GetContentsView()->AddChildView(view); 405 view->SetBoundsRect(widget->GetContentsView()->bounds()); 406 widget->Show(); 407 408 gfx::Point center(view->width() / 2, view->height() / 2); 409 views::View::ConvertPointToScreen(view, ¢er); 410 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), center); 411 generator.PressLeftButton(); 412 EXPECT_TRUE(view->got_press()); 413 scoped_ptr<aura::Window> modal_window( 414 OpenTestWindowWithParent(widget->GetNativeView(), true)); 415 modal_window->Show(); 416 EXPECT_TRUE(view->got_capture_lost()); 417 } 418 419 // Verifies that the window gets moved into the visible screen area upon screen 420 // resize. 421 TEST_F(SystemModalContainerLayoutManagerTest, KeepVisible) { 422 GetModalContainer()->SetBounds(gfx::Rect(0, 0, 1024, 768)); 423 scoped_ptr<aura::Window> main(OpenTestWindowWithParent(GetModalContainer(), 424 true)); 425 main->SetBounds(gfx::Rect(924, 668, 100, 100)); 426 // We set now the bounds of the root window to something new which will 427 // Then trigger the repos operation. 428 GetModalContainer()->SetBounds(gfx::Rect(0, 0, 800, 600)); 429 430 gfx::Rect bounds = main->bounds(); 431 EXPECT_EQ(bounds, gfx::Rect(700, 500, 100, 100)); 432 } 433 434 // Verifies that centered windows will remain centered after the visible screen 435 // area changed. 436 TEST_F(SystemModalContainerLayoutManagerTest, KeepCentered) { 437 GetModalContainer()->SetBounds(gfx::Rect(0, 0, 800, 600)); 438 scoped_ptr<aura::Window> main(OpenTestWindowWithParent(GetModalContainer(), 439 true)); 440 // Center the window. 441 main->SetBounds(gfx::Rect((800 - 512) / 2, (600 - 256) / 2, 512, 256)); 442 443 // We set now the bounds of the root window to something new which will 444 // Then trigger the reposition operation. 445 GetModalContainer()->SetBounds(gfx::Rect(0, 0, 1024, 768)); 446 447 // The window should still be centered. 448 gfx::Rect bounds = main->bounds(); 449 EXPECT_EQ(bounds.ToString(), gfx::Rect(256, 256, 512, 256).ToString()); 450 } 451 452 TEST_F(SystemModalContainerLayoutManagerTest, ShowNormalBackgroundOrLocked) { 453 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 454 scoped_ptr<aura::Window> modal_window( 455 OpenTestWindowWithParent(parent.get(), true)); 456 parent->Show(); 457 modal_window->Show(); 458 459 // Normal system modal window. Shows normal system modal background and not 460 // locked. 461 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 462 EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds()); 463 464 TestWindow::CloseTestWindow(modal_window.release()); 465 EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds()); 466 EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds()); 467 468 for (int block_reason = FIRST_BLOCK_REASON; 469 block_reason < NUMBER_OF_BLOCK_REASONS; 470 ++block_reason) { 471 // Normal system modal window while blocked. Shows blocked system modal 472 // background. 473 BlockUserSession(static_cast<UserSessionBlockReason>(block_reason)); 474 scoped_ptr<aura::Window> lock_parent(OpenTestWindowWithParent( 475 Shell::GetPrimaryRootWindowController()->GetContainer( 476 ash::kShellWindowId_LockScreenContainer), 477 false)); 478 scoped_ptr<aura::Window> lock_modal_window(OpenTestWindowWithParent( 479 lock_parent.get(), true)); 480 lock_parent->Show(); 481 lock_modal_window->Show(); 482 EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds()); 483 EXPECT_TRUE(AllRootWindowsHaveLockedModalBackgrounds()); 484 TestWindow::CloseTestWindow(lock_modal_window.release()); 485 486 // Normal system modal window while blocked, but it belongs to the normal 487 // window. Shouldn't show blocked system modal background, but normal. 488 scoped_ptr<aura::Window> modal_window( 489 OpenTestWindowWithParent(parent.get(), true)); 490 modal_window->Show(); 491 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 492 EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds()); 493 TestWindow::CloseTestWindow(modal_window.release()); 494 UnblockUserSession(); 495 // Here we should check the behavior of the locked system modal dialog when 496 // unlocked, but such case isn't handled very well right now. 497 // See crbug.com/157660 498 // TODO(mukai): add the test case when the bug is fixed. 499 } 500 } 501 502 TEST_F(SystemModalContainerLayoutManagerTest, MultiDisplays) { 503 if (!SupportsMultipleDisplays()) 504 return; 505 506 UpdateDisplay("500x500,500x500"); 507 508 scoped_ptr<aura::Window> normal(OpenToplevelTestWindow(false)); 509 normal->SetBounds(gfx::Rect(100, 100, 50, 50)); 510 511 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 512 EXPECT_EQ(2U, root_windows.size()); 513 aura::Window* container1 = Shell::GetContainer( 514 root_windows[0], ash::kShellWindowId_SystemModalContainer); 515 aura::Window* container2 = Shell::GetContainer( 516 root_windows[1], ash::kShellWindowId_SystemModalContainer); 517 518 scoped_ptr<aura::Window> modal1( 519 OpenTestWindowWithParent(container1, true)); 520 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 521 EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); 522 523 scoped_ptr<aura::Window> modal11( 524 OpenTestWindowWithParent(container1, true)); 525 EXPECT_TRUE(wm::IsActiveWindow(modal11.get())); 526 527 scoped_ptr<aura::Window> modal2( 528 OpenTestWindowWithParent(container2, true)); 529 EXPECT_TRUE(wm::IsActiveWindow(modal2.get())); 530 531 // Sanity check if they're on the correct containers. 532 EXPECT_EQ(container1, modal1->parent()); 533 EXPECT_EQ(container1, modal11->parent()); 534 EXPECT_EQ(container2, modal2->parent()); 535 536 TestWindow::CloseTestWindow(modal2.release()); 537 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 538 EXPECT_TRUE(wm::IsActiveWindow(modal11.get())); 539 540 TestWindow::CloseTestWindow(modal11.release()); 541 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 542 EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); 543 544 UpdateDisplay("500x500"); 545 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 546 EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); 547 548 UpdateDisplay("500x500,600x600"); 549 EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); 550 EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); 551 552 // No more modal screen. 553 modal1->Hide(); 554 TestWindow::CloseTestWindow(modal1.release()); 555 EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds()); 556 EXPECT_TRUE(wm::IsActiveWindow(normal.get())); 557 } 558 559 // Test that with the visible keyboard, an existing system modal dialog gets 560 // positioned into the visible area. 561 TEST_F(SystemModalContainerLayoutManagerTest, 562 SystemModalDialogGetPushedFromKeyboard) { 563 const gfx::Rect& container_bounds = GetModalContainer()->bounds(); 564 // Place the window at the bottom of the screen. 565 gfx::Size modal_size(100, 100); 566 gfx::Point modal_origin = gfx::Point( 567 (container_bounds.right() - modal_size.width()) / 2, // X centered 568 container_bounds.bottom() - modal_size.height()); // at bottom 569 gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size); 570 571 // Create a modal window. 572 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 573 scoped_ptr<aura::Window> modal_window( 574 OpenTestWindowWithParent(parent.get(), true)); 575 modal_window->SetBounds(modal_bounds); 576 parent->Show(); 577 modal_window->Show(); 578 579 EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString()); 580 581 // The keyboard gets shown and the dialog should get pushed. 582 ShowKeyboard(true); 583 EXPECT_NE(modal_bounds.ToString(), modal_window->bounds().ToString()); 584 EXPECT_GT(modal_bounds.y(), modal_window->bounds().y()); 585 EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString()); 586 EXPECT_EQ(modal_origin.x(), modal_window->bounds().x()); 587 588 // After the keyboard is gone, the window will remain where it was. 589 ShowKeyboard(false); 590 EXPECT_NE(modal_bounds.ToString(), modal_window->bounds().ToString()); 591 EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString()); 592 EXPECT_EQ(modal_origin.x(), modal_window->bounds().x()); 593 } 594 595 // Test that windows will not get cropped through the visible virtual keyboard - 596 // if centered. 597 TEST_F(SystemModalContainerLayoutManagerTest, 598 SystemModalDialogGetPushedButNotCroppedFromKeyboard) { 599 const gfx::Rect& container_bounds = GetModalContainer()->bounds(); 600 const gfx::Size screen_size = Shell::GetPrimaryRootWindow()->bounds().size(); 601 // Place the window at the bottom of the screen. 602 gfx::Size modal_size(100, screen_size.height() - 70); 603 gfx::Point modal_origin = gfx::Point( 604 (container_bounds.right() - modal_size.width()) / 2, // X centered 605 container_bounds.bottom() - modal_size.height()); // at bottom 606 gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size); 607 608 // Create a modal window. 609 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 610 scoped_ptr<aura::Window> modal_window( 611 OpenTestWindowWithParent(parent.get(), true)); 612 modal_window->SetBounds(modal_bounds); 613 parent->Show(); 614 modal_window->Show(); 615 616 EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString()); 617 618 // The keyboard gets shown and the dialog should get pushed up, but not get 619 // cropped (and aligned to the top). 620 ShowKeyboard(true); 621 EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString()); 622 EXPECT_EQ(modal_origin.x(), modal_window->bounds().x()); 623 EXPECT_EQ(0, modal_window->bounds().y()); 624 625 ShowKeyboard(false); 626 } 627 628 // Test that windows will not get cropped through the visible virtual keyboard - 629 // if not centered. 630 TEST_F(SystemModalContainerLayoutManagerTest, 631 SystemModalDialogGetPushedButNotCroppedFromKeyboardIfNotCentered) { 632 const gfx::Size screen_size = Shell::GetPrimaryRootWindow()->bounds().size(); 633 // Place the window at the bottom of the screen. 634 gfx::Size modal_size(100, screen_size.height() - 70); 635 gfx::Point modal_origin = gfx::Point(10, 20); 636 gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size); 637 638 // Create a modal window. 639 scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false)); 640 scoped_ptr<aura::Window> modal_window( 641 OpenTestWindowWithParent(parent.get(), true)); 642 modal_window->SetBounds(modal_bounds); 643 parent->Show(); 644 modal_window->Show(); 645 646 EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString()); 647 648 // The keyboard gets shown and the dialog should get pushed up, but not get 649 // cropped (and aligned to the top). 650 ShowKeyboard(true); 651 EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString()); 652 EXPECT_EQ(modal_origin.x(), modal_window->bounds().x()); 653 EXPECT_EQ(0, modal_window->bounds().y()); 654 655 ShowKeyboard(false); 656 } 657 658 } // namespace test 659 } // namespace ash 660