191ad379ad1c379e64463c714e93f28e853519dd
[platform/framework/web/crosswalk.git] / src / ash / root_window_controller_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/root_window_controller.h"
6
7 #include "ash/session/session_state_delegate.h"
8 #include "ash/shelf/shelf_layout_manager.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/system/tray/system_tray_delegate.h"
12 #include "ash/test/ash_test_base.h"
13 #include "ash/wm/system_modal_container_layout_manager.h"
14 #include "ash/wm/window_properties.h"
15 #include "ash/wm/window_state.h"
16 #include "ash/wm/window_util.h"
17 #include "base/command_line.h"
18 #include "ui/aura/client/focus_change_observer.h"
19 #include "ui/aura/client/focus_client.h"
20 #include "ui/aura/client/window_tree_client.h"
21 #include "ui/aura/env.h"
22 #include "ui/aura/test/event_generator.h"
23 #include "ui/aura/test/test_window_delegate.h"
24 #include "ui/aura/test/test_windows.h"
25 #include "ui/aura/window.h"
26 #include "ui/aura/window_event_dispatcher.h"
27 #include "ui/aura/window_tracker.h"
28 #include "ui/base/ime/dummy_text_input_client.h"
29 #include "ui/base/ime/input_method.h"
30 #include "ui/base/ime/text_input_client.h"
31 #include "ui/events/test/test_event_handler.h"
32 #include "ui/keyboard/keyboard_controller_proxy.h"
33 #include "ui/keyboard/keyboard_switches.h"
34 #include "ui/keyboard/keyboard_util.h"
35 #include "ui/views/controls/menu/menu_controller.h"
36 #include "ui/views/widget/widget.h"
37 #include "ui/views/widget/widget_delegate.h"
38
39 using aura::Window;
40 using views::Widget;
41
42 namespace ash {
43 namespace {
44
45 class TestDelegate : public views::WidgetDelegateView {
46  public:
47   explicit TestDelegate(bool system_modal) : system_modal_(system_modal) {}
48   virtual ~TestDelegate() {}
49
50   // Overridden from views::WidgetDelegate:
51   virtual views::View* GetContentsView() OVERRIDE {
52     return this;
53   }
54
55   virtual ui::ModalType GetModalType() const OVERRIDE {
56     return system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE;
57   }
58
59  private:
60   bool system_modal_;
61
62   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
63 };
64
65 class DeleteOnBlurDelegate : public aura::test::TestWindowDelegate,
66                              public aura::client::FocusChangeObserver {
67  public:
68   DeleteOnBlurDelegate() : window_(NULL) {}
69   virtual ~DeleteOnBlurDelegate() {}
70
71   void SetWindow(aura::Window* window) {
72     window_ = window;
73     aura::client::SetFocusChangeObserver(window_, this);
74   }
75
76  private:
77   // aura::test::TestWindowDelegate overrides:
78   virtual bool CanFocus() OVERRIDE {
79     return true;
80   }
81
82   // aura::client::FocusChangeObserver implementation:
83   virtual void OnWindowFocused(aura::Window* gained_focus,
84                                aura::Window* lost_focus) OVERRIDE {
85     if (window_ == lost_focus)
86       delete window_;
87   }
88
89   aura::Window* window_;
90
91   DISALLOW_COPY_AND_ASSIGN(DeleteOnBlurDelegate);
92 };
93
94 }  // namespace
95
96 namespace test {
97
98 class RootWindowControllerTest : public test::AshTestBase {
99  public:
100   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
101     views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
102         NULL, CurrentContext(), bounds);
103     widget->Show();
104     return widget;
105   }
106
107   views::Widget* CreateModalWidget(const gfx::Rect& bounds) {
108     views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
109         new TestDelegate(true), CurrentContext(), bounds);
110     widget->Show();
111     return widget;
112   }
113
114   views::Widget* CreateModalWidgetWithParent(const gfx::Rect& bounds,
115                                              gfx::NativeWindow parent) {
116     views::Widget* widget =
117         views::Widget::CreateWindowWithParentAndBounds(new TestDelegate(true),
118                                                        parent,
119                                                        bounds);
120     widget->Show();
121     return widget;
122   }
123
124   aura::Window* GetModalContainer(aura::Window* root_window) {
125     return Shell::GetContainer(root_window,
126                                ash::kShellWindowId_SystemModalContainer);
127   }
128 };
129
130 TEST_F(RootWindowControllerTest, MoveWindows_Basic) {
131   if (!SupportsMultipleDisplays())
132     return;
133   // Windows origin should be doubled when moved to the 1st display.
134   UpdateDisplay("600x600,300x300");
135   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
136   RootWindowController* controller = Shell::GetPrimaryRootWindowController();
137   ShelfLayoutManager* shelf_layout_manager =
138       controller->GetShelfLayoutManager();
139   shelf_layout_manager->SetAutoHideBehavior(
140       ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
141
142   views::Widget* normal = CreateTestWidget(gfx::Rect(650, 10, 100, 100));
143   EXPECT_EQ(root_windows[1], normal->GetNativeView()->GetRootWindow());
144   EXPECT_EQ("650,10 100x100", normal->GetWindowBoundsInScreen().ToString());
145   EXPECT_EQ("50,10 100x100",
146             normal->GetNativeView()->GetBoundsInRootWindow().ToString());
147
148   views::Widget* maximized = CreateTestWidget(gfx::Rect(700, 10, 100, 100));
149   maximized->Maximize();
150   EXPECT_EQ(root_windows[1], maximized->GetNativeView()->GetRootWindow());
151   EXPECT_EQ("600,0 300x253", maximized->GetWindowBoundsInScreen().ToString());
152   EXPECT_EQ("0,0 300x253",
153             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
154
155   views::Widget* minimized = CreateTestWidget(gfx::Rect(800, 10, 100, 100));
156   minimized->Minimize();
157   EXPECT_EQ(root_windows[1], minimized->GetNativeView()->GetRootWindow());
158   EXPECT_EQ("800,10 100x100",
159             minimized->GetWindowBoundsInScreen().ToString());
160
161   views::Widget* fullscreen = CreateTestWidget(gfx::Rect(850, 10, 100, 100));
162   fullscreen->SetFullscreen(true);
163   EXPECT_EQ(root_windows[1], fullscreen->GetNativeView()->GetRootWindow());
164
165   EXPECT_EQ("600,0 300x300",
166             fullscreen->GetWindowBoundsInScreen().ToString());
167   EXPECT_EQ("0,0 300x300",
168             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
169
170   views::Widget* unparented_control = new Widget;
171   Widget::InitParams params;
172   params.bounds = gfx::Rect(650, 10, 100, 100);
173   params.context = CurrentContext();
174   params.type = Widget::InitParams::TYPE_CONTROL;
175   unparented_control->Init(params);
176   EXPECT_EQ(root_windows[1],
177             unparented_control->GetNativeView()->GetRootWindow());
178   EXPECT_EQ(kShellWindowId_UnparentedControlContainer,
179             unparented_control->GetNativeView()->parent()->id());
180
181   aura::Window* panel = CreateTestWindowInShellWithDelegateAndType(
182       NULL, ui::wm::WINDOW_TYPE_PANEL, 0, gfx::Rect(700, 100, 100, 100));
183   EXPECT_EQ(root_windows[1], panel->GetRootWindow());
184   EXPECT_EQ(kShellWindowId_PanelContainer, panel->parent()->id());
185
186   // Make sure a window that will delete itself when losing focus
187   // will not crash.
188   aura::WindowTracker tracker;
189   DeleteOnBlurDelegate delete_on_blur_delegate;
190   aura::Window* d2 = CreateTestWindowInShellWithDelegate(
191       &delete_on_blur_delegate, 0, gfx::Rect(50, 50, 100, 100));
192   delete_on_blur_delegate.SetWindow(d2);
193   aura::client::GetFocusClient(root_windows[0])->FocusWindow(d2);
194   tracker.Add(d2);
195
196   UpdateDisplay("600x600");
197
198   // d2 must have been deleted.
199   EXPECT_FALSE(tracker.Contains(d2));
200
201   EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
202   EXPECT_EQ("100,20 100x100", normal->GetWindowBoundsInScreen().ToString());
203   EXPECT_EQ("100,20 100x100",
204             normal->GetNativeView()->GetBoundsInRootWindow().ToString());
205
206   // Maximized area on primary display has 3px (given as
207   // kAutoHideSize in shelf_layout_manager.cc) inset at the bottom.
208
209   // First clear fullscreen status, since both fullscreen and maximized windows
210   // share the same desktop workspace, which cancels the shelf status.
211   fullscreen->SetFullscreen(false);
212   EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
213   EXPECT_EQ("0,0 600x597",
214             maximized->GetWindowBoundsInScreen().ToString());
215   EXPECT_EQ("0,0 600x597",
216             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
217
218   // Set fullscreen to true. In that case the 3px inset becomes invisible so
219   // the maximized window can also use the area fully.
220   fullscreen->SetFullscreen(true);
221   EXPECT_EQ(root_windows[0], maximized->GetNativeView()->GetRootWindow());
222   EXPECT_EQ("0,0 600x600",
223             maximized->GetWindowBoundsInScreen().ToString());
224   EXPECT_EQ("0,0 600x600",
225             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
226
227   EXPECT_EQ(root_windows[0], minimized->GetNativeView()->GetRootWindow());
228   EXPECT_EQ("400,20 100x100",
229             minimized->GetWindowBoundsInScreen().ToString());
230
231   EXPECT_EQ(root_windows[0], fullscreen->GetNativeView()->GetRootWindow());
232   EXPECT_TRUE(fullscreen->IsFullscreen());
233   EXPECT_EQ("0,0 600x600",
234             fullscreen->GetWindowBoundsInScreen().ToString());
235   EXPECT_EQ("0,0 600x600",
236             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
237
238   // Test if the restore bounds are correctly updated.
239   wm::GetWindowState(maximized->GetNativeView())->Restore();
240   EXPECT_EQ("200,20 100x100", maximized->GetWindowBoundsInScreen().ToString());
241   EXPECT_EQ("200,20 100x100",
242             maximized->GetNativeView()->GetBoundsInRootWindow().ToString());
243
244   fullscreen->SetFullscreen(false);
245   EXPECT_EQ("500,20 100x100",
246             fullscreen->GetWindowBoundsInScreen().ToString());
247   EXPECT_EQ("500,20 100x100",
248             fullscreen->GetNativeView()->GetBoundsInRootWindow().ToString());
249
250   // Test if the unparented widget has moved.
251   EXPECT_EQ(root_windows[0],
252             unparented_control->GetNativeView()->GetRootWindow());
253   EXPECT_EQ(kShellWindowId_UnparentedControlContainer,
254             unparented_control->GetNativeView()->parent()->id());
255
256   // Test if the panel has moved.
257   EXPECT_EQ(root_windows[0], panel->GetRootWindow());
258   EXPECT_EQ(kShellWindowId_PanelContainer, panel->parent()->id());
259 }
260
261 TEST_F(RootWindowControllerTest, MoveWindows_Modal) {
262   if (!SupportsMultipleDisplays())
263     return;
264
265   UpdateDisplay("500x500,500x500");
266
267   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
268   // Emulate virtual screen coordinate system.
269   root_windows[0]->SetBounds(gfx::Rect(0, 0, 500, 500));
270   root_windows[1]->SetBounds(gfx::Rect(500, 0, 500, 500));
271
272   views::Widget* normal = CreateTestWidget(gfx::Rect(300, 10, 100, 100));
273   EXPECT_EQ(root_windows[0], normal->GetNativeView()->GetRootWindow());
274   EXPECT_TRUE(wm::IsActiveWindow(normal->GetNativeView()));
275
276   views::Widget* modal = CreateModalWidget(gfx::Rect(650, 10, 100, 100));
277   EXPECT_EQ(root_windows[1], modal->GetNativeView()->GetRootWindow());
278   EXPECT_TRUE(GetModalContainer(root_windows[1])->Contains(
279       modal->GetNativeView()));
280   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
281
282   aura::test::EventGenerator generator_1st(root_windows[0]);
283   generator_1st.ClickLeftButton();
284   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
285
286   UpdateDisplay("500x500");
287   EXPECT_EQ(root_windows[0], modal->GetNativeView()->GetRootWindow());
288   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
289   generator_1st.ClickLeftButton();
290   EXPECT_TRUE(wm::IsActiveWindow(modal->GetNativeView()));
291 }
292
293 TEST_F(RootWindowControllerTest, ModalContainer) {
294   UpdateDisplay("600x600");
295   Shell* shell = Shell::GetInstance();
296   RootWindowController* controller = shell->GetPrimaryRootWindowController();
297   EXPECT_EQ(user::LOGGED_IN_USER,
298             shell->system_tray_delegate()->GetUserLoginStatus());
299   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
300                 ->layout_manager(),
301             controller->GetSystemModalLayoutManager(NULL));
302
303   views::Widget* session_modal_widget =
304       CreateModalWidget(gfx::Rect(300, 10, 100, 100));
305   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
306                 ->layout_manager(),
307             controller->GetSystemModalLayoutManager(
308                 session_modal_widget->GetNativeView()));
309
310   shell->session_state_delegate()->LockScreen();
311   EXPECT_EQ(user::LOGGED_IN_LOCKED,
312             shell->system_tray_delegate()->GetUserLoginStatus());
313   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
314                 ->layout_manager(),
315             controller->GetSystemModalLayoutManager(NULL));
316
317   aura::Window* lock_container =
318       controller->GetContainer(kShellWindowId_LockScreenContainer);
319   views::Widget* lock_modal_widget =
320       CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
321   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
322                 ->layout_manager(),
323             controller->GetSystemModalLayoutManager(
324                 lock_modal_widget->GetNativeView()));
325   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
326                 ->layout_manager(),
327             controller->GetSystemModalLayoutManager(
328                 session_modal_widget->GetNativeView()));
329
330   shell->session_state_delegate()->UnlockScreen();
331 }
332
333 TEST_F(RootWindowControllerTest, ModalContainerNotLoggedInLoggedIn) {
334   UpdateDisplay("600x600");
335   Shell* shell = Shell::GetInstance();
336
337   // Configure login screen environment.
338   SetUserLoggedIn(false);
339   EXPECT_EQ(user::LOGGED_IN_NONE,
340             shell->system_tray_delegate()->GetUserLoginStatus());
341   EXPECT_EQ(0, shell->session_state_delegate()->NumberOfLoggedInUsers());
342   EXPECT_FALSE(shell->session_state_delegate()->IsActiveUserSessionStarted());
343
344   RootWindowController* controller = shell->GetPrimaryRootWindowController();
345   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
346                 ->layout_manager(),
347             controller->GetSystemModalLayoutManager(NULL));
348
349   aura::Window* lock_container =
350       controller->GetContainer(kShellWindowId_LockScreenContainer);
351   views::Widget* login_modal_widget =
352       CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100), lock_container);
353   EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
354                 ->layout_manager(),
355             controller->GetSystemModalLayoutManager(
356                 login_modal_widget->GetNativeView()));
357   login_modal_widget->Close();
358
359   // Configure user session environment.
360   SetUserLoggedIn(true);
361   SetSessionStarted(true);
362   EXPECT_EQ(user::LOGGED_IN_USER,
363             shell->system_tray_delegate()->GetUserLoginStatus());
364   EXPECT_EQ(1, shell->session_state_delegate()->NumberOfLoggedInUsers());
365   EXPECT_TRUE(shell->session_state_delegate()->IsActiveUserSessionStarted());
366   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
367                 ->layout_manager(),
368             controller->GetSystemModalLayoutManager(NULL));
369
370   views::Widget* session_modal_widget =
371         CreateModalWidget(gfx::Rect(300, 10, 100, 100));
372   EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
373                 ->layout_manager(),
374             controller->GetSystemModalLayoutManager(
375                 session_modal_widget->GetNativeView()));
376 }
377
378 TEST_F(RootWindowControllerTest, ModalContainerBlockedSession) {
379   UpdateDisplay("600x600");
380   Shell* shell = Shell::GetInstance();
381   RootWindowController* controller = shell->GetPrimaryRootWindowController();
382   aura::Window* lock_container =
383       controller->GetContainer(kShellWindowId_LockScreenContainer);
384   for (int block_reason = FIRST_BLOCK_REASON;
385        block_reason < NUMBER_OF_BLOCK_REASONS;
386        ++block_reason) {
387     views::Widget* session_modal_widget =
388           CreateModalWidget(gfx::Rect(300, 10, 100, 100));
389     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
390                   ->layout_manager(),
391               controller->GetSystemModalLayoutManager(
392                   session_modal_widget->GetNativeView()));
393     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
394                   ->layout_manager(),
395               controller->GetSystemModalLayoutManager(NULL));
396     session_modal_widget->Close();
397
398     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
399
400     EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
401                   ->layout_manager(),
402               controller->GetSystemModalLayoutManager(NULL));
403
404     views::Widget* lock_modal_widget =
405         CreateModalWidgetWithParent(gfx::Rect(300, 10, 100, 100),
406                                     lock_container);
407     EXPECT_EQ(controller->GetContainer(kShellWindowId_LockSystemModalContainer)
408                   ->layout_manager(),
409               controller->GetSystemModalLayoutManager(
410                   lock_modal_widget->GetNativeView()));
411
412     session_modal_widget =
413           CreateModalWidget(gfx::Rect(300, 10, 100, 100));
414     EXPECT_EQ(controller->GetContainer(kShellWindowId_SystemModalContainer)
415                   ->layout_manager(),
416               controller->GetSystemModalLayoutManager(
417                   session_modal_widget->GetNativeView()));
418     session_modal_widget->Close();
419
420     lock_modal_widget->Close();
421     UnblockUserSession();
422   }
423 }
424
425 TEST_F(RootWindowControllerTest, GetWindowForFullscreenMode) {
426   UpdateDisplay("600x600");
427   RootWindowController* controller =
428       Shell::GetInstance()->GetPrimaryRootWindowController();
429
430   Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
431   w1->Maximize();
432   Widget* w2 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
433   w2->SetFullscreen(true);
434   // |w3| is a transient child of |w2|.
435   Widget* w3 = Widget::CreateWindowWithParentAndBounds(NULL,
436       w2->GetNativeWindow(), gfx::Rect(0, 0, 100, 100));
437
438   // Test that GetWindowForFullscreenMode() finds the fullscreen window when one
439   // of its transient children is active.
440   w3->Activate();
441   EXPECT_EQ(w2->GetNativeWindow(), controller->GetWindowForFullscreenMode());
442
443   // If the topmost window is not fullscreen, it returns NULL.
444   w1->Activate();
445   EXPECT_EQ(NULL, controller->GetWindowForFullscreenMode());
446   w1->Close();
447   w3->Close();
448
449   // Only w2 remains, if minimized GetWindowForFullscreenMode should return
450   // NULL.
451   w2->Activate();
452   EXPECT_EQ(w2->GetNativeWindow(), controller->GetWindowForFullscreenMode());
453   w2->Minimize();
454   EXPECT_EQ(NULL, controller->GetWindowForFullscreenMode());
455 }
456
457 TEST_F(RootWindowControllerTest, MultipleDisplaysGetWindowForFullscreenMode) {
458   if (!SupportsMultipleDisplays())
459     return;
460
461   UpdateDisplay("600x600,600x600");
462   Shell::RootWindowControllerList controllers =
463       Shell::GetInstance()->GetAllRootWindowControllers();
464
465   Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
466   w1->Maximize();
467   Widget* w2 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
468   w2->SetFullscreen(true);
469   Widget* w3 = CreateTestWidget(gfx::Rect(600, 0, 100, 100));
470
471   EXPECT_EQ(w1->GetNativeWindow()->GetRootWindow(),
472             controllers[0]->GetRootWindow());
473   EXPECT_EQ(w2->GetNativeWindow()->GetRootWindow(),
474             controllers[0]->GetRootWindow());
475   EXPECT_EQ(w3->GetNativeWindow()->GetRootWindow(),
476             controllers[1]->GetRootWindow());
477
478   w1->Activate();
479   EXPECT_EQ(NULL, controllers[0]->GetWindowForFullscreenMode());
480   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
481
482   w2->Activate();
483   EXPECT_EQ(w2->GetNativeWindow(),
484             controllers[0]->GetWindowForFullscreenMode());
485   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
486
487   // Verify that the first root window controller remains in fullscreen mode
488   // when a window on the other display is activated.
489   w3->Activate();
490   EXPECT_EQ(w2->GetNativeWindow(),
491             controllers[0]->GetWindowForFullscreenMode());
492   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
493 }
494
495 // Test that user session window can't be focused if user session blocked by
496 // some overlapping UI.
497 TEST_F(RootWindowControllerTest, FocusBlockedWindow) {
498   UpdateDisplay("600x600");
499   RootWindowController* controller =
500       Shell::GetInstance()->GetPrimaryRootWindowController();
501   aura::Window* lock_container =
502       controller->GetContainer(kShellWindowId_LockScreenContainer);
503   aura::Window* lock_window = Widget::CreateWindowWithParentAndBounds(NULL,
504       lock_container, gfx::Rect(0, 0, 100, 100))->GetNativeView();
505   lock_window->Show();
506   aura::Window* session_window =
507       CreateTestWidget(gfx::Rect(0, 0, 100, 100))->GetNativeView();
508   session_window->Show();
509
510   for (int block_reason = FIRST_BLOCK_REASON;
511        block_reason < NUMBER_OF_BLOCK_REASONS;
512        ++block_reason) {
513     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
514     lock_window->Focus();
515     EXPECT_TRUE(lock_window->HasFocus());
516     session_window->Focus();
517     EXPECT_FALSE(session_window->HasFocus());
518     UnblockUserSession();
519   }
520 }
521
522 // Tracks whether OnWindowDestroying() has been invoked.
523 class DestroyedWindowObserver : public aura::WindowObserver {
524  public:
525   DestroyedWindowObserver() : destroyed_(false), window_(NULL) {}
526   virtual ~DestroyedWindowObserver() {
527     Shutdown();
528   }
529
530   void SetWindow(Window* window) {
531     window_ = window;
532     window->AddObserver(this);
533   }
534
535   bool destroyed() const { return destroyed_; }
536
537   // WindowObserver overrides:
538   virtual void OnWindowDestroying(Window* window) OVERRIDE {
539     destroyed_ = true;
540     Shutdown();
541   }
542
543  private:
544   void Shutdown() {
545     if (!window_)
546       return;
547     window_->RemoveObserver(this);
548     window_ = NULL;
549   }
550
551   bool destroyed_;
552   Window* window_;
553
554   DISALLOW_COPY_AND_ASSIGN(DestroyedWindowObserver);
555 };
556
557 // Verifies shutdown doesn't delete windows that are not owned by the parent.
558 TEST_F(RootWindowControllerTest, DontDeleteWindowsNotOwnedByParent) {
559   DestroyedWindowObserver observer1;
560   aura::test::TestWindowDelegate delegate1;
561   aura::Window* window1 = new aura::Window(&delegate1);
562   window1->SetType(ui::wm::WINDOW_TYPE_CONTROL);
563   window1->set_owned_by_parent(false);
564   observer1.SetWindow(window1);
565   window1->Init(aura::WINDOW_LAYER_NOT_DRAWN);
566   aura::client::ParentWindowWithContext(
567       window1, Shell::GetInstance()->GetPrimaryRootWindow(), gfx::Rect());
568
569   DestroyedWindowObserver observer2;
570   aura::Window* window2 = new aura::Window(NULL);
571   window2->set_owned_by_parent(false);
572   observer2.SetWindow(window2);
573   window2->Init(aura::WINDOW_LAYER_NOT_DRAWN);
574   Shell::GetInstance()->GetPrimaryRootWindow()->AddChild(window2);
575
576   Shell::GetInstance()->GetPrimaryRootWindowController()->CloseChildWindows();
577
578   ASSERT_FALSE(observer1.destroyed());
579   delete window1;
580
581   ASSERT_FALSE(observer2.destroyed());
582   delete window2;
583 }
584
585 typedef test::NoSessionAshTestBase NoSessionRootWindowControllerTest;
586
587 // Make sure that an event handler exists for entire display area.
588 TEST_F(NoSessionRootWindowControllerTest, Event) {
589   aura::Window* root = Shell::GetPrimaryRootWindow();
590   const gfx::Size size = root->bounds().size();
591   aura::Window* event_target = root->GetEventHandlerForPoint(gfx::Point(0, 0));
592   EXPECT_TRUE(event_target);
593   EXPECT_EQ(event_target,
594             root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
595   EXPECT_EQ(event_target,
596             root->GetEventHandlerForPoint(gfx::Point(size.width() - 1, 0)));
597   EXPECT_EQ(event_target,
598             root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
599   EXPECT_EQ(event_target,
600             root->GetEventHandlerForPoint(
601                 gfx::Point(size.width() - 1, size.height() - 1)));
602 }
603
604 class VirtualKeyboardRootWindowControllerTest : public RootWindowControllerTest
605 {
606  public:
607   VirtualKeyboardRootWindowControllerTest() {};
608   virtual ~VirtualKeyboardRootWindowControllerTest() {};
609
610   virtual void SetUp() OVERRIDE {
611     CommandLine::ForCurrentProcess()->AppendSwitch(
612         keyboard::switches::kEnableVirtualKeyboard);
613     test::AshTestBase::SetUp();
614     Shell::GetPrimaryRootWindowController()->ActivateKeyboard(
615         keyboard::KeyboardController::GetInstance());
616   }
617
618  private:
619   DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardRootWindowControllerTest);
620 };
621
622 class MockTextInputClient : public ui::DummyTextInputClient {
623  public:
624   MockTextInputClient() :
625       ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT) {}
626
627   virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {
628     visible_rect_ = rect;
629   }
630
631   const gfx::Rect& visible_rect() const {
632     return visible_rect_;
633   }
634
635  private:
636   gfx::Rect visible_rect_;
637
638   DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
639 };
640
641 // Test for http://crbug.com/297858. Virtual keyboard container should only show
642 // on primary root window.
643 TEST_F(VirtualKeyboardRootWindowControllerTest,
644        VirtualKeyboardOnPrimaryRootWindowOnly) {
645   if (!SupportsMultipleDisplays())
646     return;
647
648   UpdateDisplay("500x500,500x500");
649
650   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
651   aura::Window* primary_root_window = Shell::GetPrimaryRootWindow();
652   aura::Window* secondary_root_window =
653       root_windows[0] == primary_root_window ?
654           root_windows[1] : root_windows[0];
655
656   ASSERT_TRUE(Shell::GetContainer(primary_root_window,
657                                   kShellWindowId_VirtualKeyboardContainer));
658   ASSERT_FALSE(Shell::GetContainer(secondary_root_window,
659                                    kShellWindowId_VirtualKeyboardContainer));
660 }
661
662 // Test for http://crbug.com/263599. Virtual keyboard should be able to receive
663 // events at blocked user session.
664 TEST_F(VirtualKeyboardRootWindowControllerTest,
665        ClickVirtualKeyboardInBlockedWindow) {
666   aura::Window* root_window = Shell::GetPrimaryRootWindow();
667   aura::Window* keyboard_container =
668       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
669   ASSERT_TRUE(keyboard_container);
670   keyboard_container->Show();
671
672   aura::Window* keyboard_window = keyboard::KeyboardController::GetInstance()->
673       proxy()->GetKeyboardWindow();
674   keyboard_container->AddChild(keyboard_window);
675   keyboard_window->set_owned_by_parent(false);
676   keyboard_window->SetBounds(gfx::Rect());
677   keyboard_window->Show();
678
679   ui::test::TestEventHandler handler;
680   root_window->AddPreTargetHandler(&handler);
681
682   aura::test::EventGenerator event_generator(root_window, keyboard_window);
683   event_generator.ClickLeftButton();
684   int expected_mouse_presses = 1;
685   EXPECT_EQ(expected_mouse_presses, handler.num_mouse_events() / 2);
686
687   for (int block_reason = FIRST_BLOCK_REASON;
688        block_reason < NUMBER_OF_BLOCK_REASONS;
689        ++block_reason) {
690     BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
691     event_generator.ClickLeftButton();
692     expected_mouse_presses++;
693     EXPECT_EQ(expected_mouse_presses, handler.num_mouse_events() / 2);
694     UnblockUserSession();
695   }
696   root_window->RemovePreTargetHandler(&handler);
697 }
698
699 // Test for http://crbug.com/299787. RootWindowController should delete
700 // the old container since the keyboard controller creates a new window in
701 // GetWindowContainer().
702 TEST_F(VirtualKeyboardRootWindowControllerTest,
703        DeleteOldContainerOnVirtualKeyboardInit) {
704   aura::Window* root_window = Shell::GetPrimaryRootWindow();
705   aura::Window* keyboard_container =
706       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
707   ASSERT_TRUE(keyboard_container);
708   // Track the keyboard container window.
709   aura::WindowTracker tracker;
710   tracker.Add(keyboard_container);
711   // Mock a login user profile change to reinitialize the keyboard.
712   ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
713   // keyboard_container should no longer be present.
714   EXPECT_FALSE(tracker.Contains(keyboard_container));
715 }
716
717 // Test for crbug.com/342524. After user login, the work space should restore to
718 // full screen.
719 TEST_F(VirtualKeyboardRootWindowControllerTest, RestoreWorkspaceAfterLogin) {
720   aura::Window* root_window = Shell::GetPrimaryRootWindow();
721   aura::Window* keyboard_container =
722       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
723   keyboard_container->Show();
724   keyboard::KeyboardController* controller =
725       keyboard::KeyboardController::GetInstance();
726   aura::Window* keyboard_window = controller->proxy()->GetKeyboardWindow();
727   keyboard_container->AddChild(keyboard_window);
728   keyboard_window->set_owned_by_parent(false);
729   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
730       keyboard_container->bounds(), 100));
731   keyboard_window->Show();
732
733   gfx::Rect before = ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
734
735   // Notify keyboard bounds changing.
736   controller->NotifyKeyboardBoundsChanging(
737       controller->proxy()->GetKeyboardWindow()->bounds());
738
739   if (!keyboard::IsKeyboardOverscrollEnabled()) {
740     gfx::Rect after = ash::Shell::GetScreen()->GetPrimaryDisplay().work_area();
741     EXPECT_LT(after, before);
742   }
743
744   // Mock a login user profile change to reinitialize the keyboard.
745   ash::Shell::GetInstance()->OnLoginUserProfilePrepared();
746   EXPECT_EQ(ash::Shell::GetScreen()->GetPrimaryDisplay().work_area(), before);
747 }
748
749 // Ensure that system modal dialogs do not block events targeted at the virtual
750 // keyboard.
751 TEST_F(VirtualKeyboardRootWindowControllerTest, ClickWithActiveModalDialog) {
752   aura::Window* root_window = Shell::GetPrimaryRootWindow();
753   aura::Window* keyboard_container =
754       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
755   ASSERT_TRUE(keyboard_container);
756   keyboard_container->Show();
757
758   aura::Window* keyboard_window = keyboard::KeyboardController::GetInstance()->
759       proxy()->GetKeyboardWindow();
760   keyboard_container->AddChild(keyboard_window);
761   keyboard_window->set_owned_by_parent(false);
762   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
763       keyboard_container->bounds(), 100));
764
765   ui::test::TestEventHandler handler;
766   root_window->AddPreTargetHandler(&handler);
767   aura::test::EventGenerator root_window_event_generator(root_window);
768   aura::test::EventGenerator keyboard_event_generator(root_window,
769                                                       keyboard_window);
770
771   views::Widget* modal_widget =
772       CreateModalWidget(gfx::Rect(300, 10, 100, 100));
773
774   // Verify that mouse events to the root window are block with a visble modal
775   // dialog.
776   root_window_event_generator.ClickLeftButton();
777   EXPECT_EQ(0, handler.num_mouse_events());
778
779   // Verify that event dispatch to the virtual keyboard is unblocked.
780   keyboard_event_generator.ClickLeftButton();
781   EXPECT_EQ(1, handler.num_mouse_events() / 2);
782
783   modal_widget->Close();
784
785   // Verify that mouse events are now unblocked to the root window.
786   root_window_event_generator.ClickLeftButton();
787   EXPECT_EQ(2, handler.num_mouse_events() / 2);
788   root_window->RemovePreTargetHandler(&handler);
789 }
790
791 // Ensure that the visible area for scrolling the text caret excludes the
792 // region occluded by the on-screen keyboard.
793 TEST_F(VirtualKeyboardRootWindowControllerTest, EnsureCaretInWorkArea) {
794   keyboard::KeyboardController* keyboard_controller =
795       keyboard::KeyboardController::GetInstance();
796   keyboard::KeyboardControllerProxy* proxy = keyboard_controller->proxy();
797
798   MockTextInputClient text_input_client;
799   ui::InputMethod* input_method = proxy->GetInputMethod();
800   ASSERT_TRUE(input_method);
801   input_method->SetFocusedTextInputClient(&text_input_client);
802
803   aura::Window* root_window = Shell::GetPrimaryRootWindow();
804   aura::Window* keyboard_container =
805       Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
806   ASSERT_TRUE(keyboard_container);
807   keyboard_container->Show();
808
809   const int keyboard_height = 100;
810   aura::Window* keyboard_window =proxy->GetKeyboardWindow();
811   keyboard_container->AddChild(keyboard_window);
812   keyboard_window->set_owned_by_parent(false);
813   keyboard_window->SetBounds(keyboard::KeyboardBoundsFromWindowBounds(
814       keyboard_container->bounds(), keyboard_height));
815
816   proxy->EnsureCaretInWorkArea();
817   ASSERT_EQ(keyboard_container->bounds().width(),
818             text_input_client.visible_rect().width());
819   ASSERT_EQ(keyboard_container->bounds().height() - keyboard_height,
820             text_input_client.visible_rect().height());
821 }
822
823 }  // namespace test
824 }  // namespace ash