Home | History | Annotate | Download | only in ash
      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/launcher/launcher.h"
      8 #include "ash/root_window_controller.h"
      9 #include "ash/shelf/shelf_widget.h"
     10 #include "ash/shell.h"
     11 #include "ash/shell_window_ids.h"
     12 #include "ash/system/status_area_widget.h"
     13 #include "ash/system/status_area_widget_delegate.h"
     14 #include "ash/system/tray/system_tray.h"
     15 #include "ash/wm/window_util.h"
     16 #include "ash/test/ash_test_base.h"
     17 #include "ash/shell_factory.h"
     18 #include "ui/aura/root_window.h"
     19 #include "ui/aura/test/event_generator.h"
     20 #include "ui/aura/test/test_windows.h"
     21 #include "ui/aura/window.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 
     26 namespace ash {
     27 namespace test {
     28 
     29 using aura::Window;
     30 using internal::FocusCycler;
     31 
     32 namespace {
     33 
     34 internal::StatusAreaWidgetDelegate* GetStatusAreaWidgetDelegate(
     35     views::Widget* widget) {
     36   return static_cast<internal::StatusAreaWidgetDelegate*>(
     37       widget->GetContentsView());
     38 }
     39 
     40 class 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 
     68 class 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(Launcher::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 Launcher::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 
    134 TEST_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 
    145 TEST_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 
    168 TEST_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 
    191 TEST_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 
    226 TEST_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 TEST_F(FocusCyclerTest, Shelf_CycleFocusForward) {
    256   ASSERT_TRUE(CreateTray());
    257   InstallFocusCycleOnShelf();
    258   shelf_widget()->Hide();
    259 
    260   // Create a single test window.
    261   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
    262   wm::ActivateWindow(window0.get());
    263   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
    264 
    265   // Cycle focus to the status area.
    266   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    267   EXPECT_TRUE(tray()->GetWidget()->IsActive());
    268 
    269   // Cycle focus to the browser.
    270   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    271   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
    272 }
    273 
    274 TEST_F(FocusCyclerTest, Shelf_CycleFocusBackwardInvisible) {
    275   ASSERT_TRUE(CreateTray());
    276   InstallFocusCycleOnShelf();
    277   shelf_widget()->Hide();
    278 
    279   // Create a single test window.
    280   scoped_ptr<Window> window0(CreateTestWindowInShellWithId(0));
    281   wm::ActivateWindow(window0.get());
    282   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
    283 
    284   // Cycle focus to the status area.
    285   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    286   EXPECT_TRUE(tray()->GetWidget()->IsActive());
    287 
    288   // Cycle focus to the browser.
    289   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    290   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
    291 }
    292 
    293 TEST_F(FocusCyclerTest, CycleFocusThroughWindowWithPanes) {
    294   ASSERT_TRUE(CreateTray());
    295 
    296   InstallFocusCycleOnShelf();
    297 
    298   scoped_ptr<views::Widget> browser_widget(new views::Widget);
    299   PanedWidgetDelegate* test_widget_delegate =
    300       new PanedWidgetDelegate(browser_widget.get());
    301   views::Widget::InitParams widget_params(
    302       views::Widget::InitParams::TYPE_WINDOW);
    303   widget_params.context = CurrentContext();
    304   widget_params.delegate = test_widget_delegate;
    305   widget_params.ownership =
    306       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    307   browser_widget->Init(widget_params);
    308   browser_widget->Show();
    309 
    310   aura::Window* browser_window = browser_widget->GetNativeView();
    311 
    312   views::View* root_view = browser_widget->GetRootView();
    313 
    314   views::AccessiblePaneView* pane1 = new views::AccessiblePaneView();
    315   root_view->AddChildView(pane1);
    316 
    317   views::View* view1 = new views::View;
    318   view1->set_focusable(true);
    319   pane1->AddChildView(view1);
    320 
    321   views::View* view2 = new views::View;
    322   view2->set_focusable(true);
    323   pane1->AddChildView(view2);
    324 
    325   views::AccessiblePaneView* pane2 = new views::AccessiblePaneView();
    326   root_view->AddChildView(pane2);
    327 
    328   views::View* view3 = new views::View;
    329   view3->set_focusable(true);
    330   pane2->AddChildView(view3);
    331 
    332   views::View* view4 = new views::View;
    333   view4->set_focusable(true);
    334   pane2->AddChildView(view4);
    335 
    336   std::vector<views::View*> panes;
    337   panes.push_back(pane1);
    338   panes.push_back(pane2);
    339 
    340   test_widget_delegate->SetAccessiblePanes(panes);
    341 
    342   views::FocusManager* focus_manager = browser_widget->GetFocusManager();
    343 
    344   // Cycle focus to the status area.
    345   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    346   EXPECT_TRUE(tray()->GetWidget()->IsActive());
    347 
    348   // Cycle focus to the shelf.
    349   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    350   EXPECT_TRUE(shelf_widget()->IsActive());
    351 
    352   // Cycle focus to the first pane in the browser.
    353   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    354   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    355   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
    356 
    357   // Cycle focus to the second pane in the browser.
    358   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    359   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    360   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
    361 
    362   // Cycle focus back to the status area.
    363   focus_cycler()->RotateFocus(FocusCycler::FORWARD);
    364   EXPECT_TRUE(tray()->GetWidget()->IsActive());
    365 
    366   // Reverse direction - back to the second pane in the browser.
    367   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    368   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    369   EXPECT_EQ(focus_manager->GetFocusedView(), view3);
    370 
    371   // Back to the first pane in the browser.
    372   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    373   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    374   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
    375 
    376   // Back to the shelf.
    377   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    378   EXPECT_TRUE(shelf_widget()->IsActive());
    379 
    380   // Back to the status area.
    381   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    382   EXPECT_TRUE(tray()->GetWidget()->IsActive());
    383 
    384   // Pressing "Escape" while on the status area should
    385   // deactivate it, and activate the browser window.
    386   aura::RootWindow* root = Shell::GetPrimaryRootWindow();
    387   aura::test::EventGenerator event_generator(root, root);
    388   event_generator.PressKey(ui::VKEY_ESCAPE, 0);
    389   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    390   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
    391 
    392   // Similarly, pressing "Escape" while on the shelf.
    393   // should do the same thing.
    394   focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
    395   EXPECT_TRUE(shelf_widget()->IsActive());
    396   event_generator.PressKey(ui::VKEY_ESCAPE, 0);
    397   EXPECT_TRUE(wm::IsActiveWindow(browser_window));
    398   EXPECT_EQ(focus_manager->GetFocusedView(), view1);
    399 }
    400 
    401 }  // namespace test
    402 }  // namespace ash
    403