Fix FullScreen crash in Webapp
[platform/framework/web/chromium-efl.git] / ash / shell_unittest.cc
1 // Copyright 2012 The Chromium Authors
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 <memory>
8 #include <queue>
9 #include <vector>
10
11 #include "ash/accelerators//accelerator_tracker.h"
12 #include "ash/accessibility/chromevox/key_accessibility_enabler.h"
13 #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h"
14 #include "ash/display/mouse_cursor_event_filter.h"
15 #include "ash/drag_drop/drag_drop_controller.h"
16 #include "ash/drag_drop/drag_drop_controller_test_api.h"
17 #include "ash/keyboard/ui/keyboard_ui_controller.h"
18 #include "ash/keyboard/ui/keyboard_util.h"
19 #include "ash/public/cpp/ash_prefs.h"
20 #include "ash/public/cpp/keyboard/keyboard_switches.h"
21 #include "ash/public/cpp/shell_window_ids.h"
22 #include "ash/public/cpp/test/shell_test_api.h"
23 #include "ash/root_window_controller.h"
24 #include "ash/session/session_controller_impl.h"
25 #include "ash/session/test_session_controller_client.h"
26 #include "ash/shelf/home_button.h"
27 #include "ash/shelf/shelf.h"
28 #include "ash/shelf/shelf_layout_manager.h"
29 #include "ash/shelf/shelf_navigation_widget.h"
30 #include "ash/shelf/shelf_widget.h"
31 #include "ash/system/status_area_widget.h"
32 #include "ash/test/ash_test_base.h"
33 #include "ash/test/ash_test_helper.h"
34 #include "ash/test/test_widget_builder.h"
35 #include "ash/test_shell_delegate.h"
36 #include "ash/wallpaper/views/wallpaper_widget_controller.h"
37 #include "ash/wm/desks/desks_util.h"
38 #include "ash/wm/overview/overview_controller.h"
39 #include "base/command_line.h"
40 #include "base/containers/flat_set.h"
41 #include "base/ranges/algorithm.h"
42 #include "base/strings/utf_string_conversions.h"
43 #include "components/account_id/account_id.h"
44 #include "ui/aura/env.h"
45 #include "ui/aura/window.h"
46 #include "ui/aura/window_event_dispatcher.h"
47 #include "ui/base/models/simple_menu_model.h"
48 #include "ui/display/scoped_display_for_new_windows.h"
49 #include "ui/events/test/event_generator.h"
50 #include "ui/events/test/events_test_utils.h"
51 #include "ui/events/test/test_event_handler.h"
52 #include "ui/gfx/geometry/size.h"
53 #include "ui/views/controls/menu/menu_controller.h"
54 #include "ui/views/controls/menu/menu_runner.h"
55 #include "ui/views/widget/widget.h"
56 #include "ui/views/widget/widget_delegate.h"
57 #include "ui/views/window/dialog_delegate.h"
58 #include "ui/wm/core/accelerator_filter.h"
59
60 using aura::RootWindow;
61
62 namespace ash {
63
64 namespace {
65
66 aura::Window* GetActiveDeskContainer() {
67   return Shell::GetContainer(Shell::GetPrimaryRootWindow(),
68                              desks_util::GetActiveDeskContainerId());
69 }
70
71 aura::Window* GetAlwaysOnTopContainer() {
72   return Shell::GetContainer(Shell::GetPrimaryRootWindow(),
73                              kShellWindowId_AlwaysOnTopContainer);
74 }
75
76 // Expect ALL the containers!
77 void ExpectAllContainers() {
78   aura::Window* root_window = Shell::GetPrimaryRootWindow();
79
80   // Validate no duplicate container IDs.
81   base::flat_set<int> container_ids;
82   std::queue<aura::Window*> window_queue;
83   window_queue.push(root_window);
84   while (!window_queue.empty()) {
85     aura::Window* current_window = window_queue.front();
86     window_queue.pop();
87     for (aura::Window* child : current_window->children())
88       window_queue.push(child);
89
90     const int id = current_window->GetId();
91
92     // Skip windows with no IDs.
93     if (id == aura::Window::kInitialId)
94       continue;
95
96     EXPECT_TRUE(container_ids.insert(id).second)
97         << "Found duplicate ID: " << id
98         << " at window: " << current_window->GetName();
99   }
100
101   EXPECT_TRUE(
102       Shell::GetContainer(root_window, kShellWindowId_WallpaperContainer));
103
104   for (int desk_id : desks_util::GetDesksContainersIds())
105     EXPECT_TRUE(Shell::GetContainer(root_window, desk_id));
106
107   EXPECT_TRUE(
108       Shell::GetContainer(root_window, kShellWindowId_AlwaysOnTopContainer));
109   EXPECT_TRUE(Shell::GetContainer(root_window, kShellWindowId_ShelfContainer));
110   EXPECT_TRUE(
111       Shell::GetContainer(root_window, kShellWindowId_SystemModalContainer));
112   EXPECT_TRUE(Shell::GetContainer(root_window,
113                                   kShellWindowId_LockScreenWallpaperContainer));
114   EXPECT_TRUE(
115       Shell::GetContainer(root_window, kShellWindowId_LockScreenContainer));
116   EXPECT_TRUE(Shell::GetContainer(root_window,
117                                   kShellWindowId_LockSystemModalContainer));
118   EXPECT_TRUE(Shell::GetContainer(root_window, kShellWindowId_MenuContainer));
119   EXPECT_TRUE(Shell::GetContainer(root_window,
120                                   kShellWindowId_DragImageAndTooltipContainer));
121   EXPECT_TRUE(
122       Shell::GetContainer(root_window, kShellWindowId_SettingBubbleContainer));
123   EXPECT_TRUE(
124       Shell::GetContainer(root_window, kShellWindowId_OverlayContainer));
125   EXPECT_TRUE(Shell::GetContainer(root_window,
126                                   kShellWindowId_ImeWindowParentContainer));
127   EXPECT_TRUE(Shell::GetContainer(root_window,
128                                   kShellWindowId_VirtualKeyboardContainer));
129   EXPECT_TRUE(
130       Shell::GetContainer(root_window, kShellWindowId_MouseCursorContainer));
131
132   // Phantom window is not a container.
133   EXPECT_EQ(0u, container_ids.count(kShellWindowId_PhantomWindow));
134   EXPECT_FALSE(Shell::GetContainer(root_window, kShellWindowId_PhantomWindow));
135 }
136
137 std::unique_ptr<views::WidgetDelegateView> CreateModalWidgetDelegate() {
138   auto delegate = std::make_unique<views::WidgetDelegateView>();
139   delegate->SetCanResize(true);
140   delegate->SetModalType(ui::MODAL_TYPE_SYSTEM);
141   delegate->SetOwnedByWidget(true);
142   delegate->SetTitle(u"Modal Window");
143   return delegate;
144 }
145
146 class SimpleMenuDelegate : public ui::SimpleMenuModel::Delegate {
147  public:
148   SimpleMenuDelegate() = default;
149
150   SimpleMenuDelegate(const SimpleMenuDelegate&) = delete;
151   SimpleMenuDelegate& operator=(const SimpleMenuDelegate&) = delete;
152
153   ~SimpleMenuDelegate() override = default;
154
155   bool IsCommandIdChecked(int command_id) const override { return false; }
156
157   bool IsCommandIdEnabled(int command_id) const override { return true; }
158
159   void ExecuteCommand(int command_id, int event_flags) override {}
160 };
161
162 }  // namespace
163
164 class ShellTest : public AshTestBase {
165  public:
166   void TestCreateWindow(views::Widget::InitParams::Type type,
167                         bool always_on_top,
168                         aura::Window* expected_container) {
169     TestWidgetBuilder builder;
170     if (always_on_top)
171       builder.SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
172     views::Widget* widget =
173         builder.SetWidgetType(type).BuildOwnedByNativeWidget();
174
175     EXPECT_TRUE(
176         expected_container->Contains(widget->GetNativeWindow()->parent()))
177         << "TestCreateWindow: type=" << type
178         << ", always_on_top=" << always_on_top;
179
180     widget->Close();
181   }
182
183   void LockScreenAndVerifyMenuClosed() {
184     // Verify a menu is open before locking.
185     views::MenuController* menu_controller =
186         views::MenuController::GetActiveInstance();
187     DCHECK(menu_controller);
188     EXPECT_EQ(views::MenuController::ExitType::kNone,
189               menu_controller->exit_type());
190
191     // Create a LockScreen window.
192     views::Widget* lock_widget =
193         TestWidgetBuilder()
194             .SetWidgetType(views::Widget::InitParams::TYPE_WINDOW)
195             .SetShow(false)
196             .BuildOwnedByNativeWidget();
197     Shell::GetContainer(Shell::GetPrimaryRootWindow(),
198                         kShellWindowId_LockScreenContainer)
199         ->AddChild(lock_widget->GetNativeView());
200     lock_widget->Show();
201
202     // Simulate real screen locker to change session state to LOCKED
203     // when it is shown.
204     GetSessionControllerClient()->LockScreen();
205
206     SessionControllerImpl* controller = Shell::Get()->session_controller();
207     EXPECT_TRUE(controller->IsScreenLocked());
208     EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
209
210     // Verify menu is closed.
211     EXPECT_EQ(nullptr, views::MenuController::GetActiveInstance());
212     lock_widget->Close();
213     GetSessionControllerClient()->UnlockScreen();
214   }
215 };
216
217 TEST_F(ShellTest, CreateWindow) {
218   // Normal window should be created in default container.
219   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
220                    false,  // always_on_top
221                    GetActiveDeskContainer());
222   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
223                    false,  // always_on_top
224                    GetActiveDeskContainer());
225
226   // Always-on-top window and popup are created in always-on-top container.
227   TestCreateWindow(views::Widget::InitParams::TYPE_WINDOW,
228                    true,  // always_on_top
229                    GetAlwaysOnTopContainer());
230   TestCreateWindow(views::Widget::InitParams::TYPE_POPUP,
231                    true,  // always_on_top
232                    GetAlwaysOnTopContainer());
233 }
234
235 // Verifies that a window with a preferred size is created centered on the
236 // default display for new windows. Mojo apps like shortcut_viewer rely on this
237 // behavior.
238 TEST_F(ShellTest, CreateWindowWithPreferredSize) {
239   UpdateDisplay("1024x768,800x600");
240
241   aura::Window* secondary_root = Shell::GetAllRootWindows()[1];
242   display::ScopedDisplayForNewWindows scoped_display(secondary_root);
243
244   views::Widget::InitParams params;
245   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
246   // Don't specify bounds, parent or context.
247   {
248     auto delegate = std::make_unique<views::WidgetDelegateView>();
249     delegate->SetPreferredSize(gfx::Size(400, 300));
250     params.delegate = delegate.release();
251   }
252   views::Widget widget;
253   params.context = GetContext();
254   widget.Init(std::move(params));
255
256   // Widget is centered on secondary display.
257   EXPECT_EQ(secondary_root, widget.GetNativeWindow()->GetRootWindow());
258   EXPECT_EQ(GetSecondaryDisplay().work_area().CenterPoint(),
259             widget.GetRestoredBounds().CenterPoint());
260 }
261
262 TEST_F(ShellTest, ChangeZOrderLevel) {
263   // Creates a normal window.
264   views::Widget* widget = TestWidgetBuilder().BuildOwnedByNativeWidget();
265
266   // It should be in the active desk container.
267   EXPECT_TRUE(
268       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
269
270   // Set the z-order to float.
271   widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
272   // And it should in always on top container now.
273   EXPECT_EQ(GetAlwaysOnTopContainer(), widget->GetNativeWindow()->parent());
274
275   // Put the z-order back to normal.
276   widget->SetZOrderLevel(ui::ZOrderLevel::kNormal);
277   // It should go back to the active desk container.
278   EXPECT_TRUE(
279       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
280
281   // Set the z-order again to the normal value.
282   widget->SetZOrderLevel(ui::ZOrderLevel::kNormal);
283   // Should have no effect and we are still in the the active desk container.
284   EXPECT_TRUE(
285       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
286
287   widget->Close();
288 }
289
290 TEST_F(ShellTest, CreateModalWindow) {
291   // Create a normal window.
292   views::Widget* widget = TestWidgetBuilder().BuildOwnedByNativeWidget();
293
294   // It should be in the active desk container.
295   EXPECT_TRUE(
296       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
297
298   // Create a modal window.
299   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
300       CreateModalWidgetDelegate(), widget->GetNativeView());
301   modal_widget->Show();
302
303   // It should be in modal container.
304   aura::Window* modal_container = Shell::GetContainer(
305       Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer);
306   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
307
308   modal_widget->Close();
309   widget->Close();
310 }
311
312 TEST_F(ShellTest, CreateLockScreenModalWindow) {
313   // Create a normal window.
314   views::Widget* widget = TestWidgetBuilder().BuildOwnedByNativeWidget();
315   EXPECT_TRUE(widget->GetNativeView()->HasFocus());
316
317   // It should be in the active desk container.
318   EXPECT_TRUE(
319       GetActiveDeskContainer()->Contains(widget->GetNativeWindow()->parent()));
320
321   GetSessionControllerClient()->LockScreen();
322   // Create a LockScreen window.
323   views::Widget* lock_widget =
324       TestWidgetBuilder().SetShow(false).BuildOwnedByNativeWidget();
325   Shell::GetContainer(Shell::GetPrimaryRootWindow(),
326                       kShellWindowId_LockScreenContainer)
327       ->AddChild(lock_widget->GetNativeView());
328   lock_widget->Show();
329   EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
330
331   // It should be in LockScreen container.
332   aura::Window* lock_screen = Shell::GetContainer(
333       Shell::GetPrimaryRootWindow(), kShellWindowId_LockScreenContainer);
334   EXPECT_EQ(lock_screen, lock_widget->GetNativeWindow()->parent());
335
336   // Create a modal window with a lock window as parent.
337   views::Widget* lock_modal_widget = views::Widget::CreateWindowWithParent(
338       CreateModalWidgetDelegate(), lock_widget->GetNativeView());
339   lock_modal_widget->Show();
340   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
341
342   // It should be in LockScreen modal container.
343   aura::Window* lock_modal_container =
344       Shell::GetContainer(Shell::GetPrimaryRootWindow(),
345                           kShellWindowId_LockSystemModalContainer);
346   EXPECT_EQ(lock_modal_container,
347             lock_modal_widget->GetNativeWindow()->parent());
348
349   // Create a modal window with a normal window as parent.
350   views::Widget* modal_widget = views::Widget::CreateWindowWithParent(
351       CreateModalWidgetDelegate(), widget->GetNativeView());
352   modal_widget->Show();
353   // Window on lock screen shouldn't lost focus.
354   EXPECT_FALSE(modal_widget->GetNativeView()->HasFocus());
355   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
356
357   // It should be in non-LockScreen modal container.
358   aura::Window* modal_container = Shell::GetContainer(
359       Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer);
360   EXPECT_EQ(modal_container, modal_widget->GetNativeWindow()->parent());
361
362   // Modal widget without parent, caused crash see crbug.com/226141
363   views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget(
364       CreateModalWidgetDelegate(), GetContext(), nullptr);
365
366   modal_dialog->Show();
367   EXPECT_FALSE(modal_dialog->GetNativeView()->HasFocus());
368   EXPECT_TRUE(lock_modal_widget->GetNativeView()->HasFocus());
369
370   modal_dialog->Close();
371   modal_widget->Close();
372   modal_widget->Close();
373   lock_modal_widget->Close();
374   lock_widget->Close();
375   widget->Close();
376 }
377
378 TEST_F(ShellTest, IsScreenLocked) {
379   SessionControllerImpl* controller = Shell::Get()->session_controller();
380   GetSessionControllerClient()->LockScreen();
381   EXPECT_TRUE(controller->IsScreenLocked());
382   GetSessionControllerClient()->UnlockScreen();
383   EXPECT_FALSE(controller->IsScreenLocked());
384 }
385
386 TEST_F(ShellTest, LockScreenClosesActiveMenu) {
387   SimpleMenuDelegate menu_delegate;
388   std::unique_ptr<ui::SimpleMenuModel> menu_model(
389       new ui::SimpleMenuModel(&menu_delegate));
390   menu_model->AddItem(0, u"Menu item");
391   views::Widget* widget = Shell::GetPrimaryRootWindowController()
392                               ->wallpaper_widget_controller()
393                               ->GetWidget();
394   std::unique_ptr<views::MenuRunner> menu_runner(
395       new views::MenuRunner(menu_model.get(), views::MenuRunner::CONTEXT_MENU));
396
397   menu_runner->RunMenuAt(widget, nullptr, gfx::Rect(),
398                          views::MenuAnchorPosition::kTopLeft,
399                          ui::MENU_SOURCE_MOUSE);
400   LockScreenAndVerifyMenuClosed();
401 }
402
403 TEST_F(ShellTest, ManagedWindowModeBasics) {
404   // We start with the usual window containers.
405   ExpectAllContainers();
406   // Shelf is visible.
407   ShelfWidget* shelf_widget = GetPrimaryShelf()->shelf_widget();
408   EXPECT_TRUE(shelf_widget->IsVisible());
409   // Shelf is at bottom-left of screen.
410   EXPECT_EQ(0, shelf_widget->GetWindowBoundsInScreen().x());
411   EXPECT_EQ(
412       Shell::GetPrimaryRootWindow()->GetHost()->GetBoundsInPixels().height(),
413       shelf_widget->GetWindowBoundsInScreen().bottom());
414   // We have a wallpaper but not a bare layer.
415   // TODO (antrim): enable once we find out why it fails component build.
416   //  WallpaperWidgetController* wallpaper =
417   //      Shell::GetPrimaryRootWindow()->
418   //          GetProperty(kWindowDesktopComponent);
419   //  EXPECT_TRUE(wallpaper);
420   //  EXPECT_TRUE(wallpaper->widget());
421   //  EXPECT_FALSE(wallpaper->layer());
422
423   // Create a normal window.  It is not maximized.
424   views::Widget* widget = TestWidgetBuilder()
425                               .SetBounds(gfx::Rect(11, 22, 300, 400))
426                               .BuildOwnedByNativeWidget();
427   EXPECT_FALSE(widget->IsMaximized());
428
429   // Clean up.
430   widget->Close();
431 }
432
433 // Tests that the cursor-filter is ahead of the drag-drop controller in the
434 // pre-target list.
435 TEST_F(ShellTest, TestPreTargetHandlerOrder) {
436   Shell* shell = Shell::Get();
437   ui::EventTargetTestApi test_api(shell);
438   ShellTestApi shell_test_api;
439
440   ui::EventHandlerList handlers = test_api.GetPreTargetHandlers();
441   ui::EventHandlerList::const_iterator cursor_filter =
442       base::ranges::find(handlers, shell->mouse_cursor_filter());
443   ui::EventHandlerList::const_iterator drag_drop =
444       base::ranges::find(handlers, shell_test_api.drag_drop_controller());
445   EXPECT_NE(handlers.end(), cursor_filter);
446   EXPECT_NE(handlers.end(), drag_drop);
447   EXPECT_GT(drag_drop, cursor_filter);
448 }
449
450 // Tests that the accelerator_tracker is ahead of the accelerator_filter in the
451 // pre-target list to make sure the accelerators won't be filtered out before
452 // getting AcceleratorTracker.
453 TEST_F(ShellTest, AcceleratorPreTargetHandlerOrder) {
454   Shell* shell = Shell::Get();
455   ui::EventTargetTestApi test_api(shell);
456
457   ui::EventHandlerList handlers = test_api.GetPreTargetHandlers();
458   ui::EventHandlerList::const_iterator accelerator_tracker =
459       base::ranges::find(handlers, shell->accelerator_tracker());
460   ui::EventHandlerList::const_iterator accelerator_filter =
461       base::ranges::find(handlers, shell->accelerator_filter());
462   EXPECT_NE(handlers.end(), accelerator_tracker);
463   EXPECT_NE(handlers.end(), accelerator_filter);
464   EXPECT_GT(accelerator_filter, accelerator_tracker);
465 }
466
467 TEST_F(ShellTest, TestAccessibilityHandlerOrder) {
468   Shell* shell = Shell::Get();
469   ui::EventTargetTestApi test_api(shell);
470   ShellTestApi shell_test_api;
471
472   ui::EventHandler select_to_speak;
473   shell->AddAccessibilityEventHandler(
474       &select_to_speak,
475       AccessibilityEventHandlerManager::HandlerType::kSelectToSpeak);
476
477   // Check ordering.
478   ui::EventHandlerList handlers = test_api.GetPreTargetHandlers();
479
480   ui::EventHandlerList::const_iterator cursor_filter =
481       base::ranges::find(handlers, shell->mouse_cursor_filter());
482   ui::EventHandlerList::const_iterator fullscreen_magnifier_filter =
483       base::ranges::find(handlers, shell->fullscreen_magnifier_controller());
484   ui::EventHandlerList::const_iterator chromevox_filter =
485       base::ranges::find(handlers, shell->key_accessibility_enabler());
486   ui::EventHandlerList::const_iterator select_to_speak_filter =
487       base::ranges::find(handlers, &select_to_speak);
488   EXPECT_NE(handlers.end(), cursor_filter);
489   EXPECT_NE(handlers.end(), fullscreen_magnifier_filter);
490   EXPECT_NE(handlers.end(), chromevox_filter);
491   EXPECT_NE(handlers.end(), select_to_speak_filter);
492
493   EXPECT_LT(cursor_filter, fullscreen_magnifier_filter);
494   EXPECT_LT(fullscreen_magnifier_filter, chromevox_filter);
495   EXPECT_LT(chromevox_filter, select_to_speak_filter);
496
497   // Removing works.
498   shell->RemoveAccessibilityEventHandler(&select_to_speak);
499
500   handlers = test_api.GetPreTargetHandlers();
501   cursor_filter = base::ranges::find(handlers, shell->mouse_cursor_filter());
502   fullscreen_magnifier_filter =
503       base::ranges::find(handlers, shell->fullscreen_magnifier_controller());
504   chromevox_filter =
505       base::ranges::find(handlers, shell->key_accessibility_enabler());
506   select_to_speak_filter = base::ranges::find(handlers, &select_to_speak);
507   EXPECT_NE(handlers.end(), cursor_filter);
508   EXPECT_NE(handlers.end(), fullscreen_magnifier_filter);
509   EXPECT_NE(handlers.end(), chromevox_filter);
510   EXPECT_EQ(handlers.end(), select_to_speak_filter);
511
512   // Ordering still works.
513   EXPECT_LT(cursor_filter, fullscreen_magnifier_filter);
514   EXPECT_LT(fullscreen_magnifier_filter, chromevox_filter);
515
516   // Adding another is correct.
517   ui::EventHandler docked_magnifier;
518   shell->AddAccessibilityEventHandler(
519       &docked_magnifier,
520       AccessibilityEventHandlerManager::HandlerType::kDockedMagnifier);
521
522   handlers = test_api.GetPreTargetHandlers();
523   cursor_filter = base::ranges::find(handlers, shell->mouse_cursor_filter());
524   fullscreen_magnifier_filter =
525       base::ranges::find(handlers, shell->fullscreen_magnifier_controller());
526   chromevox_filter =
527       base::ranges::find(handlers, shell->key_accessibility_enabler());
528   ui::EventHandlerList::const_iterator docked_magnifier_filter =
529       base::ranges::find(handlers, &docked_magnifier);
530   EXPECT_NE(handlers.end(), cursor_filter);
531   EXPECT_NE(handlers.end(), fullscreen_magnifier_filter);
532   EXPECT_NE(handlers.end(), docked_magnifier_filter);
533   EXPECT_NE(handlers.end(), chromevox_filter);
534
535   // Inserted in proper order.
536   EXPECT_LT(cursor_filter, fullscreen_magnifier_filter);
537   EXPECT_LT(fullscreen_magnifier_filter, docked_magnifier_filter);
538   EXPECT_LT(docked_magnifier_filter, chromevox_filter);
539 }
540
541 // Verifies an EventHandler added to Env gets notified from EventGenerator.
542 TEST_F(ShellTest, EnvPreTargetHandler) {
543   ui::test::TestEventHandler event_handler;
544   aura::Env::GetInstance()->AddPreTargetHandler(&event_handler);
545   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
546   generator.MoveMouseBy(1, 1);
547   EXPECT_NE(0, event_handler.num_mouse_events());
548   aura::Env::GetInstance()->RemovePreTargetHandler(&event_handler);
549 }
550
551 // Verifies that pressing tab on an empty shell (one with no windows visible)
552 // will put focus on the shelf. This enables keyboard only users to get to the
553 // shelf without knowing the more obscure accelerators. Tab should move focus to
554 // the home button, shift + tab to the status widget. From there, normal shelf
555 // tab behaviour takes over, and the shell no longer catches that event.
556 TEST_F(ShellTest, NoWindowTabFocus) {
557   ExpectAllContainers();
558
559   StatusAreaWidget* status_area_widget =
560       GetPrimaryShelf()->status_area_widget();
561   ShelfNavigationWidget* home_button = GetPrimaryShelf()->navigation_widget();
562
563   // Create a normal window.  It is not maximized.
564   auto widget = CreateTestWidget();
565
566   // Hit tab with window open, and expect that focus is not on the navigation
567   // widget or status widget.
568   PressAndReleaseKey(ui::VKEY_TAB);
569   EXPECT_FALSE(home_button->GetNativeView()->HasFocus());
570   EXPECT_FALSE(status_area_widget->GetNativeView()->HasFocus());
571
572   // Minimize the window, hit tab and expect that focus is on the launcher.
573   widget->Minimize();
574   PressAndReleaseKey(ui::VKEY_TAB);
575   EXPECT_TRUE(home_button->GetNativeView()->HasFocus());
576
577   // Show (to steal focus back before continuing testing) and close the window.
578   widget->Show();
579   widget->Close();
580   EXPECT_FALSE(home_button->GetNativeView()->HasFocus());
581
582   // Confirm that pressing tab when overview mode is open does not go to home
583   // button. Tab should be handled by overview mode and not hit the shell event
584   // handler.
585   EnterOverview();
586   PressAndReleaseKey(ui::VKEY_TAB);
587   EXPECT_FALSE(home_button->GetNativeView()->HasFocus());
588   ExitOverview();
589
590   // Hit shift tab and expect that focus is on status widget.
591   PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
592   EXPECT_TRUE(status_area_widget->GetNativeView()->HasFocus());
593 }
594
595 // This verifies WindowObservers are removed when a window is destroyed after
596 // the Shell is destroyed. This scenario (aura::Windows being deleted after the
597 // Shell) occurs if someone is holding a reference to an unparented Window, as
598 // is the case with a RenderWidgetHostViewAura that isn't on screen. As long as
599 // everything is ok, we won't crash. If there is a bug, window's destructor will
600 // notify some deleted object (say VideoDetector or ActivationController) and
601 // this will crash.
602 class ShellTest2 : public AshTestBase {
603  public:
604   ShellTest2() = default;
605
606   ShellTest2(const ShellTest2&) = delete;
607   ShellTest2& operator=(const ShellTest2&) = delete;
608
609   ~ShellTest2() override = default;
610
611  protected:
612   std::unique_ptr<aura::Window> window_;
613 };
614
615 TEST_F(ShellTest2, DontCrashWhenWindowDeleted) {
616   window_ = std::make_unique<aura::Window>(nullptr,
617                                            aura::client::WINDOW_TYPE_UNKNOWN);
618   window_->Init(ui::LAYER_NOT_DRAWN);
619 }
620
621 using ShellLoginTest = NoSessionAshTestBase;
622
623 TEST_F(ShellLoginTest, DragAndDropDisabledBeforeLogin) {
624   DragDropController* drag_drop_controller =
625       ShellTestApi().drag_drop_controller();
626   DragDropControllerTestApi drag_drop_controller_test_api(drag_drop_controller);
627   EXPECT_FALSE(drag_drop_controller_test_api.enabled());
628
629   SimulateUserLogin("user1@test.com");
630   EXPECT_TRUE(drag_drop_controller_test_api.enabled());
631 }
632
633 using NoDuplicateShellContainerIdsTest = AshTestBase;
634
635 TEST_F(NoDuplicateShellContainerIdsTest, ValidateContainersIds) {
636   ExpectAllContainers();
637 }
638
639 }  // namespace ash