- add sources.
[platform/framework/web/crosswalk.git] / src / ash / shell_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/shell.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "ash/ash_switches.h"
11 #include "ash/desktop_background/desktop_background_widget_controller.h"
12 #include "ash/display/mouse_cursor_event_filter.h"
13 #include "ash/drag_drop/drag_drop_controller.h"
14 #include "ash/launcher/launcher.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/session_state_delegate.h"
17 #include "ash/shelf/shelf_layout_manager.h"
18 #include "ash/shelf/shelf_widget.h"
19 #include "ash/shell_delegate.h"
20 #include "ash/shell_window_ids.h"
21 #include "ash/test/ash_test_base.h"
22 #include "ash/test/shell_test_api.h"
23 #include "ash/wm/root_window_layout_manager.h"
24 #include "ash/wm/window_util.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "ui/aura/client/aura_constants.h"
27 #include "ui/aura/root_window.h"
28 #include "ui/aura/window.h"
29 #include "ui/base/models/simple_menu_model.h"
30 #include "ui/gfx/size.h"
31 #include "ui/views/controls/menu/menu_controller.h"
32 #include "ui/views/controls/menu/menu_runner.h"
33 #include "ui/views/widget/widget.h"
34 #include "ui/views/widget/widget_delegate.h"
35 #include "ui/views/window/dialog_delegate.h"
36
37 using aura::RootWindow;
38
39 namespace ash {
40
41 namespace {
42
43 aura::Window* GetDefaultContainer() {
44   return Shell::GetContainer(
45       Shell::GetPrimaryRootWindow(),
46       internal::kShellWindowId_DefaultContainer);
47 }
48
49 aura::Window* GetAlwaysOnTopContainer() {
50   return Shell::GetContainer(
51       Shell::GetPrimaryRootWindow(),
52       internal::kShellWindowId_AlwaysOnTopContainer);
53 }
54
55 // Expect ALL the containers!
56 void ExpectAllContainers() {
57   aura::Window* root_window = Shell::GetPrimaryRootWindow();
58   EXPECT_TRUE(Shell::GetContainer(
59       root_window, internal::kShellWindowId_DesktopBackgroundContainer));
60   EXPECT_TRUE(Shell::GetContainer(
61       root_window, internal::kShellWindowId_DefaultContainer));
62   EXPECT_TRUE(Shell::GetContainer(
63       root_window, internal::kShellWindowId_AlwaysOnTopContainer));
64   EXPECT_TRUE(Shell::GetContainer(
65       root_window, internal::kShellWindowId_PanelContainer));
66   EXPECT_TRUE(Shell::GetContainer(
67       root_window, internal::kShellWindowId_ShelfContainer));
68   EXPECT_TRUE(Shell::GetContainer(
69       root_window, internal::kShellWindowId_SystemModalContainer));
70   EXPECT_TRUE(Shell::GetContainer(
71       root_window, internal::kShellWindowId_LockScreenBackgroundContainer));
72   EXPECT_TRUE(Shell::GetContainer(
73       root_window, internal::kShellWindowId_LockScreenContainer));
74   EXPECT_TRUE(Shell::GetContainer(
75       root_window, internal::kShellWindowId_LockSystemModalContainer));
76   EXPECT_TRUE(Shell::GetContainer(
77       root_window, internal::kShellWindowId_StatusContainer));
78   EXPECT_TRUE(Shell::GetContainer(
79       root_window, internal::kShellWindowId_MenuContainer));
80   EXPECT_TRUE(Shell::GetContainer(
81       root_window, internal::kShellWindowId_DragImageAndTooltipContainer));
82   EXPECT_TRUE(Shell::GetContainer(
83       root_window, internal::kShellWindowId_SettingBubbleContainer));
84   EXPECT_TRUE(Shell::GetContainer(
85       root_window, internal::kShellWindowId_OverlayContainer));
86 }
87
88 class ModalWindow : public views::WidgetDelegateView {
89  public:
90   ModalWindow() {}
91   virtual ~ModalWindow() {}
92
93   // Overridden from views::WidgetDelegate:
94   virtual views::View* GetContentsView() OVERRIDE {
95     return this;
96   }
97   virtual bool CanResize() const OVERRIDE {
98     return true;
99   }
100   virtual base::string16 GetWindowTitle() const OVERRIDE {
101     return ASCIIToUTF16("Modal Window");
102   }
103   virtual ui::ModalType GetModalType() const OVERRIDE {
104     return ui::MODAL_TYPE_SYSTEM;
105   }
106
107  private:
108   DISALLOW_COPY_AND_ASSIGN(ModalWindow);
109 };
110
111 class SimpleMenuDelegate : public ui::SimpleMenuModel::Delegate {
112  public:
113   SimpleMenuDelegate() {}
114   virtual ~SimpleMenuDelegate() {}
115
116   virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
117     return false;
118   }
119
120   virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
121     return true;
122   }
123
124   virtual bool GetAcceleratorForCommandId(
125       int command_id,
126       ui::Accelerator* accelerator) OVERRIDE {
127     return false;
128   }
129
130   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
131   }
132
133  private:
134   DISALLOW_COPY_AND_ASSIGN(SimpleMenuDelegate);
135 };
136
137 }  // namespace
138
139 class ShellTest : public test::AshTestBase {
140  public:
141   views::Widget* CreateTestWindow(views::Widget::InitParams params) {
142     views::Widget* widget = new views::Widget;
143     params.context = CurrentContext();
144     widget->Init(params);
145     return widget;
146   }
147
148   void TestCreateWindow(views::Widget::InitParams::Type type,
149                         bool always_on_top,
150                         aura::Window* expected_container) {
151     views::Widget::InitParams widget_params(type);
152     widget_params.keep_on_top = always_on_top;
153
154     views::Widget* widget = CreateTestWindow(widget_params);
155     widget->Show();
156
157     EXPECT_TRUE(
158         expected_container->Contains(widget->GetNativeWindow()->parent())) <<
159         "TestCreateWindow: type=" << type << ", always_on_top=" <<
160         always_on_top;
161
162     widget->Close();
163   }
164
165   void LockScreenAndVerifyMenuClosed() {
166     // Verify a menu is open before locking.
167     views::MenuController* menu_controller =
168         views::MenuController::GetActiveInstance();
169     DCHECK(menu_controller);
170     EXPECT_EQ(views::MenuController::EXIT_NONE, menu_controller->exit_type());
171
172     // Create a LockScreen window.
173     views::Widget::InitParams widget_params(
174         views::Widget::InitParams::TYPE_WINDOW);
175     SessionStateDelegate* delegate =
176         Shell::GetInstance()->session_state_delegate();
177     delegate->LockScreen();
178     views::Widget* lock_widget = CreateTestWindow(widget_params);
179     ash::Shell::GetContainer(
180         Shell::GetPrimaryRootWindow(),
181         ash::internal::kShellWindowId_LockScreenContainer)->
182         AddChild(lock_widget->GetNativeView());
183     lock_widget->Show();
184     EXPECT_TRUE(delegate->IsScreenLocked());
185     EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
186
187     // Verify menu is closed.
188     EXPECT_NE(views::MenuController::EXIT_NONE, menu_controller->exit_type());
189     lock_widget->Close();
190     delegate->UnlockScreen();
191
192     // In case the menu wasn't closed, cancel the menu to exit the nested menu
193     // run loop so that the test will not time out.
194     menu_controller->CancelAll();
195   }
196 };
197
198 TEST_F(ShellTest, CreateWindow) {
199   // Normal window should be created in default container.
200   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
201                    false,  // always_on_top
202                    GetDefaultContainer());
203   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
204                    false,  // always_on_top
205                    GetDefaultContainer());
206
207   // Always-on-top window and popup are created in always-on-top container.
208   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
209                    true,  // always_on_top
210                    GetAlwaysOnTopContainer());
211   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
212                    true,  // always_on_top
213                    GetAlwaysOnTopContainer());
214 }
215
216 TEST_F(ShellTest, ChangeAlwaysOnTop) {
217   views::Widget::InitParams widget_params(
218       views::Widget::InitParams::TYPE_WINDOW);
219
220   // Creates a normal window
221   views::Widget* widget = CreateTestWindow(widget_params);
222   widget->Show();
223
224   // It should be in default container.
225   EXPECT_TRUE(GetDefaultContainer()->Contains(
226                   widget->GetNativeWindow()->parent()));
227
228   // Flip always-on-top flag.
229   widget->SetAlwaysOnTop(true);
230   // And it should in always on top container now.
231   EXPECT_EQ(GetAlwaysOnTopContainer(), widget->GetNativeWindow()->parent());
232
233   // Flip always-on-top flag.
234   widget->SetAlwaysOnTop(false);
235   // It should go back to default container.
236   EXPECT_TRUE(GetDefaultContainer()->Contains(
237                   widget->GetNativeWindow()->parent()));
238
239   // Set the same always-on-top flag again.
240   widget->SetAlwaysOnTop(false);
241   // Should have no effect and we are still in the default container.
242   EXPECT_TRUE(GetDefaultContainer()->Contains(
243                   widget->GetNativeWindow()->parent()));
244
245   widget->Close();
246 }
247
248 TEST_F(ShellTest, CreateModalWindow) {
249   views::Widget::InitParams widget_params(
250       views::Widget::InitParams::TYPE_WINDOW);
251
252   // Create a normal window.
253   views::Widget* widget = CreateTestWindow(widget_params);
254   widget->Show();
255
256   // It should be in default container.
257   EXPECT_TRUE(GetDefaultContainer()->Contains(
258                   widget->GetNativeWindow()->parent()));
259
260   // Create a modal window.
261   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
262       new ModalWindow(), widget->GetNativeView());
263   modal_widget->Show();
264
265   // It should be in modal container.
266   aura::Window* modal_container = Shell::GetContainer(
267       Shell::GetPrimaryRootWindow(),
268       internal::kShellWindowId_SystemModalContainer);
269   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
270
271   modal_widget->Close();
272   widget->Close();
273 }
274
275 class TestModalDialogDelegate : public views::DialogDelegateView {
276  public:
277   TestModalDialogDelegate() {}
278
279   // Overridden from views::WidgetDelegate:
280   virtual ui::ModalType GetModalType() const OVERRIDE {
281     return ui::MODAL_TYPE_SYSTEM;
282   }
283 };
284
285 TEST_F(ShellTest, CreateLockScreenModalWindow) {
286   views::Widget::InitParams widget_params(
287       views::Widget::InitParams::TYPE_WINDOW);
288
289   // Create a normal window.
290   views::Widget* widget = CreateTestWindow(widget_params);
291   widget->Show();
292   EXPECT_TRUE(widget->GetNativeView()->HasFocus());
293
294   // It should be in default container.
295   EXPECT_TRUE(GetDefaultContainer()->Contains(
296                   widget->GetNativeWindow()->parent()));
297
298   Shell::GetInstance()->session_state_delegate()->LockScreen();
299   // Create a LockScreen window.
300   views::Widget* lock_widget = CreateTestWindow(widget_params);
301   ash::Shell::GetContainer(
302       Shell::GetPrimaryRootWindow(),
303       ash::internal::kShellWindowId_LockScreenContainer)->
304       AddChild(lock_widget->GetNativeView());
305   lock_widget->Show();
306   EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
307
308   // It should be in LockScreen container.
309   aura::Window* lock_screen = Shell::GetContainer(
310       Shell::GetPrimaryRootWindow(),
311       ash::internal::kShellWindowId_LockScreenContainer);
312   EXPECT_EQ(lock_screen, lock_widget->GetNativeWindow()->parent());
313
314   // Create a modal window with a lock window as parent.
315   views::Widget* lock_modal_widget = views::Widget::CreateWindowWithParent(
316       new ModalWindow(), lock_widget->GetNativeView());
317   lock_modal_widget->Show();
318   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
319
320   // It should be in LockScreen modal container.
321   aura::Window* lock_modal_container = Shell::GetContainer(
322       Shell::GetPrimaryRootWindow(),
323       ash::internal::kShellWindowId_LockSystemModalContainer);
324   EXPECT_EQ(lock_modal_container,
325             lock_modal_widget->GetNativeWindow()->parent());
326
327   // Create a modal window with a normal window as parent.
328   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
329       new ModalWindow(), widget->GetNativeView());
330   modal_widget->Show();
331   // Window on lock screen shouldn't lost focus.
332   EXPECT_FALSE(modal_widget->GetNativeView()->HasFocus());
333   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
334
335   // It should be in non-LockScreen modal container.
336   aura::Window* modal_container = Shell::GetContainer(
337       Shell::GetPrimaryRootWindow(),
338       ash::internal::kShellWindowId_SystemModalContainer);
339   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
340
341   // Modal dialog without parent, caused crash see crbug.com/226141
342   views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget(
343       new TestModalDialogDelegate(), CurrentContext(), NULL);
344
345   modal_dialog->Show();
346   EXPECT_FALSE(modal_dialog->GetNativeView()->HasFocus());
347   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
348
349   modal_dialog->Close();
350   modal_widget->Close();
351   modal_widget->Close();
352   lock_modal_widget->Close();
353   lock_widget->Close();
354   widget->Close();
355 }
356
357 TEST_F(ShellTest, IsScreenLocked) {
358   SessionStateDelegate* delegate =
359       Shell::GetInstance()->session_state_delegate();
360   delegate->LockScreen();
361   EXPECT_TRUE(delegate->IsScreenLocked());
362   delegate->UnlockScreen();
363   EXPECT_FALSE(delegate->IsScreenLocked());
364 }
365
366 TEST_F(ShellTest, LockScreenClosesActiveMenu) {
367   SimpleMenuDelegate menu_delegate;
368   scoped_ptr<ui::SimpleMenuModel> menu_model(
369       new ui::SimpleMenuModel(&menu_delegate));
370   menu_model->AddItem(0, ASCIIToUTF16("Menu item"));
371   views::Widget* widget = ash::Shell::GetPrimaryRootWindowController()->
372       wallpaper_controller()->widget();
373   scoped_ptr<views::MenuRunner> menu_runner(
374       new views::MenuRunner(menu_model.get()));
375
376   // When MenuRunner runs a nested loop the LockScreenAndVerifyMenuClosed
377   // command will fire, check the menu state and ensure the nested menu loop
378   // is exited so that the test will terminate.
379   base::MessageLoopForUI::current()->PostTask(FROM_HERE,
380       base::Bind(&ShellTest::LockScreenAndVerifyMenuClosed,
381                  base::Unretained(this)));
382
383   EXPECT_EQ(views::MenuRunner::NORMAL_EXIT,
384       menu_runner->RunMenuAt(widget, NULL, gfx::Rect(),
385         views::MenuItemView::TOPLEFT, ui::MENU_SOURCE_MOUSE,
386         views::MenuRunner::CONTEXT_MENU));
387 }
388
389 TEST_F(ShellTest, ManagedWindowModeBasics) {
390   Shell* shell = Shell::GetInstance();
391   Shell::TestApi test_api(shell);
392
393   // We start with the usual window containers.
394   ExpectAllContainers();
395   // Launcher is visible.
396   ShelfWidget* launcher_widget = Launcher::ForPrimaryDisplay()->shelf_widget();
397   EXPECT_TRUE(launcher_widget->IsVisible());
398   // Launcher is at bottom-left of screen.
399   EXPECT_EQ(0, launcher_widget->GetWindowBoundsInScreen().x());
400   EXPECT_EQ(
401       Shell::GetPrimaryRootWindow()->GetDispatcher()->GetHostSize().height(),
402       launcher_widget->GetWindowBoundsInScreen().bottom());
403   // We have a desktop background but not a bare layer.
404   // TODO (antrim): enable once we find out why it fails component build.
405   //  internal::DesktopBackgroundWidgetController* background =
406   //      Shell::GetPrimaryRootWindow()->
407   //          GetProperty(internal::kWindowDesktopComponent);
408   //  EXPECT_TRUE(background);
409   //  EXPECT_TRUE(background->widget());
410   //  EXPECT_FALSE(background->layer());
411
412   // Create a normal window.  It is not maximized.
413   views::Widget::InitParams widget_params(
414       views::Widget::InitParams::TYPE_WINDOW);
415   widget_params.bounds.SetRect(11, 22, 300, 400);
416   views::Widget* widget = CreateTestWindow(widget_params);
417   widget->Show();
418   EXPECT_FALSE(widget->IsMaximized());
419
420   // Clean up.
421   widget->Close();
422 }
423
424 TEST_F(ShellTest, FullscreenWindowHidesShelf) {
425   ExpectAllContainers();
426
427   // Create a normal window.  It is not maximized.
428   views::Widget::InitParams widget_params(
429       views::Widget::InitParams::TYPE_WINDOW);
430   widget_params.bounds.SetRect(11, 22, 300, 400);
431   views::Widget* widget = CreateTestWindow(widget_params);
432   widget->Show();
433   EXPECT_FALSE(widget->IsMaximized());
434
435   // Shelf defaults to visible.
436   EXPECT_EQ(
437       SHELF_VISIBLE,
438       Shell::GetPrimaryRootWindowController()->
439           GetShelfLayoutManager()->visibility_state());
440
441   // Fullscreen window hides it.
442   widget->SetFullscreen(true);
443   EXPECT_EQ(
444       SHELF_HIDDEN,
445       Shell::GetPrimaryRootWindowController()->
446           GetShelfLayoutManager()->visibility_state());
447
448   // Restoring the window restores it.
449   widget->Restore();
450   EXPECT_EQ(
451       SHELF_VISIBLE,
452       Shell::GetPrimaryRootWindowController()->
453           GetShelfLayoutManager()->visibility_state());
454
455   // Clean up.
456   widget->Close();
457 }
458
459 namespace {
460
461 // Builds the list of parents from |window| to the root. The returned vector is
462 // in reverse order (|window| is first).
463 std::vector<aura::Window*> BuildPathToRoot(aura::Window* window) {
464   std::vector<aura::Window*> results;
465   while (window) {
466     results.push_back(window);
467     window = window->parent();
468   }
469   return results;
470 }
471
472 }  // namespace
473
474 // Various assertions around SetShelfAutoHideBehavior() and
475 // GetShelfAutoHideBehavior().
476 TEST_F(ShellTest, ToggleAutoHide) {
477   scoped_ptr<aura::Window> window(new aura::Window(NULL));
478   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
479   window->SetType(aura::client::WINDOW_TYPE_NORMAL);
480   window->Init(ui::LAYER_TEXTURED);
481   ParentWindowInPrimaryRootWindow(window.get());
482   window->Show();
483   wm::ActivateWindow(window.get());
484
485   Shell* shell = Shell::GetInstance();
486   aura::Window* root_window = Shell::GetPrimaryRootWindow();
487   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
488                                   root_window);
489   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
490             shell->GetShelfAutoHideBehavior(root_window));
491   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
492                                   root_window);
493   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
494             shell->GetShelfAutoHideBehavior(root_window));
495   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
496   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
497             shell->GetShelfAutoHideBehavior(root_window));
498   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
499                                   root_window);
500   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
501             shell->GetShelfAutoHideBehavior(root_window));
502   shell->SetShelfAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
503                                   root_window);
504   EXPECT_EQ(ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER,
505             shell->GetShelfAutoHideBehavior(root_window));
506 }
507
508 TEST_F(ShellTest, TestPreTargetHandlerOrder) {
509   Shell* shell = Shell::GetInstance();
510   Shell::TestApi test_api(shell);
511   test::ShellTestApi shell_test_api(shell);
512
513   const ui::EventHandlerList& handlers = test_api.pre_target_handlers();
514   EXPECT_EQ(handlers[0], shell->mouse_cursor_filter());
515   EXPECT_EQ(handlers[1], shell_test_api.drag_drop_controller());
516 }
517
518 // This verifies WindowObservers are removed when a window is destroyed after
519 // the Shell is destroyed. This scenario (aura::Windows being deleted after the
520 // Shell) occurs if someone is holding a reference to an unparented Window, as
521 // is the case with a RenderWidgetHostViewAura that isn't on screen. As long as
522 // everything is ok, we won't crash. If there is a bug, window's destructor will
523 // notify some deleted object (say VideoDetector or ActivationController) and
524 // this will crash.
525 class ShellTest2 : public test::AshTestBase {
526  public:
527   ShellTest2() {}
528   virtual ~ShellTest2() {}
529
530  protected:
531   scoped_ptr<aura::Window> window_;
532
533  private:
534   DISALLOW_COPY_AND_ASSIGN(ShellTest2);
535 };
536
537 TEST_F(ShellTest2, DontCrashWhenWindowDeleted) {
538   window_.reset(new aura::Window(NULL));
539   window_->Init(ui::LAYER_NOT_DRAWN);
540 }
541
542 }  // namespace ash