123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/wm/system_modal_container_layout_manager.h"
- #include <memory>
- #include "ash/keyboard/keyboard_controller_impl.h"
- #include "ash/keyboard/ui/keyboard_ui.h"
- #include "ash/keyboard/ui/keyboard_ui_controller.h"
- #include "ash/keyboard/ui/test/keyboard_test_util.h"
- #include "ash/public/cpp/keyboard/keyboard_switches.h"
- #include "ash/public/cpp/shelf_config.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/root_window_controller.h"
- #include "ash/shell.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/container_finder.h"
- #include "ash/wm/window_util.h"
- #include "base/command_line.h"
- #include "base/compiler_specific.h"
- #include "base/run_loop.h"
- #include "components/session_manager/session_manager_types.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/aura/test/test_window_delegate.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_event_dispatcher.h"
- #include "ui/base/hit_test.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/scoped_animation_duration_scale_mode.h"
- #include "ui/compositor/test/layer_animator_test_controller.h"
- #include "ui/events/test/event_generator.h"
- #include "ui/views/test/capture_tracking_view.h"
- #include "ui/views/widget/widget.h"
- #include "ui/views/widget/widget_delegate.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- aura::Window* GetModalContainer() {
- return Shell::GetPrimaryRootWindowController()->GetContainer(
- ash::kShellWindowId_SystemModalContainer);
- }
- bool AllRootWindowsHaveModalBackgroundsForContainer(int container_id) {
- aura::Window::Windows containers =
- GetContainersForAllRootWindows(container_id);
- bool has_modal_screen = !containers.empty();
- for (aura::Window* container : containers) {
- has_modal_screen &= static_cast<SystemModalContainerLayoutManager*>(
- container->layout_manager())
- ->has_window_dimmer();
- }
- return has_modal_screen;
- }
- bool AllRootWindowsHaveLockedModalBackgrounds() {
- return AllRootWindowsHaveModalBackgroundsForContainer(
- kShellWindowId_LockSystemModalContainer);
- }
- bool AllRootWindowsHaveModalBackgrounds() {
- return AllRootWindowsHaveModalBackgroundsForContainer(
- kShellWindowId_SystemModalContainer);
- }
- class TestWindow : public views::WidgetDelegateView {
- public:
- explicit TestWindow(bool modal) {
- SetModalType(modal ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE);
- SetPreferredSize(gfx::Size(50, 50));
- }
- TestWindow(const TestWindow&) = delete;
- TestWindow& operator=(const TestWindow&) = delete;
- ~TestWindow() override = default;
- // The window needs be closed from widget in order for
- // aura::client::kModalKey property to be reset.
- static void CloseTestWindow(aura::Window* window) {
- views::Widget::GetWidgetForNativeWindow(window)->Close();
- }
- };
- class EventTestWindow : public TestWindow {
- public:
- explicit EventTestWindow(bool modal) : TestWindow(modal), mouse_presses_(0) {}
- EventTestWindow(const EventTestWindow&) = delete;
- EventTestWindow& operator=(const EventTestWindow&) = delete;
- ~EventTestWindow() override = default;
- aura::Window* ShowTestWindowWithContext(aura::Window* context) {
- views::Widget* widget =
- views::Widget::CreateWindowWithContext(this, context);
- widget->Show();
- return widget->GetNativeView();
- }
- aura::Window* ShowTestWindowWithParent(aura::Window* parent) {
- DCHECK(parent);
- views::Widget* widget = views::Widget::CreateWindowWithParent(this, parent);
- widget->Show();
- return widget->GetNativeView();
- }
- // Overridden from views::View:
- bool OnMousePressed(const ui::MouseEvent& event) override {
- mouse_presses_++;
- return false;
- }
- int mouse_presses() const { return mouse_presses_; }
- private:
- int mouse_presses_;
- };
- class TransientWindowObserver : public aura::WindowObserver {
- public:
- TransientWindowObserver() : destroyed_(false) {}
- TransientWindowObserver(const TransientWindowObserver&) = delete;
- TransientWindowObserver& operator=(const TransientWindowObserver&) = delete;
- ~TransientWindowObserver() override = default;
- bool destroyed() const { return destroyed_; }
- // Overridden from aura::WindowObserver:
- void OnWindowDestroyed(aura::Window* window) override { destroyed_ = true; }
- private:
- bool destroyed_;
- };
- } // namespace
- class SystemModalContainerLayoutManagerTest : public AshTestBase {
- public:
- void SetUp() override {
- // Allow a virtual keyboard (and initialize it per default).
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- keyboard::switches::kEnableVirtualKeyboard);
- AshTestBase::SetUp();
- }
- aura::Window* ShowToplevelTestWindow(bool modal) {
- views::Widget* widget = views::Widget::CreateWindowWithContext(
- new TestWindow(modal), GetContext());
- widget->Show();
- return widget->GetNativeView();
- }
- aura::Window* ShowTestWindowWithParent(aura::Window* parent, bool modal) {
- views::Widget* widget =
- views::Widget::CreateWindowWithParent(new TestWindow(modal), parent);
- widget->Show();
- return widget->GetNativeView();
- }
- // Show or hide the keyboard.
- void ShowKeyboard(bool show) {
- auto* keyboard = keyboard::KeyboardUIController::Get();
- ASSERT_TRUE(keyboard->IsEnabled());
- if (show == keyboard->IsKeyboardVisible())
- return;
- if (show) {
- keyboard->ShowKeyboard(true /* lock */);
- ASSERT_TRUE(keyboard::WaitUntilShown());
- } else {
- keyboard->HideKeyboardByUser();
- }
- DCHECK_EQ(show, keyboard->IsKeyboardVisible());
- }
- };
- TEST_F(SystemModalContainerLayoutManagerTest, NonModalTransient) {
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- aura::Window* transient = ShowTestWindowWithParent(parent.get(), false);
- TransientWindowObserver destruction_observer;
- transient->AddObserver(&destruction_observer);
- EXPECT_EQ(parent.get(), ::wm::GetTransientParent(transient));
- EXPECT_EQ(parent->parent(), transient->parent());
- // The transient should be destroyed with its parent.
- parent.reset();
- EXPECT_TRUE(destruction_observer.destroyed());
- }
- TEST_F(SystemModalContainerLayoutManagerTest, ModalTransient) {
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- // parent should be active.
- EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
- aura::Window* t1 = ShowTestWindowWithParent(parent.get(), true);
- TransientWindowObserver do1;
- t1->AddObserver(&do1);
- EXPECT_EQ(parent.get(), ::wm::GetTransientParent(t1));
- EXPECT_EQ(GetModalContainer(), t1->parent());
- // t1 should now be active.
- EXPECT_TRUE(wm::IsActiveWindow(t1));
- // Attempting to click the parent should result in no activation change.
- ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get());
- e1.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(t1));
- // Now open another modal transient parented to the original modal transient.
- aura::Window* t2 = ShowTestWindowWithParent(t1, true);
- TransientWindowObserver do2;
- t2->AddObserver(&do2);
- EXPECT_TRUE(wm::IsActiveWindow(t2));
- EXPECT_EQ(t1, ::wm::GetTransientParent(t2));
- EXPECT_EQ(GetModalContainer(), t2->parent());
- // t2 should still be active, even after clicking on t1.
- ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1);
- e2.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(t2));
- // Both transients should be destroyed with parent.
- parent.reset();
- EXPECT_TRUE(do1.destroyed());
- EXPECT_TRUE(do2.destroyed());
- }
- TEST_F(SystemModalContainerLayoutManagerTest, ModalNonTransient) {
- std::unique_ptr<aura::Window> t1(ShowToplevelTestWindow(true));
- // parent should be active.
- EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
- TransientWindowObserver do1;
- t1->AddObserver(&do1);
- EXPECT_EQ(NULL, ::wm::GetTransientParent(t1.get()));
- EXPECT_EQ(GetModalContainer(), t1->parent());
- // t1 should now be active.
- EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
- // Attempting to click the parent should result in no activation change.
- ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(),
- Shell::GetPrimaryRootWindow());
- e1.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
- // Now open another modal transient parented to the original modal transient.
- aura::Window* t2 = ShowTestWindowWithParent(t1.get(), true);
- TransientWindowObserver do2;
- t2->AddObserver(&do2);
- EXPECT_TRUE(wm::IsActiveWindow(t2));
- EXPECT_EQ(t1.get(), ::wm::GetTransientParent(t2));
- EXPECT_EQ(GetModalContainer(), t2->parent());
- // t2 should still be active, even after clicking on t1.
- ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1.get());
- e2.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(t2));
- // Both transients should be destroyed with parent.
- t1.reset();
- EXPECT_TRUE(do1.destroyed());
- EXPECT_TRUE(do2.destroyed());
- }
- // Tests that we can activate an unrelated window after a modal window is closed
- // for a window.
- TEST_F(SystemModalContainerLayoutManagerTest, CanActivateAfterEndModalSession) {
- std::unique_ptr<aura::Window> unrelated(ShowToplevelTestWindow(false));
- unrelated->SetBounds(gfx::Rect(100, 100, 50, 50));
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- // parent should be active.
- EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
- std::unique_ptr<aura::Window> transient(
- ShowTestWindowWithParent(parent.get(), true));
- // t1 should now be active.
- EXPECT_TRUE(wm::IsActiveWindow(transient.get()));
- // Attempting to click the parent should result in no activation change.
- ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get());
- e1.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(transient.get()));
- // Now close the transient.
- transient->Hide();
- TestWindow::CloseTestWindow(transient.release());
- base::RunLoop().RunUntilIdle();
- // parent should now be active again.
- EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
- // Attempting to click unrelated should activate it.
- ui::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), unrelated.get());
- e2.ClickLeftButton();
- EXPECT_TRUE(wm::IsActiveWindow(unrelated.get()));
- }
- TEST_F(SystemModalContainerLayoutManagerTest, EventFocusContainers) {
- // Create a normal window and attempt to receive a click event.
- EventTestWindow* main_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> main(
- main_delegate->ShowTestWindowWithContext(GetContext()));
- EXPECT_TRUE(wm::IsActiveWindow(main.get()));
- ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), main.get());
- e1.ClickLeftButton();
- EXPECT_EQ(1, main_delegate->mouse_presses());
- EventTestWindow* status_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> status_control(
- status_delegate->ShowTestWindowWithParent(
- Shell::GetPrimaryRootWindowController()->GetContainer(
- kShellWindowId_ShelfContainer)));
- status_control->SetBounds(main->bounds());
- // Make sure that status window can receive event.
- e1.ClickLeftButton();
- EXPECT_EQ(1, status_delegate->mouse_presses());
- // Create a modal window for the main window and verify that the main window
- // no longer receives mouse events.
- EventTestWindow* transient_delegate = new EventTestWindow(true);
- aura::Window* transient =
- transient_delegate->ShowTestWindowWithParent(main.get());
- EXPECT_TRUE(wm::IsActiveWindow(transient));
- e1.ClickLeftButton();
- EXPECT_EQ(0, transient_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- status_control->Hide();
- e1.ClickLeftButton();
- EXPECT_EQ(1, transient_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- for (int block_reason = FIRST_BLOCK_REASON;
- block_reason < NUMBER_OF_BLOCK_REASONS; ++block_reason) {
- // Create a window in the lock screen container and ensure that it receives
- // the mouse event instead of the modal window (crbug.com/110920).
- BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
- EventTestWindow* lock_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> lock(lock_delegate->ShowTestWindowWithParent(
- Shell::GetPrimaryRootWindowController()->GetContainer(
- kShellWindowId_LockScreenContainer)));
- // BlockUserSession could change the workspace size. Make sure |lock| has
- // the same bounds as |main| so that |lock| gets the generated mouse events.
- lock->SetBounds(main->bounds());
- EXPECT_TRUE(wm::IsActiveWindow(lock.get()));
- e1.ClickLeftButton();
- EXPECT_EQ(1, lock_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- // Make sure that a modal container created by the lock screen can still
- // receive mouse events.
- EventTestWindow* lock_modal_delegate = new EventTestWindow(true);
- aura::Window* lock_modal =
- lock_modal_delegate->ShowTestWindowWithParent(lock.get());
- EXPECT_TRUE(wm::IsActiveWindow(lock_modal));
- e1.ClickLeftButton();
- // Verify that none of the other containers received any more mouse presses.
- EXPECT_EQ(1, lock_modal_delegate->mouse_presses());
- EXPECT_EQ(1, lock_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- EXPECT_EQ(1, transient_delegate->mouse_presses());
- // Showing status will block events.
- status_control->Show();
- e1.ClickLeftButton();
- // Verify that none of the other containers received any more mouse presses.
- EXPECT_EQ(1, lock_modal_delegate->mouse_presses());
- EXPECT_EQ(1, lock_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- EXPECT_EQ(1, transient_delegate->mouse_presses());
- status_control->Hide();
- // Close |lock| before unlocking so that Shell::OnLockStateChanged does
- // not DCHECK on finding a system modal in Lock layer when unlocked.
- lock.reset();
- UnblockUserSession();
- }
- }
- // Test if a user can still click the status area in lock screen
- // even if the user session has system modal dialog.
- TEST_F(SystemModalContainerLayoutManagerTest,
- ClickStatusWithModalDialogInLockedState) {
- // Create a normal window and attempt to receive a click event.
- EventTestWindow* main_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> main(
- main_delegate->ShowTestWindowWithContext(GetContext()));
- ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), main.get());
- // A window for status area to test if it could receive an event
- // under each condition.
- EventTestWindow* status_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> status_control(
- status_delegate->ShowTestWindowWithParent(
- Shell::GetPrimaryRootWindowController()->GetContainer(
- kShellWindowId_ShelfContainer)));
- status_control->SetBounds(main->bounds());
- status_control->SetName("Status Control");
- // Events are blocked on all windows because status window is above the modal
- // window.
- EventTestWindow* modal_delegate = new EventTestWindow(true);
- aura::Window* modal = modal_delegate->ShowTestWindowWithParent(main.get());
- modal->SetName("Modal Window");
- EXPECT_TRUE(wm::IsActiveWindow(modal));
- generator.ClickLeftButton();
- EXPECT_EQ(0, main_delegate->mouse_presses());
- EXPECT_EQ(0, modal_delegate->mouse_presses());
- EXPECT_EQ(0, status_delegate->mouse_presses());
- BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
- // In lock screen, a window in status area container should be able to receive
- // the event even with a system modal dialog in the user session.
- generator.ClickLeftButton();
- EXPECT_EQ(0, main_delegate->mouse_presses());
- EXPECT_EQ(0, modal_delegate->mouse_presses());
- EXPECT_EQ(1, status_delegate->mouse_presses());
- }
- TEST_F(SystemModalContainerLayoutManagerTest, ModalTransientChildEvents) {
- // Create a normal window and attempt to receive a click event.
- EventTestWindow* main_delegate = new EventTestWindow(false);
- std::unique_ptr<aura::Window> main(
- main_delegate->ShowTestWindowWithContext(GetContext()));
- EXPECT_TRUE(wm::IsActiveWindow(main.get()));
- ui::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), main.get());
- e1.ClickLeftButton();
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create a modal window for the main window and verify that the main window
- // no longer receives mouse events.
- EventTestWindow* modal1_delegate = new EventTestWindow(true);
- aura::Window* modal1 = modal1_delegate->ShowTestWindowWithParent(main.get());
- EXPECT_TRUE(wm::IsActiveWindow(modal1));
- e1.ClickLeftButton();
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create a non-modal transient child of modal1 and verify it receives mouse
- // events instead of main and modal1.
- EventTestWindow* modal1_transient_delegate = new EventTestWindow(false);
- aura::Window* modal1_transient =
- modal1_transient_delegate->ShowTestWindowWithParent(modal1);
- EXPECT_TRUE(wm::IsActiveWindow(modal1_transient));
- e1.ClickLeftButton();
- EXPECT_EQ(1, modal1_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create a child control for modal1_transient and it receives mouse events.
- aura::test::EventCountDelegate control_delegate;
- control_delegate.set_window_component(HTCLIENT);
- std::unique_ptr<aura::Window> child =
- std::make_unique<aura::Window>(&control_delegate);
- child->SetType(aura::client::WINDOW_TYPE_CONTROL);
- child->Init(ui::LAYER_TEXTURED);
- modal1_transient->AddChild(child.get());
- child->SetBounds(gfx::Rect(100, 100));
- child->Show();
- e1.ClickLeftButton();
- EXPECT_EQ("1 1", control_delegate.GetMouseButtonCountsAndReset());
- EXPECT_EQ(1, modal1_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create another modal window for the main window and it receives mouse
- // events instead of all others.
- EventTestWindow* modal2_delegate = new EventTestWindow(true);
- aura::Window* modal2 = modal2_delegate->ShowTestWindowWithParent(main.get());
- EXPECT_TRUE(wm::IsActiveWindow(modal2));
- e1.ClickLeftButton();
- EXPECT_EQ(1, modal2_delegate->mouse_presses());
- EXPECT_EQ("0 0", control_delegate.GetMouseButtonCountsAndReset());
- EXPECT_EQ(1, modal1_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create a non-modal transient child of modal2 and it receives events.
- EventTestWindow* modal2_transient_delegate = new EventTestWindow(false);
- aura::Window* modal2_transient =
- modal2_transient_delegate->ShowTestWindowWithParent(modal2);
- EXPECT_TRUE(wm::IsActiveWindow(modal2_transient));
- e1.ClickLeftButton();
- EXPECT_EQ(1, modal2_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal2_delegate->mouse_presses());
- EXPECT_EQ("0 0", control_delegate.GetMouseButtonCountsAndReset());
- EXPECT_EQ(1, modal1_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- // Create a non-modal transient grandchild of modal2 and it receives events.
- EventTestWindow* modal2_transient_grandchild_delegate =
- new EventTestWindow(false);
- aura::Window* modal2_transient_grandchild =
- modal2_transient_grandchild_delegate->ShowTestWindowWithParent(
- modal2_transient);
- EXPECT_TRUE(wm::IsActiveWindow(modal2_transient_grandchild));
- e1.ClickLeftButton();
- EXPECT_EQ(1, modal2_transient_grandchild_delegate->mouse_presses());
- EXPECT_EQ(1, modal2_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal2_delegate->mouse_presses());
- EXPECT_EQ("0 0", control_delegate.GetMouseButtonCountsAndReset());
- EXPECT_EQ(1, modal1_transient_delegate->mouse_presses());
- EXPECT_EQ(1, modal1_delegate->mouse_presses());
- EXPECT_EQ(1, main_delegate->mouse_presses());
- }
- // Makes sure we don't crash if a modal window is shown while the parent window
- // is hidden.
- TEST_F(SystemModalContainerLayoutManagerTest, ShowModalWhileHidden) {
- // Hide the lock screen.
- Shell::GetPrimaryRootWindowController()
- ->GetContainer(kShellWindowId_SystemModalContainer)
- ->layer()
- ->SetOpacity(0);
- // Create a modal window.
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- }
- // Verifies we generate a capture lost when showing a modal window.
- TEST_F(SystemModalContainerLayoutManagerTest, ChangeCapture) {
- std::unique_ptr<aura::Window> widget_window(ShowToplevelTestWindow(false));
- views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView;
- views::View* client_view =
- views::Widget::GetWidgetForNativeView(widget_window.get())
- ->non_client_view()
- ->client_view();
- client_view->AddChildView(view);
- view->SetBoundsRect(client_view->bounds());
- gfx::Point center(view->width() / 2, view->height() / 2);
- views::View::ConvertPointToScreen(view, ¢er);
- ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), center);
- generator.PressLeftButton();
- EXPECT_TRUE(view->got_press());
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(widget_window.get(), true));
- EXPECT_TRUE(view->got_capture_lost());
- }
- // Verifies that the window gets moved into the visible screen area upon screen
- // resize.
- TEST_F(SystemModalContainerLayoutManagerTest, KeepVisible) {
- GetModalContainer()->SetBounds(gfx::Rect(0, 0, 1024, 768));
- std::unique_ptr<aura::Window> main(
- ShowTestWindowWithParent(GetModalContainer(), true));
- const int shelf_height = ShelfConfig::Get()->shelf_size();
- main->SetBounds(gfx::Rect(924, 668 - shelf_height, 100, 100));
- // We set now the bounds of the root window to something new which will
- // Then trigger the repos operation.
- GetModalContainer()->SetBounds(gfx::Rect(0, 0, 800, 600));
- gfx::Rect bounds = main->bounds();
- EXPECT_EQ(bounds, gfx::Rect(700, 500 - shelf_height, 100, 100));
- }
- // Verifies that centered windows will remain centered after the visible screen
- // area changed.
- TEST_F(SystemModalContainerLayoutManagerTest, KeepCentered) {
- GetModalContainer()->SetBounds(gfx::Rect(0, 0, 800, 600));
- std::unique_ptr<aura::Window> main(
- ShowTestWindowWithParent(GetModalContainer(), true));
- // Center the window.
- main->SetBounds(gfx::Rect((800 - 512) / 2, (600 - 256) / 2, 512, 256));
- // We set now the bounds of the root window to something new which will
- // Then trigger the reposition operation.
- GetModalContainer()->SetBounds(gfx::Rect(0, 0, 600, 400));
- // The window should still be centered.
- gfx::Rect bounds = main->bounds();
- EXPECT_EQ(bounds.ToString(),
- gfx::Rect((600 - 512) / 2, (400 - 256) / 2, 512, 256).ToString());
- }
- // Verifies that centered windows will remain centered in the secondary screen
- // with correct global position in screen coordinate system and local position
- // relative to root window.
- TEST_F(SystemModalContainerLayoutManagerTest, KeepCenteredSecondaryScreen) {
- UpdateDisplay("800x600,800+0-800x600");
- // Create a lock modal window in a lock state.
- GetSessionControllerClient()->SetSessionState(
- session_manager::SessionState::OOBE);
- aura::Window::Windows root_windows = Shell::GetAllRootWindows();
- aura::Window* secondary_display_modal_container = Shell::GetContainer(
- root_windows[1], kShellWindowId_LockSystemModalContainer);
- secondary_display_modal_container->SetBounds(gfx::Rect(0, 0, 800, 600));
- std::unique_ptr<aura::Window> modal(
- ShowTestWindowWithParent(secondary_display_modal_container, true));
- // Center the window.
- modal->SetBounds(gfx::Rect((800 - 512) / 2, (600 - 256) / 2, 512, 256));
- // We set now the bounds of the root window to something new which will
- // Then trigger the reposition operation.
- secondary_display_modal_container->SetBounds(gfx::Rect(0, 0, 600, 400));
- // The window should still be centered with global and local coordinates.
- gfx::Rect modal_bounds_in_screen = modal->GetBoundsInScreen();
- EXPECT_EQ(
- modal_bounds_in_screen.ToString(),
- gfx::Rect(800 + (600 - 512) / 2, (400 - 256) / 2, 512, 256).ToString());
- gfx::Rect modal_bounds_in_root = modal->bounds();
- EXPECT_EQ(modal_bounds_in_root.ToString(),
- gfx::Rect((600 - 512) / 2, (400 - 256) / 2, 512, 256).ToString());
- }
- TEST_F(SystemModalContainerLayoutManagerTest, ShowNormalBackgroundOrLocked) {
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- // Normal system modal window. Shows normal system modal background and not
- // locked.
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
- TestWindow::CloseTestWindow(modal_window.release());
- EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
- for (int block_reason = FIRST_BLOCK_REASON;
- block_reason < NUMBER_OF_BLOCK_REASONS; ++block_reason) {
- // Normal system modal window while blocked. Shows blocked system modal
- // background.
- BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
- std::unique_ptr<aura::Window> lock_parent(ShowTestWindowWithParent(
- Shell::GetPrimaryRootWindowController()->GetContainer(
- kShellWindowId_LockScreenContainer),
- false));
- std::unique_ptr<aura::Window> lock_modal_window(
- ShowTestWindowWithParent(lock_parent.get(), true));
- EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(AllRootWindowsHaveLockedModalBackgrounds());
- TestWindow::CloseTestWindow(lock_modal_window.release());
- // Normal system modal window while blocked, but it belongs to the normal
- // window. Shouldn't show blocked system modal background, but normal.
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
- TestWindow::CloseTestWindow(modal_window.release());
- // Close |lock_parent| before unlocking so that Shell::OnLockStateChanged
- // does not DCHECK on finding a system modal in Lock layer when unlocked.
- lock_parent.reset();
- UnblockUserSession();
- // Here we should check the behavior of the locked system modal dialog when
- // unlocked, but such case isn't handled very well right now.
- // See crbug.com/157660
- // TODO(mukai): add the test case when the bug is fixed.
- }
- }
- TEST_F(SystemModalContainerLayoutManagerTest, MultiDisplays) {
- UpdateDisplay("600x500,600x500");
- std::unique_ptr<aura::Window> normal(ShowToplevelTestWindow(false));
- normal->SetBounds(gfx::Rect(100, 100, 50, 50));
- aura::Window::Windows root_windows = Shell::GetAllRootWindows();
- EXPECT_EQ(2U, root_windows.size());
- aura::Window* container1 =
- Shell::GetContainer(root_windows[0], kShellWindowId_SystemModalContainer);
- aura::Window* container2 =
- Shell::GetContainer(root_windows[1], kShellWindowId_SystemModalContainer);
- std::unique_ptr<aura::Window> modal1(
- ShowTestWindowWithParent(container1, true));
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
- std::unique_ptr<aura::Window> modal11(
- ShowTestWindowWithParent(container1, true));
- EXPECT_TRUE(wm::IsActiveWindow(modal11.get()));
- std::unique_ptr<aura::Window> modal2(
- ShowTestWindowWithParent(container2, true));
- EXPECT_TRUE(wm::IsActiveWindow(modal2.get()));
- // Sanity check if they're on the correct containers.
- EXPECT_EQ(container1, modal1->parent());
- EXPECT_EQ(container1, modal11->parent());
- EXPECT_EQ(container2, modal2->parent());
- TestWindow::CloseTestWindow(modal2.release());
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(modal11.get()));
- TestWindow::CloseTestWindow(modal11.release());
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
- UpdateDisplay("600x500");
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
- UpdateDisplay("600x500,700x600");
- EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
- // No more modal screen.
- modal1->Hide();
- TestWindow::CloseTestWindow(modal1.release());
- EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
- EXPECT_TRUE(wm::IsActiveWindow(normal.get()));
- }
- // Test that with the visible keyboard, an existing system modal dialog gets
- // positioned into the visible area.
- TEST_F(SystemModalContainerLayoutManagerTest,
- SystemModalDialogGetPushedFromKeyboard) {
- const gfx::Rect& container_bounds = GetModalContainer()->bounds();
- // Place the window at the bottom of the screen.
- gfx::Size modal_size(100, 100);
- gfx::Point modal_origin = gfx::Point(
- (container_bounds.right() - modal_size.width()) / 2, // X centered
- container_bounds.bottom() - modal_size.height()); // at bottom
- gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size);
- // Create a modal window.
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- modal_window->SetBounds(modal_bounds);
- EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString());
- // The keyboard gets shown and the dialog should get pushed.
- ShowKeyboard(true);
- EXPECT_NE(modal_bounds.ToString(), modal_window->bounds().ToString());
- EXPECT_GT(modal_bounds.y(), modal_window->bounds().y());
- EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString());
- EXPECT_EQ(modal_origin.x(), modal_window->bounds().x());
- // After the keyboard is gone, the window will remain where it was.
- ShowKeyboard(false);
- EXPECT_NE(modal_bounds.ToString(), modal_window->bounds().ToString());
- EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString());
- EXPECT_EQ(modal_origin.x(), modal_window->bounds().x());
- }
- // Test that windows will not get cropped through the visible virtual keyboard -
- // if centered.
- TEST_F(SystemModalContainerLayoutManagerTest,
- SystemModalDialogGetPushedButNotCroppedFromKeyboard) {
- const gfx::Rect& container_bounds = GetModalContainer()->bounds();
- const gfx::Size screen_size = Shell::GetPrimaryRootWindow()->bounds().size();
- // Place the window at the bottom of the screen.
- gfx::Size modal_size(100, screen_size.height() - 70);
- gfx::Point modal_origin = gfx::Point(
- (container_bounds.right() - modal_size.width()) / 2, // X centered
- container_bounds.bottom() - modal_size.height()); // at bottom
- gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size);
- // Create a modal window.
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- modal_window->SetBounds(modal_bounds);
- EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString());
- // The keyboard gets shown and the dialog should get pushed up, but not get
- // cropped (and aligned to the top).
- ShowKeyboard(true);
- EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString());
- EXPECT_EQ(modal_origin.x(), modal_window->bounds().x());
- EXPECT_EQ(0, modal_window->bounds().y());
- ShowKeyboard(false);
- }
- // Test that windows will not get cropped through the visible virtual keyboard -
- // if not centered.
- TEST_F(SystemModalContainerLayoutManagerTest,
- SystemModalDialogGetPushedButNotCroppedFromKeyboardIfNotCentered) {
- const gfx::Size screen_size = Shell::GetPrimaryRootWindow()->bounds().size();
- // Place the window at the bottom of the screen.
- gfx::Size modal_size(100, screen_size.height() - 70);
- gfx::Point modal_origin = gfx::Point(10, 20);
- gfx::Rect modal_bounds = gfx::Rect(modal_origin, modal_size);
- // Create a modal window.
- std::unique_ptr<aura::Window> parent(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- ShowTestWindowWithParent(parent.get(), true));
- modal_window->SetBounds(modal_bounds);
- EXPECT_EQ(modal_bounds.ToString(), modal_window->bounds().ToString());
- // The keyboard gets shown and the dialog should get pushed up, but not get
- // cropped (and aligned to the top).
- ShowKeyboard(true);
- EXPECT_EQ(modal_size.ToString(), modal_window->bounds().size().ToString());
- EXPECT_EQ(modal_origin.x(), modal_window->bounds().x());
- EXPECT_EQ(0, modal_window->bounds().y());
- ShowKeyboard(false);
- }
- TEST_F(SystemModalContainerLayoutManagerTest, UpdateModalType) {
- aura::Window* modal_container = Shell::GetContainer(
- Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer);
- aura::Window* window = ShowTestWindowWithParent(modal_container, false);
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- // Setting twice should not cause error.
- window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE);
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- window_util::CloseWidgetForWindow(window);
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- }
- TEST_F(SystemModalContainerLayoutManagerTest, VisibilityChange) {
- std::unique_ptr<aura::Window> window(ShowToplevelTestWindow(false));
- std::unique_ptr<aura::Window> modal_window(
- views::Widget::CreateWindowWithContext(new TestWindow(true), GetContext())
- ->GetNativeWindow());
- SystemModalContainerLayoutManager* layout_manager =
- Shell::GetPrimaryRootWindowController()->GetSystemModalLayoutManager(
- modal_window.get());
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- EXPECT_FALSE(layout_manager->has_window_dimmer());
- modal_window->Show();
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- EXPECT_TRUE(layout_manager->has_window_dimmer());
- // Make sure that a child visibility change should not cause
- // inconsistent state.
- std::unique_ptr<aura::Window> child = std::make_unique<aura::Window>(nullptr);
- child->SetType(aura::client::WINDOW_TYPE_CONTROL);
- child->Init(ui::LAYER_TEXTURED);
- modal_window->AddChild(child.get());
- child->Show();
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- EXPECT_TRUE(layout_manager->has_window_dimmer());
- modal_window->Hide();
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- EXPECT_FALSE(layout_manager->has_window_dimmer());
- modal_window->Show();
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- EXPECT_TRUE(layout_manager->has_window_dimmer());
- }
- namespace {
- class InputTestDelegate : public aura::test::TestWindowDelegate {
- public:
- InputTestDelegate() = default;
- InputTestDelegate(const InputTestDelegate&) = delete;
- InputTestDelegate& operator=(const InputTestDelegate&) = delete;
- ~InputTestDelegate() override = default;
- void RunTest(AshTestBase* test_base) {
- std::unique_ptr<aura::Window> window(
- test_base->CreateTestWindowInShellWithDelegate(
- this, 0, gfx::Rect(0, 0, 100, 100)));
- window->Show();
- GenerateEvents(window.get());
- EXPECT_EQ(2, mouse_event_count_);
- EXPECT_EQ(3, scroll_event_count_);
- EXPECT_EQ(4, touch_event_count_);
- EXPECT_EQ(10, gesture_event_count_);
- Reset();
- views::Widget* widget = views::Widget::CreateWindowWithContext(
- new TestWindow(true), Shell::GetPrimaryRootWindow(),
- gfx::Rect(200, 200, 100, 100));
- widget->Show();
- EXPECT_TRUE(Shell::IsSystemModalWindowOpen());
- // Events should be blocked.
- GenerateEvents(window.get());
- EXPECT_EQ(0, mouse_event_count_);
- EXPECT_EQ(0, scroll_event_count_);
- EXPECT_EQ(0, touch_event_count_);
- EXPECT_EQ(0, gesture_event_count_);
- Reset();
- widget->Close();
- EXPECT_FALSE(Shell::IsSystemModalWindowOpen());
- GenerateEvents(window.get());
- EXPECT_EQ(2, mouse_event_count_);
- EXPECT_EQ(3, scroll_event_count_);
- EXPECT_EQ(4, touch_event_count_);
- EXPECT_EQ(10, gesture_event_count_);
- }
- private:
- // ui::EventHandler:
- void OnMouseEvent(ui::MouseEvent* event) override { mouse_event_count_++; }
- void OnScrollEvent(ui::ScrollEvent* event) override { scroll_event_count_++; }
- void OnTouchEvent(ui::TouchEvent* event) override { touch_event_count_++; }
- void OnGestureEvent(ui::GestureEvent* event) override {
- gesture_event_count_++;
- }
- void GenerateEvents(aura::Window* window) {
- ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow(),
- window);
- event_generator.ClickLeftButton();
- event_generator.ScrollSequence(window->bounds().CenterPoint(),
- base::TimeDelta(), 0, 10, 1, 2);
- event_generator.PressTouch();
- event_generator.ReleaseTouch();
- event_generator.GestureTapAt(window->bounds().CenterPoint());
- }
- void Reset() {
- mouse_event_count_ = 0;
- scroll_event_count_ = 0;
- touch_event_count_ = 0;
- gesture_event_count_ = 0;
- }
- int mouse_event_count_ = 0;
- int scroll_event_count_ = 0;
- int touch_event_count_ = 0;
- int gesture_event_count_ = 0;
- };
- } // namespace
- TEST_F(SystemModalContainerLayoutManagerTest, BlockAllEvents) {
- InputTestDelegate delegate;
- delegate.RunTest(this);
- }
- // Make sure that events are properly blocked in multi displays environment.
- TEST_F(SystemModalContainerLayoutManagerTest, BlockEventsInMultiDisplays) {
- UpdateDisplay("600x500, 600x500");
- InputTestDelegate delegate;
- delegate.RunTest(this);
- }
- } // namespace ash
|