Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / ash / focus_cycler_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/focus_cycler.h"
6
7 #include <memory>
8
9 #include "ash/shelf/shelf.h"
10 #include "ash/shelf/shelf_focus_cycler.h"
11 #include "ash/shelf/shelf_navigation_widget.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/system/status_area_widget.h"
15 #include "ash/system/status_area_widget_delegate.h"
16 #include "ash/test/ash_test_base.h"
17 #include "ash/wm/window_util.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/ranges/algorithm.h"
20 #include "ui/aura/test/test_windows.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_event_dispatcher.h"
23 #include "ui/events/test/event_generator.h"
24 #include "ui/views/accessible_pane_view.h"
25 #include "ui/views/controls/button/menu_button.h"
26 #include "ui/views/widget/widget.h"
27
28 namespace ash {
29
30 using aura::Window;
31
32 namespace {
33
34 StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate(views::Widget* widget) {
35   return static_cast<StatusAreaWidgetDelegate*>(widget->GetContentsView());
36 }
37
38 class PanedWidgetDelegate : public views::WidgetDelegate {
39  public:
40   PanedWidgetDelegate(views::Widget* widget) : widget_(widget) {}
41
42   void SetAccessiblePanes(const std::vector<views::View*>& panes) {
43     accessible_panes_ = panes;
44   }
45
46   // views::WidgetDelegate:
47   void GetAccessiblePanes(std::vector<views::View*>* panes) override {
48     base::ranges::copy(accessible_panes_, std::back_inserter(*panes));
49   }
50   views::Widget* GetWidget() override { return widget_; }
51   const views::Widget* GetWidget() const override { return widget_; }
52
53  private:
54   raw_ptr<views::Widget, DanglingUntriaged | ExperimentalAsh> widget_;
55   std::vector<views::View*> accessible_panes_;
56 };
57
58 }  // namespace
59
60 class FocusCyclerTest : public AshTestBase {
61  public:
62   FocusCyclerTest() = default;
63
64   FocusCyclerTest(const FocusCyclerTest&) = delete;
65   FocusCyclerTest& operator=(const FocusCyclerTest&) = delete;
66
67   void SetUp() override {
68     AshTestBase::SetUp();
69
70     focus_cycler_ = std::make_unique<FocusCycler>();
71   }
72
73   void TearDown() override {
74     GetStatusAreaWidgetDelegate(GetPrimaryStatusAreaWidget())
75         ->SetFocusCyclerForTesting(nullptr);
76
77     GetPrimaryShelf()->shelf_widget()->SetFocusCycler(nullptr);
78
79     focus_cycler_.reset();
80
81     AshTestBase::TearDown();
82   }
83
84  protected:
85   // Setup the system tray focus cycler.
86   void SetUpTrayFocusCycle() {
87     views::Widget* system_tray_widget = GetPrimaryStatusAreaWidget();
88     ASSERT_TRUE(system_tray_widget);
89     focus_cycler_->AddWidget(system_tray_widget);
90     GetStatusAreaWidgetDelegate(system_tray_widget)
91         ->SetFocusCyclerForTesting(focus_cycler());
92   }
93
94   views::Widget* GetPrimaryStatusAreaWidget() {
95     return GetPrimaryShelf()->GetStatusAreaWidget();
96   }
97
98   FocusCycler* focus_cycler() { return focus_cycler_.get(); }
99
100   void InstallFocusCycleOnShelf() {
101     // Add the shelf.
102     GetPrimaryShelf()->hotseat_widget()->SetFocusCycler(focus_cycler());
103   }
104
105  private:
106   std::unique_ptr<FocusCycler> focus_cycler_;
107 };
108
109 TEST_F(FocusCyclerTest, CycleFocusBrowserOnly) {
110   // Create a single test window.
111   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
112   wm::ActivateWindow(window0.get());
113   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
114
115   // Cycle the window
116   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
117   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
118 }
119
120 TEST_F(FocusCyclerTest, CycleFocusForward) {
121   SetUpTrayFocusCycle();
122
123   InstallFocusCycleOnShelf();
124
125   // Create a single test window.
126   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
127   wm::ActivateWindow(window0.get());
128   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
129
130   // Cycle focus to the status area.
131   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
132   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
133
134   // Cycle focus to the shelf.
135   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
136   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
137
138   // Cycle focus to the browser.
139   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
140   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
141 }
142
143 TEST_F(FocusCyclerTest, CycleFocusBackward) {
144   SetUpTrayFocusCycle();
145
146   InstallFocusCycleOnShelf();
147
148   // Create a single test window.
149   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
150   wm::ActivateWindow(window0.get());
151   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
152
153   // Cycle focus to the shelf.
154   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
155   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
156
157   // Cycle focus to the status area.
158   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
159   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
160
161   // Cycle focus to the browser.
162   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
163   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
164 }
165
166 TEST_F(FocusCyclerTest, CycleFocusForwardBackward) {
167   SetUpTrayFocusCycle();
168
169   InstallFocusCycleOnShelf();
170
171   // Create a single test window.
172   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
173   wm::ActivateWindow(window0.get());
174   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
175
176   // Cycle focus to the shelf.
177   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
178   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
179
180   // Cycle focus to the status area.
181   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
182   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
183
184   // Cycle focus to the browser.
185   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
186   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
187
188   // Cycle focus to the status area.
189   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
190   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
191
192   // Cycle focus to the shelf.
193   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
194   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
195
196   // Cycle focus to the browser.
197   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
198   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
199 }
200
201 TEST_F(FocusCyclerTest, CycleFocusNoBrowser) {
202   SetUpTrayFocusCycle();
203
204   InstallFocusCycleOnShelf();
205
206   // Add the shelf and focus it.
207   focus_cycler()->FocusWidget(GetPrimaryShelf()->hotseat_widget());
208
209   // Cycle focus to the status area.
210   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
211   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
212
213   // Cycle focus to the shelf.
214   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
215   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
216
217   // Cycle focus to the status area.
218   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
219   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
220
221   // Cycle focus to the shelf.
222   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
223   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
224
225   // Cycle focus to the status area.
226   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
227   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
228 }
229
230 // Tests that focus cycles from the active browser to the status area and back.
231 TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) {
232   SetUpTrayFocusCycle();
233   InstallFocusCycleOnShelf();
234   GetPrimaryShelf()->hotseat_widget()->Hide();
235
236   // Create two test windows.
237   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
238   std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
239   wm::ActivateWindow(window1.get());
240   wm::ActivateWindow(window0.get());
241   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
242
243   // Cycle focus to the status area.
244   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
245   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
246
247   // Cycle focus to the browser.
248   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
249   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
250
251   // Cycle focus to the status area.
252   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
253   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
254 }
255
256 TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) {
257   SetUpTrayFocusCycle();
258   InstallFocusCycleOnShelf();
259   GetPrimaryShelf()->hotseat_widget()->Hide();
260
261   // Create a single test window.
262   std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
263   wm::ActivateWindow(window0.get());
264   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
265
266   // Cycle focus to the status area.
267   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
268   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
269
270   // Cycle focus to the browser.
271   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
272   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
273 }
274
275 TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) {
276   SetUpTrayFocusCycle();
277
278   InstallFocusCycleOnShelf();
279
280   std::unique_ptr<PanedWidgetDelegate> test_widget_delegate;
281   std::unique_ptr<views::Widget> browser_widget(new views::Widget);
282   test_widget_delegate =
283       std::make_unique<PanedWidgetDelegate>(browser_widget.get());
284   views::Widget::InitParams widget_params(
285       views::Widget::InitParams::TYPE_WINDOW);
286   widget_params.delegate = test_widget_delegate.get();
287   widget_params.ownership =
288       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
289   widget_params.context = GetContext();
290   browser_widget->Init(std::move(widget_params));
291   browser_widget->Show();
292
293   aura::Window* browser_window = browser_widget->GetNativeView();
294
295   views::View* root_view = browser_widget->GetRootView();
296
297   // pane1 contains view1 and view2, pane2 contains view3 and view4.
298   views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
299   root_view->AddChildView(pane1);
300
301   views::View* view1 = new views::View;
302   view1->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
303   pane1->AddChildView(view1);
304
305   views::View* view2 = new views::View;
306   view2->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
307   pane1->AddChildView(view2);
308
309   views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
310   root_view->AddChildView(pane2);
311
312   views::View* view3 = new views::View;
313   view3->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
314   pane2->AddChildView(view3);
315
316   views::View* view4 = new views::View;
317   view4->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
318   pane2->AddChildView(view4);
319
320   std::vector<views::View*> panes;
321   panes.push_back(pane1);
322   panes.push_back(pane2);
323
324   test_widget_delegate->SetAccessiblePanes(panes);
325
326   views::FocusManager* focus_manager = browser_widget->GetFocusManager();
327
328   // Cycle focus to the status area.
329   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
330   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
331
332   // Cycle focus to the shelf.
333   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
334   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
335
336   // Cycle focus to the first pane in the browser.
337   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
338   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
339   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
340
341   // Cycle focus to the second pane in the browser.
342   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
343   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
344   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
345
346   // Cycle focus back to the status area.
347   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
348   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
349
350   // Reverse direction - back to the second pane in the browser.
351   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
352   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
353   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
354
355   // Back to the first pane in the browser.
356   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
357   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
358   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
359
360   // Back to the shelf.
361   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
362   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
363
364   // Back to the status area.
365   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
366   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
367
368   // Pressing "Escape" while on the status area should
369   // deactivate it, and activate the browser window.
370   PressAndReleaseKey(ui::VKEY_ESCAPE);
371   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
372   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
373
374   // Similarly, pressing "Escape" while on the shelf should do the same thing.
375   // Focus the navigation widget directly because the shelf has no apps here.
376   GetPrimaryShelf()->shelf_focus_cycler()->FocusNavigation(false /* last */);
377   EXPECT_TRUE(GetPrimaryShelf()->navigation_widget()->IsActive());
378   PressAndReleaseKey(ui::VKEY_ESCAPE);
379   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
380   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
381 }
382
383 TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes_MoveOntoNext) {
384   SetUpTrayFocusCycle();
385
386   InstallFocusCycleOnShelf();
387
388   std::unique_ptr<views::Widget> browser_widget =
389       std::make_unique<views::Widget>();
390   std::unique_ptr<PanedWidgetDelegate> test_widget_delegate =
391       std::make_unique<PanedWidgetDelegate>(browser_widget.get());
392   views::Widget::InitParams widget_params(
393       views::Widget::InitParams::TYPE_WINDOW);
394   widget_params.delegate = test_widget_delegate.get();
395   widget_params.ownership =
396       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
397
398   widget_params.context = GetContext();
399   browser_widget->Init(std::move(widget_params));
400   browser_widget->Show();
401
402   aura::Window* browser_window = browser_widget->GetNativeView();
403
404   views::View* root_view = browser_widget->GetRootView();
405
406   // pane1 contains view1 and view2, pane2 contains view3 and view4.
407   views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
408   root_view->AddChildView(pane1);
409
410   views::View* view1 = new views::View();
411   view1->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
412   pane1->AddChildView(view1);
413
414   views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
415   root_view->AddChildView(pane2);
416
417   views::View* view2 = new views::View();
418   view2->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
419   pane2->AddChildView(view2);
420
421   test_widget_delegate->SetAccessiblePanes({pane1, pane2});
422
423   views::FocusManager* focus_manager = browser_widget->GetFocusManager();
424
425   // Cycle focus to the status area.
426   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
427   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
428
429   // Cycle focus to the shelf.
430   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
431   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
432
433   // Cycle focus to the first pane in the browser.
434   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
435   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
436   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
437
438   // Cycle focus back to the status area by asking the focus_cycler to move
439   // onto the next widget. This should skip the next accessible pane.
440   focus_cycler()->RotateFocus(FocusCycler::FORWARD, true);
441   EXPECT_FALSE(wm::IsActiveWindow(browser_window));
442   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
443
444   // Manually deallocate to ensure delegate outlives widget.
445   browser_widget.release();
446   test_widget_delegate.release();
447 }
448
449 // Test that when the shelf widget & status area widget are removed, they should
450 // also be removed from focus cycler.
451 TEST_F(FocusCyclerTest, RemoveWidgetOnDisplayRemoved) {
452   // Two displays are added, so two shelf widgets and two status area widgets
453   // are added to focus cycler.
454   UpdateDisplay("800x700, 600x500");
455   // Remove one display. Its shelf widget and status area widget should also be
456   // removed from focus cycler.
457   UpdateDisplay("800x700");
458
459   // Create a single test window.
460   std::unique_ptr<Window> window(CreateTestWindowInShellWithId(0));
461   wm::ActivateWindow(window.get());
462   EXPECT_TRUE(wm::IsActiveWindow(window.get()));
463
464   // Cycle focus to the navigation widget.
465   Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
466   EXPECT_TRUE(GetPrimaryShelf()->navigation_widget()->IsActive());
467
468   // Cycle focus to the hotseat widget.
469   Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
470   EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
471
472   // Cycle focus to the status area.
473   Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
474   EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
475
476   // Cycle focus should go back to the browser.
477   Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
478   EXPECT_TRUE(wm::IsActiveWindow(window.get()));
479 }
480
481 }  // namespace ash