focus_cycler_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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. #include "ash/focus_cycler.h"
  5. #include <memory>
  6. #include "ash/shelf/shelf.h"
  7. #include "ash/shelf/shelf_focus_cycler.h"
  8. #include "ash/shelf/shelf_navigation_widget.h"
  9. #include "ash/shelf/shelf_widget.h"
  10. #include "ash/shell.h"
  11. #include "ash/system/status_area_widget.h"
  12. #include "ash/system/status_area_widget_delegate.h"
  13. #include "ash/test/ash_test_base.h"
  14. #include "ash/wm/window_util.h"
  15. #include "ui/aura/test/test_windows.h"
  16. #include "ui/aura/window.h"
  17. #include "ui/aura/window_event_dispatcher.h"
  18. #include "ui/events/test/event_generator.h"
  19. #include "ui/views/accessible_pane_view.h"
  20. #include "ui/views/controls/button/menu_button.h"
  21. #include "ui/views/widget/widget.h"
  22. namespace ash {
  23. using aura::Window;
  24. namespace {
  25. StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate(views::Widget* widget) {
  26. return static_cast<StatusAreaWidgetDelegate*>(widget->GetContentsView());
  27. }
  28. class PanedWidgetDelegate : public views::WidgetDelegate {
  29. public:
  30. PanedWidgetDelegate(views::Widget* widget) : widget_(widget) {}
  31. void SetAccessiblePanes(const std::vector<views::View*>& panes) {
  32. accessible_panes_ = panes;
  33. }
  34. // views::WidgetDelegate:
  35. void GetAccessiblePanes(std::vector<views::View*>* panes) override {
  36. std::copy(accessible_panes_.begin(), accessible_panes_.end(),
  37. std::back_inserter(*panes));
  38. }
  39. views::Widget* GetWidget() override { return widget_; }
  40. const views::Widget* GetWidget() const override { return widget_; }
  41. private:
  42. views::Widget* widget_;
  43. std::vector<views::View*> accessible_panes_;
  44. };
  45. } // namespace
  46. class FocusCyclerTest : public AshTestBase {
  47. public:
  48. FocusCyclerTest() = default;
  49. FocusCyclerTest(const FocusCyclerTest&) = delete;
  50. FocusCyclerTest& operator=(const FocusCyclerTest&) = delete;
  51. void SetUp() override {
  52. AshTestBase::SetUp();
  53. focus_cycler_ = std::make_unique<FocusCycler>();
  54. }
  55. void TearDown() override {
  56. GetStatusAreaWidgetDelegate(GetPrimaryStatusAreaWidget())
  57. ->SetFocusCyclerForTesting(nullptr);
  58. GetPrimaryShelf()->shelf_widget()->SetFocusCycler(nullptr);
  59. focus_cycler_.reset();
  60. AshTestBase::TearDown();
  61. }
  62. protected:
  63. // Setup the system tray focus cycler.
  64. void SetUpTrayFocusCycle() {
  65. views::Widget* system_tray_widget = GetPrimaryStatusAreaWidget();
  66. ASSERT_TRUE(system_tray_widget);
  67. focus_cycler_->AddWidget(system_tray_widget);
  68. GetStatusAreaWidgetDelegate(system_tray_widget)
  69. ->SetFocusCyclerForTesting(focus_cycler());
  70. }
  71. views::Widget* GetPrimaryStatusAreaWidget() {
  72. return GetPrimaryShelf()->GetStatusAreaWidget();
  73. }
  74. FocusCycler* focus_cycler() { return focus_cycler_.get(); }
  75. void InstallFocusCycleOnShelf() {
  76. // Add the shelf.
  77. GetPrimaryShelf()->hotseat_widget()->SetFocusCycler(focus_cycler());
  78. }
  79. private:
  80. std::unique_ptr<FocusCycler> focus_cycler_;
  81. };
  82. TEST_F(FocusCyclerTest, CycleFocusBrowserOnly) {
  83. // Create a single test window.
  84. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  85. wm::ActivateWindow(window0.get());
  86. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  87. // Cycle the window
  88. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  89. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  90. }
  91. TEST_F(FocusCyclerTest, CycleFocusForward) {
  92. SetUpTrayFocusCycle();
  93. InstallFocusCycleOnShelf();
  94. // Create a single test window.
  95. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  96. wm::ActivateWindow(window0.get());
  97. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  98. // Cycle focus to the status area.
  99. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  100. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  101. // Cycle focus to the shelf.
  102. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  103. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  104. // Cycle focus to the browser.
  105. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  106. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  107. }
  108. TEST_F(FocusCyclerTest, CycleFocusBackward) {
  109. SetUpTrayFocusCycle();
  110. InstallFocusCycleOnShelf();
  111. // Create a single test window.
  112. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  113. wm::ActivateWindow(window0.get());
  114. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  115. // Cycle focus to the shelf.
  116. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  117. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  118. // Cycle focus to the status area.
  119. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  120. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  121. // Cycle focus to the browser.
  122. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  123. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  124. }
  125. TEST_F(FocusCyclerTest, CycleFocusForwardBackward) {
  126. SetUpTrayFocusCycle();
  127. InstallFocusCycleOnShelf();
  128. // Create a single test window.
  129. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  130. wm::ActivateWindow(window0.get());
  131. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  132. // Cycle focus to the shelf.
  133. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  134. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  135. // Cycle focus to the status area.
  136. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  137. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  138. // Cycle focus to the browser.
  139. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  140. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  141. // Cycle focus to the status area.
  142. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  143. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  144. // Cycle focus to the shelf.
  145. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  146. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  147. // Cycle focus to the browser.
  148. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  149. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  150. }
  151. TEST_F(FocusCyclerTest, CycleFocusNoBrowser) {
  152. SetUpTrayFocusCycle();
  153. InstallFocusCycleOnShelf();
  154. // Add the shelf and focus it.
  155. focus_cycler()->FocusWidget(GetPrimaryShelf()->hotseat_widget());
  156. // Cycle focus to the status area.
  157. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  158. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  159. // Cycle focus to the shelf.
  160. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  161. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  162. // Cycle focus to the status area.
  163. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  164. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  165. // Cycle focus to the shelf.
  166. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  167. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  168. // Cycle focus to the status area.
  169. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  170. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  171. }
  172. // Tests that focus cycles from the active browser to the status area and back.
  173. TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) {
  174. SetUpTrayFocusCycle();
  175. InstallFocusCycleOnShelf();
  176. GetPrimaryShelf()->hotseat_widget()->Hide();
  177. // Create two test windows.
  178. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  179. std::unique_ptr<Window> window1(CreateTestWindowInShellWithId(1));
  180. wm::ActivateWindow(window1.get());
  181. wm::ActivateWindow(window0.get());
  182. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  183. // Cycle focus to the status area.
  184. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  185. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  186. // Cycle focus to the browser.
  187. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  188. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  189. // Cycle focus to the status area.
  190. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  191. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  192. }
  193. TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) {
  194. SetUpTrayFocusCycle();
  195. InstallFocusCycleOnShelf();
  196. GetPrimaryShelf()->hotseat_widget()->Hide();
  197. // Create a single test window.
  198. std::unique_ptr<Window> window0(CreateTestWindowInShellWithId(0));
  199. wm::ActivateWindow(window0.get());
  200. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  201. // Cycle focus to the status area.
  202. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  203. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  204. // Cycle focus to the browser.
  205. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  206. EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
  207. }
  208. TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) {
  209. SetUpTrayFocusCycle();
  210. InstallFocusCycleOnShelf();
  211. std::unique_ptr<PanedWidgetDelegate> test_widget_delegate;
  212. std::unique_ptr<views::Widget> browser_widget(new views::Widget);
  213. test_widget_delegate =
  214. std::make_unique<PanedWidgetDelegate>(browser_widget.get());
  215. views::Widget::InitParams widget_params(
  216. views::Widget::InitParams::TYPE_WINDOW);
  217. widget_params.delegate = test_widget_delegate.get();
  218. widget_params.ownership =
  219. views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  220. widget_params.context = GetContext();
  221. browser_widget->Init(std::move(widget_params));
  222. browser_widget->Show();
  223. aura::Window* browser_window = browser_widget->GetNativeView();
  224. views::View* root_view = browser_widget->GetRootView();
  225. // pane1 contains view1 and view2, pane2 contains view3 and view4.
  226. views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
  227. root_view->AddChildView(pane1);
  228. views::View* view1 = new views::View;
  229. view1->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  230. pane1->AddChildView(view1);
  231. views::View* view2 = new views::View;
  232. view2->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  233. pane1->AddChildView(view2);
  234. views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
  235. root_view->AddChildView(pane2);
  236. views::View* view3 = new views::View;
  237. view3->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  238. pane2->AddChildView(view3);
  239. views::View* view4 = new views::View;
  240. view4->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  241. pane2->AddChildView(view4);
  242. std::vector<views::View*> panes;
  243. panes.push_back(pane1);
  244. panes.push_back(pane2);
  245. test_widget_delegate->SetAccessiblePanes(panes);
  246. views::FocusManager* focus_manager = browser_widget->GetFocusManager();
  247. // Cycle focus to the status area.
  248. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  249. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  250. // Cycle focus to the shelf.
  251. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  252. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  253. // Cycle focus to the first pane in the browser.
  254. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  255. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  256. EXPECT_EQ(focus_manager->GetFocusedView(), view1);
  257. // Cycle focus to the second pane in the browser.
  258. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  259. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  260. EXPECT_EQ(focus_manager->GetFocusedView(), view3);
  261. // Cycle focus back to the status area.
  262. focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  263. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  264. // Reverse direction - back to the second pane in the browser.
  265. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  266. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  267. EXPECT_EQ(focus_manager->GetFocusedView(), view3);
  268. // Back to the first pane in the browser.
  269. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  270. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  271. EXPECT_EQ(focus_manager->GetFocusedView(), view1);
  272. // Back to the shelf.
  273. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  274. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  275. // Back to the status area.
  276. focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
  277. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  278. // Pressing "Escape" while on the status area should
  279. // deactivate it, and activate the browser window.
  280. PressAndReleaseKey(ui::VKEY_ESCAPE);
  281. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  282. EXPECT_EQ(focus_manager->GetFocusedView(), view1);
  283. // Similarly, pressing "Escape" while on the shelf should do the same thing.
  284. // Focus the navigation widget directly because the shelf has no apps here.
  285. GetPrimaryShelf()->shelf_focus_cycler()->FocusNavigation(false /* last */);
  286. EXPECT_TRUE(GetPrimaryShelf()->navigation_widget()->IsActive());
  287. PressAndReleaseKey(ui::VKEY_ESCAPE);
  288. EXPECT_TRUE(wm::IsActiveWindow(browser_window));
  289. EXPECT_EQ(focus_manager->GetFocusedView(), view1);
  290. }
  291. // Test that when the shelf widget & status area widget are removed, they should
  292. // also be removed from focus cycler.
  293. TEST_F(FocusCyclerTest, RemoveWidgetOnDisplayRemoved) {
  294. // Two displays are added, so two shelf widgets and two status area widgets
  295. // are added to focus cycler.
  296. UpdateDisplay("800x700, 600x500");
  297. // Remove one display. Its shelf widget and status area widget should also be
  298. // removed from focus cycler.
  299. UpdateDisplay("800x700");
  300. // Create a single test window.
  301. std::unique_ptr<Window> window(CreateTestWindowInShellWithId(0));
  302. wm::ActivateWindow(window.get());
  303. EXPECT_TRUE(wm::IsActiveWindow(window.get()));
  304. // Cycle focus to the navigation widget.
  305. Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  306. EXPECT_TRUE(GetPrimaryShelf()->navigation_widget()->IsActive());
  307. // Cycle focus to the hotseat widget.
  308. Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  309. EXPECT_TRUE(GetPrimaryShelf()->hotseat_widget()->IsActive());
  310. // Cycle focus to the status area.
  311. Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  312. EXPECT_TRUE(GetPrimaryStatusAreaWidget()->IsActive());
  313. // Cycle focus should go back to the browser.
  314. Shell::Get()->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
  315. EXPECT_TRUE(wm::IsActiveWindow(window.get()));
  316. }
  317. } // namespace ash