focus_cycler_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/focus_cycler.h" 6 7#include "ash/root_window_controller.h" 8#include "ash/shelf/shelf.h" 9#include "ash/shelf/shelf_widget.h" 10#include "ash/shell.h" 11#include "ash/shell_factory.h" 12#include "ash/shell_window_ids.h" 13#include "ash/system/status_area_widget.h" 14#include "ash/system/status_area_widget_delegate.h" 15#include "ash/system/tray/system_tray.h" 16#include "ash/test/ash_test_base.h" 17#include "ash/wm/window_util.h" 18#include "ui/aura/test/event_generator.h" 19#include "ui/aura/test/test_windows.h" 20#include "ui/aura/window.h" 21#include "ui/aura/window_event_dispatcher.h" 22#include "ui/views/accessible_pane_view.h" 23#include "ui/views/controls/button/menu_button.h" 24#include "ui/views/widget/widget.h" 25 26namespace ash { 27namespace test { 28 29using aura::Window; 30using internal::FocusCycler; 31 32namespace { 33 34internal::StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate( 35 views::Widget* widget) { 36 return static_cast<internal::StatusAreaWidgetDelegate*>( 37 widget->GetContentsView()); 38} 39 40class PanedWidgetDelegate : public views::WidgetDelegate { 41 public: 42 PanedWidgetDelegate(views::Widget* widget) : widget_(widget) {} 43 44 void SetAccessiblePanes(const std::vector<views::View*>& panes) { 45 accessible_panes_ = panes; 46 } 47 48 // views::WidgetDelegate. 49 virtual void GetAccessiblePanes(std::vector<views::View*>* panes) OVERRIDE { 50 std::copy(accessible_panes_.begin(), 51 accessible_panes_.end(), 52 std::back_inserter(*panes)); 53 } 54 virtual views::Widget* GetWidget() OVERRIDE { 55 return widget_; 56 }; 57 virtual const views::Widget* GetWidget() const OVERRIDE { 58 return widget_; 59 } 60 61 private: 62 views::Widget* widget_; 63 std::vector<views::View*> accessible_panes_; 64}; 65 66} // namespace 67 68class FocusCyclerTest : public AshTestBase { 69 public: 70 FocusCyclerTest() {} 71 72 virtual void SetUp() OVERRIDE { 73 AshTestBase::SetUp(); 74 75 focus_cycler_.reset(new FocusCycler()); 76 77 ASSERT_TRUE(Shelf::ForPrimaryDisplay()); 78 } 79 80 virtual void TearDown() OVERRIDE { 81 if (tray_) { 82 GetStatusAreaWidgetDelegate(tray_->GetWidget())-> 83 SetFocusCyclerForTesting(NULL); 84 tray_.reset(); 85 } 86 87 shelf_widget()->SetFocusCycler(NULL); 88 89 focus_cycler_.reset(); 90 91 AshTestBase::TearDown(); 92 } 93 94 protected: 95 // Creates the system tray, returning true on success. 96 bool CreateTray() { 97 if (tray_) 98 return false; 99 aura::Window* parent = Shell::GetPrimaryRootWindowController()-> 100 GetContainer(ash::internal::kShellWindowId_StatusContainer); 101 102 internal::StatusAreaWidget* widget = new internal::StatusAreaWidget(parent); 103 widget->CreateTrayViews(); 104 widget->Show(); 105 tray_.reset(widget->system_tray()); 106 if (!tray_->GetWidget()) 107 return false; 108 focus_cycler_->AddWidget(tray()->GetWidget()); 109 GetStatusAreaWidgetDelegate(tray_->GetWidget())->SetFocusCyclerForTesting( 110 focus_cycler()); 111 return true; 112 } 113 114 FocusCycler* focus_cycler() { return focus_cycler_.get(); } 115 116 SystemTray* tray() { return tray_.get(); } 117 118 ShelfWidget* shelf_widget() { 119 return Shelf::ForPrimaryDisplay()->shelf_widget(); 120 } 121 122 void InstallFocusCycleOnShelf() { 123 // Add the shelf. 124 shelf_widget()->SetFocusCycler(focus_cycler()); 125 } 126 127 private: 128 scoped_ptr<FocusCycler> focus_cycler_; 129 scoped_ptr<SystemTray> tray_; 130 131 DISALLOW_COPY_AND_ASSIGN(FocusCyclerTest); 132}; 133 134TEST_F(FocusCyclerTest, CycleFocusBrowserOnly) { 135 // Create a single test window. 136 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 137 wm::ActivateWindow(window0.get()); 138 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 139 140 // Cycle the window 141 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 142 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 143} 144 145TEST_F(FocusCyclerTest, CycleFocusForward) { 146 ASSERT_TRUE(CreateTray()); 147 148 InstallFocusCycleOnShelf(); 149 150 // Create a single test window. 151 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 152 wm::ActivateWindow(window0.get()); 153 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 154 155 // Cycle focus to the status area. 156 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 157 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 158 159 // Cycle focus to the shelf. 160 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 161 EXPECT_TRUE(shelf_widget()->IsActive()); 162 163 // Cycle focus to the browser. 164 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 165 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 166} 167 168TEST_F(FocusCyclerTest, CycleFocusBackward) { 169 ASSERT_TRUE(CreateTray()); 170 171 InstallFocusCycleOnShelf(); 172 173 // Create a single test window. 174 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 175 wm::ActivateWindow(window0.get()); 176 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 177 178 // Cycle focus to the shelf. 179 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 180 EXPECT_TRUE(shelf_widget()->IsActive()); 181 182 // Cycle focus to the status area. 183 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 184 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 185 186 // Cycle focus to the browser. 187 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 188 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 189} 190 191TEST_F(FocusCyclerTest, CycleFocusForwardBackward) { 192 ASSERT_TRUE(CreateTray()); 193 194 InstallFocusCycleOnShelf(); 195 196 // Create a single test window. 197 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 198 wm::ActivateWindow(window0.get()); 199 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 200 201 // Cycle focus to the shelf. 202 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 203 EXPECT_TRUE(shelf_widget()->IsActive()); 204 205 // Cycle focus to the status area. 206 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 207 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 208 209 // Cycle focus to the browser. 210 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 211 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 212 213 // Cycle focus to the status area. 214 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 215 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 216 217 // Cycle focus to the shelf. 218 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 219 EXPECT_TRUE(shelf_widget()->IsActive()); 220 221 // Cycle focus to the browser. 222 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 223 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 224} 225 226TEST_F(FocusCyclerTest, CycleFocusNoBrowser) { 227 ASSERT_TRUE(CreateTray()); 228 229 InstallFocusCycleOnShelf(); 230 231 // Add the shelf and focus it. 232 focus_cycler()->FocusWidget(shelf_widget()); 233 234 // Cycle focus to the status area. 235 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 236 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 237 238 // Cycle focus to the shelf. 239 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 240 EXPECT_TRUE(shelf_widget()->IsActive()); 241 242 // Cycle focus to the status area. 243 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 244 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 245 246 // Cycle focus to the shelf. 247 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 248 EXPECT_TRUE(shelf_widget()->IsActive()); 249 250 // Cycle focus to the status area. 251 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 252 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 253} 254 255// Tests that focus cycles from the active browser to the status area and back. 256TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) { 257 ASSERT_TRUE(CreateTray()); 258 InstallFocusCycleOnShelf(); 259 shelf_widget()->Hide(); 260 261 // Create two test windows. 262 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 263 scoped_ptr<Window> window1(CreateTestWindowInShellWithId(1)); 264 wm::ActivateWindow(window1.get()); 265 wm::ActivateWindow(window0.get()); 266 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 267 268 // Cycle focus to the status area. 269 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 270 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 271 272 // Cycle focus to the browser. 273 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 274 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 275 276 // Cycle focus to the status area. 277 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 278 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 279} 280 281TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) { 282 ASSERT_TRUE(CreateTray()); 283 InstallFocusCycleOnShelf(); 284 shelf_widget()->Hide(); 285 286 // Create a single test window. 287 scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0)); 288 wm::ActivateWindow(window0.get()); 289 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 290 291 // Cycle focus to the status area. 292 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 293 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 294 295 // Cycle focus to the browser. 296 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 297 EXPECT_TRUE(wm::IsActiveWindow(window0.get())); 298} 299 300TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) { 301 ASSERT_TRUE(CreateTray()); 302 303 InstallFocusCycleOnShelf(); 304 305 scoped_ptr<PanedWidgetDelegate> test_widget_delegate; 306 scoped_ptr<views::Widget> browser_widget(new views::Widget); 307 test_widget_delegate.reset(new PanedWidgetDelegate(browser_widget.get())); 308 views::Widget::InitParams widget_params( 309 views::Widget::InitParams::TYPE_WINDOW); 310 widget_params.context = CurrentContext(); 311 widget_params.delegate = test_widget_delegate.get(); 312 widget_params.ownership = 313 views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 314 browser_widget->Init(widget_params); 315 browser_widget->Show(); 316 317 aura::Window* browser_window = browser_widget->GetNativeView(); 318 319 views::View* root_view = browser_widget->GetRootView(); 320 321 views::AccessiblePaneView* pane1 = new views::AccessiblePaneView(); 322 root_view->AddChildView(pane1); 323 324 views::View* view1 = new views::View; 325 view1->SetFocusable(true); 326 pane1->AddChildView(view1); 327 328 views::View* view2 = new views::View; 329 view2->SetFocusable(true); 330 pane1->AddChildView(view2); 331 332 views::AccessiblePaneView* pane2 = new views::AccessiblePaneView(); 333 root_view->AddChildView(pane2); 334 335 views::View* view3 = new views::View; 336 view3->SetFocusable(true); 337 pane2->AddChildView(view3); 338 339 views::View* view4 = new views::View; 340 view4->SetFocusable(true); 341 pane2->AddChildView(view4); 342 343 std::vector<views::View*> panes; 344 panes.push_back(pane1); 345 panes.push_back(pane2); 346 347 test_widget_delegate->SetAccessiblePanes(panes); 348 349 views::FocusManager* focus_manager = browser_widget->GetFocusManager(); 350 351 // Cycle focus to the status area. 352 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 353 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 354 355 // Cycle focus to the shelf. 356 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 357 EXPECT_TRUE(shelf_widget()->IsActive()); 358 359 // Cycle focus to the first pane in the browser. 360 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 361 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 362 EXPECT_EQ(focus_manager->GetFocusedView(), view1); 363 364 // Cycle focus to the second pane in the browser. 365 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 366 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 367 EXPECT_EQ(focus_manager->GetFocusedView(), view3); 368 369 // Cycle focus back to the status area. 370 focus_cycler()->RotateFocus(FocusCycler::FORWARD); 371 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 372 373 // Reverse direction - back to the second pane in the browser. 374 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 375 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 376 EXPECT_EQ(focus_manager->GetFocusedView(), view3); 377 378 // Back to the first pane in the browser. 379 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 380 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 381 EXPECT_EQ(focus_manager->GetFocusedView(), view1); 382 383 // Back to the shelf. 384 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 385 EXPECT_TRUE(shelf_widget()->IsActive()); 386 387 // Back to the status area. 388 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 389 EXPECT_TRUE(tray()->GetWidget()->IsActive()); 390 391 // Pressing "Escape" while on the status area should 392 // deactivate it, and activate the browser window. 393 aura::Window* root = Shell::GetPrimaryRootWindow(); 394 aura::test::EventGenerator event_generator(root, root); 395 event_generator.PressKey(ui::VKEY_ESCAPE, 0); 396 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 397 EXPECT_EQ(focus_manager->GetFocusedView(), view1); 398 399 // Similarly, pressing "Escape" while on the shelf. 400 // should do the same thing. 401 focus_cycler()->RotateFocus(FocusCycler::BACKWARD); 402 EXPECT_TRUE(shelf_widget()->IsActive()); 403 event_generator.PressKey(ui::VKEY_ESCAPE, 0); 404 EXPECT_TRUE(wm::IsActiveWindow(browser_window)); 405 EXPECT_EQ(focus_manager->GetFocusedView(), view1); 406} 407 408} // namespace test 409} // namespace ash 410