- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / system_modal_container_layout_manager_unittest.cc
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_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/compiler_specific.h"
14 #include "base/run_loop.h"
15 #include "ui/aura/root_window.h"
16 #include "ui/aura/test/event_generator.h"
17 #include "ui/aura/window.h"
18 #include "ui/compositor/layer.h"
19 #include "ui/gfx/screen.h"
20 #include "ui/views/test/capture_tracking_view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/widget/widget_delegate.h"
23
24 namespace ash {
25 namespace test {
26
27 namespace {
28
29 aura::Window* GetModalContainer() {
30   return Shell::GetPrimaryRootWindowController()->GetContainer(
31       ash::internal::kShellWindowId_SystemModalContainer);
32 }
33
34 bool AllRootWindowsHaveModalBackgroundsForContainer(int container_id) {
35   std::vector<aura::Window*> containers =
36       Shell::GetContainersFromAllRootWindows(container_id, NULL);
37   bool has_modal_screen = !containers.empty();
38   for (std::vector<aura::Window*>::iterator iter = containers.begin();
39        iter != containers.end(); ++iter) {
40     has_modal_screen &=
41         static_cast<internal::SystemModalContainerLayoutManager*>(
42             (*iter)->layout_manager())->has_modal_background();
43   }
44   return has_modal_screen;
45 }
46
47 bool AllRootWindowsHaveLockedModalBackgrounds() {
48   return AllRootWindowsHaveModalBackgroundsForContainer(
49       internal::kShellWindowId_LockSystemModalContainer);
50 }
51
52 bool AllRootWindowsHaveModalBackgrounds() {
53   return AllRootWindowsHaveModalBackgroundsForContainer(
54       internal::kShellWindowId_SystemModalContainer);
55 }
56
57 class TestWindow : public views::WidgetDelegateView {
58  public:
59   explicit TestWindow(bool modal) : modal_(modal) {}
60   virtual ~TestWindow() {}
61
62   // The window needs be closed from widget in order for
63   // aura::client::kModalKey property to be reset.
64   static void CloseTestWindow(aura::Window* window) {
65     views::Widget::GetWidgetForNativeWindow(window)->Close();
66   }
67
68   // Overridden from views::View:
69   virtual gfx::Size GetPreferredSize() OVERRIDE {
70     return gfx::Size(50, 50);
71   }
72
73   // Overridden from views::WidgetDelegate:
74   virtual views::View* GetContentsView() OVERRIDE {
75     return this;
76   }
77   virtual ui::ModalType GetModalType() const OVERRIDE {
78     return modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE;
79   }
80
81  private:
82   bool modal_;
83
84   DISALLOW_COPY_AND_ASSIGN(TestWindow);
85 };
86
87 class EventTestWindow : public TestWindow {
88  public:
89   explicit EventTestWindow(bool modal) : TestWindow(modal),
90                                          mouse_presses_(0) {}
91   virtual ~EventTestWindow() {}
92
93   aura::Window* OpenTestWindowWithContext(aura::Window* context) {
94     views::Widget* widget =
95         views::Widget::CreateWindowWithContext(this, context);
96     widget->Show();
97     return widget->GetNativeView();
98   }
99
100   aura::Window* OpenTestWindowWithParent(aura::Window* parent) {
101     DCHECK(parent);
102     views::Widget* widget =
103         views::Widget::CreateWindowWithParent(this, parent);
104     widget->Show();
105     return widget->GetNativeView();
106   }
107
108   // Overridden from views::View:
109   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
110     mouse_presses_++;
111     return false;
112   }
113
114   int mouse_presses() const { return mouse_presses_; }
115  private:
116   int mouse_presses_;
117
118   DISALLOW_COPY_AND_ASSIGN(EventTestWindow);
119 };
120
121 class TransientWindowObserver : public aura::WindowObserver {
122  public:
123   TransientWindowObserver() : destroyed_(false) {}
124   virtual ~TransientWindowObserver() {}
125
126   bool destroyed() const { return destroyed_; }
127
128   // Overridden from aura::WindowObserver:
129   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
130     destroyed_ = true;
131   }
132
133  private:
134   bool destroyed_;
135
136   DISALLOW_COPY_AND_ASSIGN(TransientWindowObserver);
137 };
138
139 }  // namespace
140
141 class SystemModalContainerLayoutManagerTest : public AshTestBase {
142  public:
143   aura::Window* OpenToplevelTestWindow(bool modal) {
144     views::Widget* widget = views::Widget::CreateWindowWithContext(
145         new TestWindow(modal), CurrentContext());
146     widget->Show();
147     return widget->GetNativeView();
148   }
149
150   aura::Window* OpenTestWindowWithParent(aura::Window* parent, bool modal) {
151     views::Widget* widget =
152         views::Widget::CreateWindowWithParent(new TestWindow(modal), parent);
153     widget->Show();
154     return widget->GetNativeView();
155   }
156 };
157
158 TEST_F(SystemModalContainerLayoutManagerTest, NonModalTransient) {
159   scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false));
160   aura::Window* transient = OpenTestWindowWithParent(parent.get(), false);
161   TransientWindowObserver destruction_observer;
162   transient->AddObserver(&destruction_observer);
163
164   EXPECT_EQ(parent.get(), transient->transient_parent());
165   EXPECT_EQ(parent->parent(), transient->parent());
166
167   // The transient should be destroyed with its parent.
168   parent.reset();
169   EXPECT_TRUE(destruction_observer.destroyed());
170 }
171
172 TEST_F(SystemModalContainerLayoutManagerTest, ModalTransient) {
173   scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false));
174   // parent should be active.
175   EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
176   aura::Window* t1 = OpenTestWindowWithParent(parent.get(), true);
177
178   TransientWindowObserver do1;
179   t1->AddObserver(&do1);
180
181   EXPECT_EQ(parent.get(), t1->transient_parent());
182   EXPECT_EQ(GetModalContainer(), t1->parent());
183
184   // t1 should now be active.
185   EXPECT_TRUE(wm::IsActiveWindow(t1));
186
187   // Attempting to click the parent should result in no activation change.
188   aura::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get());
189   e1.ClickLeftButton();
190   EXPECT_TRUE(wm::IsActiveWindow(t1));
191
192   // Now open another modal transient parented to the original modal transient.
193   aura::Window* t2 = OpenTestWindowWithParent(t1, true);
194   TransientWindowObserver do2;
195   t2->AddObserver(&do2);
196
197   EXPECT_TRUE(wm::IsActiveWindow(t2));
198
199   EXPECT_EQ(t1, t2->transient_parent());
200   EXPECT_EQ(GetModalContainer(), t2->parent());
201
202   // t2 should still be active, even after clicking on t1.
203   aura::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1);
204   e2.ClickLeftButton();
205   EXPECT_TRUE(wm::IsActiveWindow(t2));
206
207   // Both transients should be destroyed with parent.
208   parent.reset();
209   EXPECT_TRUE(do1.destroyed());
210   EXPECT_TRUE(do2.destroyed());
211 }
212
213 TEST_F(SystemModalContainerLayoutManagerTest, ModalNonTransient) {
214   scoped_ptr<aura::Window> t1(OpenToplevelTestWindow(true));
215   // parent should be active.
216   EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
217   TransientWindowObserver do1;
218   t1->AddObserver(&do1);
219
220   EXPECT_EQ(NULL, t1->transient_parent());
221   EXPECT_EQ(GetModalContainer(), t1->parent());
222
223   // t1 should now be active.
224   EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
225
226   // Attempting to click the parent should result in no activation change.
227   aura::test::EventGenerator e1(Shell::GetPrimaryRootWindow(),
228                                 Shell::GetPrimaryRootWindow());
229   e1.ClickLeftButton();
230   EXPECT_TRUE(wm::IsActiveWindow(t1.get()));
231
232   // Now open another modal transient parented to the original modal transient.
233   aura::Window* t2 = OpenTestWindowWithParent(t1.get(), true);
234   TransientWindowObserver do2;
235   t2->AddObserver(&do2);
236
237   EXPECT_TRUE(wm::IsActiveWindow(t2));
238
239   EXPECT_EQ(t1, t2->transient_parent());
240   EXPECT_EQ(GetModalContainer(), t2->parent());
241
242   // t2 should still be active, even after clicking on t1.
243   aura::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), t1.get());
244   e2.ClickLeftButton();
245   EXPECT_TRUE(wm::IsActiveWindow(t2));
246
247   // Both transients should be destroyed with parent.
248   t1.reset();
249   EXPECT_TRUE(do1.destroyed());
250   EXPECT_TRUE(do2.destroyed());
251 }
252
253 // Tests that we can activate an unrelated window after a modal window is closed
254 // for a window.
255 TEST_F(SystemModalContainerLayoutManagerTest, CanActivateAfterEndModalSession) {
256   scoped_ptr<aura::Window> unrelated(OpenToplevelTestWindow(false));
257   unrelated->SetBounds(gfx::Rect(100, 100, 50, 50));
258   scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false));
259   // parent should be active.
260   EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
261
262   scoped_ptr<aura::Window> transient(
263       OpenTestWindowWithParent(parent.get(), true));
264   // t1 should now be active.
265   EXPECT_TRUE(wm::IsActiveWindow(transient.get()));
266
267   // Attempting to click the parent should result in no activation change.
268   aura::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), parent.get());
269   e1.ClickLeftButton();
270   EXPECT_TRUE(wm::IsActiveWindow(transient.get()));
271
272   // Now close the transient.
273   transient->Hide();
274   TestWindow::CloseTestWindow(transient.release());
275
276   base::RunLoop().RunUntilIdle();
277
278   // parent should now be active again.
279   EXPECT_TRUE(wm::IsActiveWindow(parent.get()));
280
281   // Attempting to click unrelated should activate it.
282   aura::test::EventGenerator e2(Shell::GetPrimaryRootWindow(), unrelated.get());
283   e2.ClickLeftButton();
284   EXPECT_TRUE(wm::IsActiveWindow(unrelated.get()));
285 }
286
287 TEST_F(SystemModalContainerLayoutManagerTest, EventFocusContainers) {
288   // Create a normal window and attempt to receive a click event.
289   EventTestWindow* main_delegate = new EventTestWindow(false);
290   scoped_ptr<aura::Window> main(
291       main_delegate->OpenTestWindowWithContext(CurrentContext()));
292   EXPECT_TRUE(wm::IsActiveWindow(main.get()));
293   aura::test::EventGenerator e1(Shell::GetPrimaryRootWindow(), main.get());
294   e1.ClickLeftButton();
295   EXPECT_EQ(1, main_delegate->mouse_presses());
296
297   // Create a modal window for the main window and verify that the main window
298   // no longer receives mouse events.
299   EventTestWindow* transient_delegate = new EventTestWindow(true);
300   aura::Window* transient =
301       transient_delegate->OpenTestWindowWithParent(main.get());
302   EXPECT_TRUE(wm::IsActiveWindow(transient));
303   e1.ClickLeftButton();
304   EXPECT_EQ(1, transient_delegate->mouse_presses());
305
306   for (int block_reason = FIRST_BLOCK_REASON;
307        block_reason < NUMBER_OF_BLOCK_REASONS;
308        ++block_reason) {
309     // Create a window in the lock screen container and ensure that it receives
310     // the mouse event instead of the modal window (crbug.com/110920).
311     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
312     EventTestWindow* lock_delegate = new EventTestWindow(false);
313     scoped_ptr<aura::Window> lock(lock_delegate->OpenTestWindowWithParent(
314         Shell::GetPrimaryRootWindowController()->GetContainer(
315             ash::internal::kShellWindowId_LockScreenContainer)));
316     EXPECT_TRUE(wm::IsActiveWindow(lock.get()));
317     e1.ClickLeftButton();
318     EXPECT_EQ(1, lock_delegate->mouse_presses());
319
320     // Make sure that a modal container created by the lock screen can still
321     // receive mouse events.
322     EventTestWindow* lock_modal_delegate = new EventTestWindow(true);
323     aura::Window* lock_modal =
324         lock_modal_delegate->OpenTestWindowWithParent(lock.get());
325     EXPECT_TRUE(wm::IsActiveWindow(lock_modal));
326     e1.ClickLeftButton();
327     // Verify that none of the other containers received any more mouse presses.
328     EXPECT_EQ(1, lock_modal_delegate->mouse_presses());
329     EXPECT_EQ(1, lock_delegate->mouse_presses());
330     EXPECT_EQ(1, main_delegate->mouse_presses());
331     EXPECT_EQ(1, transient_delegate->mouse_presses());
332     UnblockUserSession();
333   }
334 }
335
336 // Makes sure we don't crash if a modal window is shown while the parent window
337 // is hidden.
338 TEST_F(SystemModalContainerLayoutManagerTest, ShowModalWhileHidden) {
339   // Hide the lock screen.
340   Shell::GetPrimaryRootWindowController()->GetContainer(
341       internal::kShellWindowId_SystemModalContainer)->layer()->SetOpacity(0);
342
343   // Create a modal window.
344   scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false));
345   scoped_ptr<aura::Window> modal_window(
346       OpenTestWindowWithParent(parent.get(), true));
347   parent->Show();
348   modal_window->Show();
349 }
350
351 // Verifies we generate a capture lost when showing a modal window.
352 TEST_F(SystemModalContainerLayoutManagerTest, ChangeCapture) {
353   views::Widget* widget = views::Widget::CreateWindowWithContext(
354       new TestWindow(false), CurrentContext());
355   scoped_ptr<aura::Window> widget_window(widget->GetNativeView());
356   views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView;
357   widget->GetContentsView()->AddChildView(view);
358   view->SetBoundsRect(widget->GetContentsView()->bounds());
359   widget->Show();
360
361   gfx::Point center(view->width() / 2, view->height() / 2);
362   views::View::ConvertPointToScreen(view, &center);
363   aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), center);
364   generator.PressLeftButton();
365   EXPECT_TRUE(view->got_press());
366   scoped_ptr<aura::Window> modal_window(
367       OpenTestWindowWithParent(widget->GetNativeView(), true));
368   modal_window->Show();
369   EXPECT_TRUE(view->got_capture_lost());
370 }
371
372 // Verifies that the window gets moved into the visible screen area upon screen
373 // resize.
374 TEST_F(SystemModalContainerLayoutManagerTest, KeepVisible) {
375   GetModalContainer()->SetBounds(gfx::Rect(0, 0, 1024, 768));
376   scoped_ptr<aura::Window> main(OpenTestWindowWithParent(GetModalContainer(),
377                                                          true));
378   main->SetBounds(gfx::Rect(924, 668, 100, 100));
379   // We set now the bounds of the root window to something new which will
380   // Then trigger the repos operation.
381   GetModalContainer()->SetBounds(gfx::Rect(0, 0, 800, 600));
382
383   gfx::Rect bounds = main->bounds();
384   EXPECT_EQ(bounds, gfx::Rect(700, 500, 100, 100));
385 }
386
387 TEST_F(SystemModalContainerLayoutManagerTest, ShowNormalBackgroundOrLocked) {
388   scoped_ptr<aura::Window> parent(OpenToplevelTestWindow(false));
389   scoped_ptr<aura::Window> modal_window(
390       OpenTestWindowWithParent(parent.get(), true));
391   parent->Show();
392   modal_window->Show();
393
394   // Normal system modal window.  Shows normal system modal background and not
395   // locked.
396   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
397   EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
398
399   TestWindow::CloseTestWindow(modal_window.release());
400   EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
401   EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
402
403   for (int block_reason = FIRST_BLOCK_REASON;
404        block_reason < NUMBER_OF_BLOCK_REASONS;
405        ++block_reason) {
406     // Normal system modal window while blocked.  Shows blocked system modal
407     // background.
408     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
409     scoped_ptr<aura::Window> lock_parent(OpenTestWindowWithParent(
410         Shell::GetPrimaryRootWindowController()->GetContainer(
411             ash::internal::kShellWindowId_LockScreenContainer),
412         false));
413     scoped_ptr<aura::Window> lock_modal_window(OpenTestWindowWithParent(
414         lock_parent.get(), true));
415     lock_parent->Show();
416     lock_modal_window->Show();
417     EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
418     EXPECT_TRUE(AllRootWindowsHaveLockedModalBackgrounds());
419     TestWindow::CloseTestWindow(lock_modal_window.release());
420
421     // Normal system modal window while blocked, but it belongs to the normal
422     // window.  Shouldn't show blocked system modal background, but normal.
423     scoped_ptr<aura::Window> modal_window(
424         OpenTestWindowWithParent(parent.get(), true));
425     modal_window->Show();
426     EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
427     EXPECT_FALSE(AllRootWindowsHaveLockedModalBackgrounds());
428     TestWindow::CloseTestWindow(modal_window.release());
429     UnblockUserSession();
430     // Here we should check the behavior of the locked system modal dialog when
431     // unlocked, but such case isn't handled very well right now.
432     // See crbug.com/157660
433     // TODO(mukai): add the test case when the bug is fixed.
434   }
435 }
436
437 TEST_F(SystemModalContainerLayoutManagerTest, MultiDisplays) {
438   if (!SupportsMultipleDisplays())
439     return;
440
441   UpdateDisplay("500x500,500x500");
442
443   scoped_ptr<aura::Window> normal(OpenToplevelTestWindow(false));
444   normal->SetBounds(gfx::Rect(100, 100, 50, 50));
445
446   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
447   EXPECT_EQ(2U, root_windows.size());
448   aura::Window* container1 = Shell::GetContainer(
449       root_windows[0], ash::internal::kShellWindowId_SystemModalContainer);
450   aura::Window* container2 = Shell::GetContainer(
451       root_windows[1], ash::internal::kShellWindowId_SystemModalContainer);
452
453   scoped_ptr<aura::Window> modal1(
454       OpenTestWindowWithParent(container1, true));
455   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
456   EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
457
458   scoped_ptr<aura::Window> modal11(
459       OpenTestWindowWithParent(container1, true));
460   EXPECT_TRUE(wm::IsActiveWindow(modal11.get()));
461
462   scoped_ptr<aura::Window> modal2(
463       OpenTestWindowWithParent(container2, true));
464   EXPECT_TRUE(wm::IsActiveWindow(modal2.get()));
465
466   // Sanity check if they're on the correct containers.
467   EXPECT_EQ(container1, modal1->parent());
468   EXPECT_EQ(container1, modal11->parent());
469   EXPECT_EQ(container2, modal2->parent());
470
471   TestWindow::CloseTestWindow(modal2.release());
472   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
473   EXPECT_TRUE(wm::IsActiveWindow(modal11.get()));
474
475   TestWindow::CloseTestWindow(modal11.release());
476   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
477   EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
478
479   UpdateDisplay("500x500");
480   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
481   EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
482
483   UpdateDisplay("500x500,600x600");
484   EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds());
485   EXPECT_TRUE(wm::IsActiveWindow(modal1.get()));
486
487   // No more modal screen.
488   modal1->Hide();
489   TestWindow::CloseTestWindow(modal1.release());
490   EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds());
491   EXPECT_TRUE(wm::IsActiveWindow(normal.get()));
492 }
493
494 }  // namespace test
495 }  // namespace ash