Home | History | Annotate | Download | only in wm
      1 // Copyright 2013 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/wm/immersive_fullscreen_controller.h"
      6 
      7 #include "ash/display/display_manager.h"
      8 #include "ash/root_window_controller.h"
      9 #include "ash/screen_ash.h"
     10 #include "ash/shelf/shelf_layout_manager.h"
     11 #include "ash/shelf/shelf_types.h"
     12 #include "ash/shell.h"
     13 #include "ash/test/ash_test_base.h"
     14 #include "ui/aura/client/aura_constants.h"
     15 #include "ui/aura/client/cursor_client.h"
     16 #include "ui/aura/env.h"
     17 #include "ui/aura/root_window.h"
     18 #include "ui/aura/test/event_generator.h"
     19 #include "ui/aura/window.h"
     20 #include "ui/gfx/animation/slide_animation.h"
     21 #include "ui/views/bubble/bubble_delegate.h"
     22 #include "ui/views/view.h"
     23 #include "ui/views/widget/widget.h"
     24 
     25 // For now, immersive fullscreen is Chrome OS only.
     26 #if defined(OS_CHROMEOS)
     27 
     28 namespace ash {
     29 
     30 namespace {
     31 
     32 class MockImmersiveFullscreenControllerDelegate
     33     : public ImmersiveFullscreenController::Delegate {
     34  public:
     35   MockImmersiveFullscreenControllerDelegate(views::View* top_container_view)
     36       : top_container_view_(top_container_view),
     37         enabled_(false),
     38         visible_fraction_(1) {
     39   }
     40   virtual ~MockImmersiveFullscreenControllerDelegate() {}
     41 
     42   // ImmersiveFullscreenController::Delegate overrides:
     43   virtual void OnImmersiveRevealStarted() OVERRIDE {
     44     enabled_ = true;
     45     visible_fraction_ = 0;
     46   }
     47   virtual void OnImmersiveRevealEnded() OVERRIDE {
     48     visible_fraction_ = 0;
     49   }
     50   virtual void OnImmersiveFullscreenExited() OVERRIDE {
     51     enabled_ = false;
     52     visible_fraction_ = 1;
     53   }
     54   virtual void SetVisibleFraction(double visible_fraction) OVERRIDE {
     55     visible_fraction_ = visible_fraction;
     56   }
     57   virtual std::vector<gfx::Rect> GetVisibleBoundsInScreen() const OVERRIDE {
     58     std::vector<gfx::Rect> bounds_in_screen;
     59     bounds_in_screen.push_back(top_container_view_->GetBoundsInScreen());
     60     return bounds_in_screen;
     61   }
     62 
     63   bool is_enabled() const {
     64     return enabled_;
     65   }
     66 
     67   double visible_fraction() const {
     68     return visible_fraction_;
     69   }
     70 
     71  private:
     72   views::View* top_container_view_;
     73   bool enabled_;
     74   double visible_fraction_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(MockImmersiveFullscreenControllerDelegate);
     77 };
     78 
     79 }  // namespace
     80 
     81 /////////////////////////////////////////////////////////////////////////////
     82 
     83 class ImmersiveFullscreenControllerTest : public ash::test::AshTestBase {
     84  public:
     85   enum Modality {
     86     MODALITY_MOUSE,
     87     MODALITY_TOUCH,
     88     MODALITY_GESTURE
     89   };
     90 
     91   ImmersiveFullscreenControllerTest() : widget_(NULL), top_container_(NULL) {}
     92   virtual ~ImmersiveFullscreenControllerTest() {}
     93 
     94   ImmersiveFullscreenController* controller() {
     95     return controller_.get();
     96   }
     97 
     98   views::View* top_container() {
     99     return top_container_;
    100   }
    101 
    102   aura::Window* window() {
    103     return widget_->GetNativeWindow();
    104   }
    105 
    106   MockImmersiveFullscreenControllerDelegate* delegate() {
    107     return delegate_.get();
    108   }
    109 
    110   // Access to private data from the controller.
    111   bool top_edge_hover_timer_running() const {
    112     return controller_->top_edge_hover_timer_.IsRunning();
    113   }
    114   int mouse_x_when_hit_top() const {
    115     return controller_->mouse_x_when_hit_top_in_screen_;
    116   }
    117 
    118   // ash::test::AshTestBase overrides:
    119   virtual void SetUp() OVERRIDE {
    120     ash::test::AshTestBase::SetUp();
    121 
    122     widget_ = new views::Widget();
    123     views::Widget::InitParams params;
    124     params.context = CurrentContext();
    125     widget_->Init(params);
    126     widget_->Show();
    127 
    128     window()->SetProperty(aura::client::kShowStateKey,
    129                           ui::SHOW_STATE_FULLSCREEN);
    130 
    131     top_container_ = new views::View();
    132     top_container_->SetBounds(
    133         0, 0, widget_->GetWindowBoundsInScreen().width(), 100);
    134     top_container_->SetFocusable(true);
    135     widget_->GetContentsView()->AddChildView(top_container_);
    136 
    137     delegate_.reset(
    138         new MockImmersiveFullscreenControllerDelegate(top_container_));
    139     controller_.reset(new ImmersiveFullscreenController);
    140     controller_->Init(delegate_.get(), widget_, top_container_);
    141     controller_->SetupForTest();
    142 
    143     // The mouse is moved so that it is not over |top_container_| by
    144     // AshTestBase.
    145   }
    146 
    147   // Enables / disables immersive fullscreen.
    148   void SetEnabled(bool enabled) {
    149     controller_->SetEnabled(ImmersiveFullscreenController::WINDOW_TYPE_OTHER,
    150                             enabled);
    151   }
    152 
    153   // Attempt to reveal the top-of-window views via |modality|.
    154   // The top-of-window views can only be revealed via mouse hover or a gesture.
    155   void AttemptReveal(Modality modality) {
    156     ASSERT_NE(modality, MODALITY_TOUCH);
    157     AttemptRevealStateChange(true, modality);
    158   }
    159 
    160   // Attempt to unreveal the top-of-window views via |modality|. The
    161   // top-of-window views can be unrevealed via any modality.
    162   void AttemptUnreveal(Modality modality) {
    163     AttemptRevealStateChange(false, modality);
    164   }
    165 
    166   // Sets whether the mouse is hovered above |top_container_|.
    167   // SetHovered(true) moves the mouse over the |top_container_| but does not
    168   // move it to the top of the screen so will not initiate a reveal.
    169   void SetHovered(bool is_mouse_hovered) {
    170     MoveMouse(0, is_mouse_hovered ? 10 : top_container_->height() + 100);
    171   }
    172 
    173   // Move the mouse to the given coordinates. The coordinates should be in
    174   // |top_container_| coordinates.
    175   void MoveMouse(int x, int y) {
    176     gfx::Point screen_position(x, y);
    177     views::View::ConvertPointToScreen(top_container_, &screen_position);
    178     GetEventGenerator().MoveMouseTo(screen_position.x(), screen_position.y());
    179 
    180     // If the top edge timer started running as a result of the mouse move, run
    181     // the task which occurs after the timer delay. This reveals the
    182     // top-of-window views synchronously if the mouse is hovered at the top of
    183     // the screen.
    184     if (controller()->top_edge_hover_timer_.IsRunning()) {
    185       controller()->top_edge_hover_timer_.user_task().Run();
    186       controller()->top_edge_hover_timer_.Stop();
    187     }
    188   }
    189 
    190  private:
    191   // Attempt to change the revealed state to |revealed| via |modality|.
    192   void AttemptRevealStateChange(bool revealed, Modality modality) {
    193     // Compute the event position in |top_container_| coordinates.
    194     gfx::Point event_position(0, revealed ? 0 : top_container_->height() + 100);
    195     switch (modality) {
    196       case MODALITY_MOUSE: {
    197         MoveMouse(event_position.x(), event_position.y());
    198         break;
    199       }
    200       case MODALITY_TOUCH: {
    201         gfx::Point screen_position = event_position;
    202         views::View::ConvertPointToScreen(top_container_, &screen_position);
    203 
    204         aura::test::EventGenerator& event_generator(GetEventGenerator());
    205         event_generator.MoveTouch(event_position);
    206         event_generator.PressTouch();
    207         event_generator.ReleaseTouch();
    208         break;
    209       }
    210       case MODALITY_GESTURE: {
    211         aura::client::GetCursorClient(CurrentContext())->DisableMouseEvents();
    212         ImmersiveFullscreenController::SwipeType swipe_type = revealed ?
    213             ImmersiveFullscreenController::SWIPE_OPEN :
    214             ImmersiveFullscreenController::SWIPE_CLOSE;
    215         controller_->UpdateRevealedLocksForSwipe(swipe_type);
    216         break;
    217       }
    218     }
    219   }
    220 
    221   scoped_ptr<ImmersiveFullscreenController> controller_;
    222   scoped_ptr<MockImmersiveFullscreenControllerDelegate> delegate_;
    223   views::Widget* widget_;  // Owned by the native widget.
    224   views::View* top_container_;  // Owned by |root_view_|.
    225 
    226   DISALLOW_COPY_AND_ASSIGN(ImmersiveFullscreenControllerTest);
    227 };
    228 
    229 // Test the initial state and that the delegate gets notified of the
    230 // top-of-window views getting hidden and revealed.
    231 TEST_F(ImmersiveFullscreenControllerTest, Delegate) {
    232   // Initial state.
    233   EXPECT_FALSE(controller()->IsEnabled());
    234   EXPECT_FALSE(controller()->IsRevealed());
    235   EXPECT_FALSE(delegate()->is_enabled());
    236 
    237   // Enabling initially hides the top views.
    238   SetEnabled(true);
    239   EXPECT_TRUE(controller()->IsEnabled());
    240   EXPECT_FALSE(controller()->IsRevealed());
    241   EXPECT_TRUE(delegate()->is_enabled());
    242   EXPECT_EQ(0, delegate()->visible_fraction());
    243 
    244   // Revealing shows the top views.
    245   AttemptReveal(MODALITY_MOUSE);
    246   EXPECT_TRUE(controller()->IsEnabled());
    247   EXPECT_TRUE(controller()->IsRevealed());
    248   EXPECT_TRUE(delegate()->is_enabled());
    249   EXPECT_EQ(1, delegate()->visible_fraction());
    250 
    251   // Disabling ends the immersive reveal.
    252   SetEnabled(false);
    253   EXPECT_FALSE(controller()->IsEnabled());
    254   EXPECT_FALSE(controller()->IsRevealed());
    255   EXPECT_FALSE(delegate()->is_enabled());
    256 }
    257 
    258 // GetRevealedLock() specific tests.
    259 TEST_F(ImmersiveFullscreenControllerTest, RevealedLock) {
    260   scoped_ptr<ImmersiveRevealedLock> lock1;
    261   scoped_ptr<ImmersiveRevealedLock> lock2;
    262 
    263   // Immersive fullscreen is not on by default.
    264   EXPECT_FALSE(controller()->IsEnabled());
    265 
    266   // 1) Test acquiring and releasing a revealed state lock while immersive
    267   // fullscreen is disabled. Acquiring or releasing the lock should have no
    268   // effect till immersive fullscreen is enabled.
    269   lock1.reset(controller()->GetRevealedLock(
    270       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    271   EXPECT_FALSE(controller()->IsEnabled());
    272   EXPECT_FALSE(controller()->IsRevealed());
    273 
    274   // Immersive fullscreen should start in the revealed state due to the lock.
    275   SetEnabled(true);
    276   EXPECT_TRUE(controller()->IsEnabled());
    277   EXPECT_TRUE(controller()->IsRevealed());
    278 
    279   SetEnabled(false);
    280   EXPECT_FALSE(controller()->IsEnabled());
    281   EXPECT_FALSE(controller()->IsRevealed());
    282 
    283   lock1.reset();
    284   EXPECT_FALSE(controller()->IsEnabled());
    285   EXPECT_FALSE(controller()->IsRevealed());
    286 
    287   // Immersive fullscreen should start in the closed state because the lock is
    288   // no longer held.
    289   SetEnabled(true);
    290   EXPECT_TRUE(controller()->IsEnabled());
    291   EXPECT_FALSE(controller()->IsRevealed());
    292 
    293   // 2) Test that acquiring a lock reveals the top-of-window views if they are
    294   // hidden.
    295   lock1.reset(controller()->GetRevealedLock(
    296       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    297   EXPECT_TRUE(controller()->IsRevealed());
    298 
    299   // 3) Test that the top-of-window views are only hidden when all of the locks
    300   // are released.
    301   lock2.reset(controller()->GetRevealedLock(
    302       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    303   lock1.reset();
    304   EXPECT_TRUE(controller()->IsRevealed());
    305 
    306   lock2.reset();
    307   EXPECT_FALSE(controller()->IsRevealed());
    308 }
    309 
    310 // Test mouse event processing for top-of-screen reveal triggering.
    311 TEST_F(ImmersiveFullscreenControllerTest, OnMouseEvent) {
    312   // Set up initial state.
    313   UpdateDisplay("800x600,800x600");
    314   ash::DisplayLayout display_layout(ash::DisplayLayout::RIGHT, 0);
    315   ash::Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
    316       display_layout);
    317 
    318   // Set up initial state.
    319   SetEnabled(true);
    320   ASSERT_TRUE(controller()->IsEnabled());
    321   ASSERT_FALSE(controller()->IsRevealed());
    322 
    323   aura::test::EventGenerator& event_generator(GetEventGenerator());
    324 
    325   gfx::Rect top_container_bounds_in_screen =
    326       top_container()->GetBoundsInScreen();
    327   // A position along the top edge of TopContainerView in screen coordinates.
    328   gfx::Point top_edge_pos(top_container_bounds_in_screen.x() + 100,
    329                           top_container_bounds_in_screen.y());
    330 
    331   // Mouse wheel event does nothing.
    332   ui::MouseEvent wheel(
    333       ui::ET_MOUSEWHEEL, top_edge_pos, top_edge_pos, ui::EF_NONE);
    334   event_generator.Dispatch(&wheel);
    335   EXPECT_FALSE(top_edge_hover_timer_running());
    336 
    337   // Move to top edge of screen starts hover timer running. We cannot use
    338   // MoveMouse() because MoveMouse() stops the timer if it started running.
    339   event_generator.MoveMouseTo(top_edge_pos);
    340   EXPECT_TRUE(top_edge_hover_timer_running());
    341   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
    342 
    343   // Moving |ImmersiveFullscreenControllerTest::kMouseRevealBoundsHeight| down
    344   // from the top edge stops it.
    345   event_generator.MoveMouseBy(0, 3);
    346   EXPECT_FALSE(top_edge_hover_timer_running());
    347 
    348   // Moving back to the top starts the timer again.
    349   event_generator.MoveMouseTo(top_edge_pos);
    350   EXPECT_TRUE(top_edge_hover_timer_running());
    351   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
    352 
    353   // Slight move to the right keeps the timer running for the same hit point.
    354   event_generator.MoveMouseBy(1, 0);
    355   EXPECT_TRUE(top_edge_hover_timer_running());
    356   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
    357 
    358   // Moving back to the left also keeps the timer running.
    359   event_generator.MoveMouseBy(-1, 0);
    360   EXPECT_TRUE(top_edge_hover_timer_running());
    361   EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
    362 
    363   // Large move right restarts the timer (so it is still running) and considers
    364   // this a new hit at the top.
    365   event_generator.MoveMouseTo(top_edge_pos.x() + 100, top_edge_pos.y());
    366   EXPECT_TRUE(top_edge_hover_timer_running());
    367   EXPECT_EQ(top_edge_pos.x() + 100, mouse_x_when_hit_top());
    368 
    369   // Moving off the top edge horizontally stops the timer.
    370   event_generator.MoveMouseTo(top_container_bounds_in_screen.right() + 1,
    371                               top_container_bounds_in_screen.y());
    372   EXPECT_FALSE(top_edge_hover_timer_running());
    373 
    374   // Once revealed, a move just a little below the top container doesn't end a
    375   // reveal.
    376   AttemptReveal(MODALITY_MOUSE);
    377   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
    378                               top_container_bounds_in_screen.bottom() + 1);
    379   EXPECT_TRUE(controller()->IsRevealed());
    380 
    381   // Once revealed, clicking just below the top container ends the reveal.
    382   event_generator.ClickLeftButton();
    383   EXPECT_FALSE(controller()->IsRevealed());
    384 
    385   // Moving a lot below the top container ends a reveal.
    386   AttemptReveal(MODALITY_MOUSE);
    387   EXPECT_TRUE(controller()->IsRevealed());
    388   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
    389                               top_container_bounds_in_screen.bottom() + 50);
    390   EXPECT_FALSE(controller()->IsRevealed());
    391 
    392   // The mouse position cannot cause a reveal when the top container's widget
    393   // has capture.
    394   views::Widget* widget = top_container()->GetWidget();
    395   widget->SetCapture(top_container());
    396   AttemptReveal(MODALITY_MOUSE);
    397   EXPECT_FALSE(controller()->IsRevealed());
    398   widget->ReleaseCapture();
    399 
    400   // The mouse position cannot end the reveal while the top container's widget
    401   // has capture.
    402   AttemptReveal(MODALITY_MOUSE);
    403   EXPECT_TRUE(controller()->IsRevealed());
    404   widget->SetCapture(top_container());
    405   event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
    406                               top_container_bounds_in_screen.bottom() + 51);
    407   EXPECT_TRUE(controller()->IsRevealed());
    408 
    409   // Releasing capture should end the reveal.
    410   widget->ReleaseCapture();
    411   EXPECT_FALSE(controller()->IsRevealed());
    412 }
    413 
    414 // Test mouse event processing for top-of-screen reveal triggering when the
    415 // top container's widget is inactive.
    416 TEST_F(ImmersiveFullscreenControllerTest, Inactive) {
    417   // Set up initial state.
    418   views::Widget* popup_widget = views::Widget::CreateWindowWithContextAndBounds(
    419       NULL,
    420       CurrentContext(),
    421       gfx::Rect(0, 0, 200, 200));
    422   popup_widget->Show();
    423   ASSERT_FALSE(top_container()->GetWidget()->IsActive());
    424 
    425   SetEnabled(true);
    426   ASSERT_TRUE(controller()->IsEnabled());
    427   ASSERT_FALSE(controller()->IsRevealed());
    428 
    429   gfx::Rect top_container_bounds_in_screen =
    430       top_container()->GetBoundsInScreen();
    431   gfx::Rect popup_bounds_in_screen = popup_widget->GetWindowBoundsInScreen();
    432   ASSERT_EQ(top_container_bounds_in_screen.origin().ToString(),
    433             popup_bounds_in_screen.origin().ToString());
    434   ASSERT_GT(top_container_bounds_in_screen.right(),
    435             popup_bounds_in_screen.right());
    436 
    437   // The top-of-window views should stay hidden if the cursor is at the top edge
    438   // but above an obscured portion of the top-of-window views.
    439   MoveMouse(popup_bounds_in_screen.x(),
    440             top_container_bounds_in_screen.y());
    441   EXPECT_FALSE(controller()->IsRevealed());
    442 
    443   // The top-of-window views should reveal if the cursor is at the top edge and
    444   // above an unobscured portion of the top-of-window views.
    445   MoveMouse(top_container_bounds_in_screen.right() - 1,
    446             top_container_bounds_in_screen.y());
    447   EXPECT_TRUE(controller()->IsRevealed());
    448 
    449   // The top-of-window views should stay revealed if the cursor is moved off
    450   // of the top edge.
    451   MoveMouse(top_container_bounds_in_screen.right() - 1,
    452             top_container_bounds_in_screen.bottom() - 1);
    453   EXPECT_TRUE(controller()->IsRevealed());
    454 
    455   // Moving way off of the top-of-window views should end the immersive reveal.
    456   MoveMouse(top_container_bounds_in_screen.right() - 1,
    457             top_container_bounds_in_screen.bottom() + 50);
    458   EXPECT_FALSE(controller()->IsRevealed());
    459 
    460   // Moving way off of the top-of-window views in a region where the
    461   // top-of-window views are obscured should also end the immersive reveal.
    462   // Ideally, the immersive reveal would end immediately when the cursor moves
    463   // to an obscured portion of the top-of-window views.
    464   MoveMouse(top_container_bounds_in_screen.right() - 1,
    465             top_container_bounds_in_screen.y());
    466   EXPECT_TRUE(controller()->IsRevealed());
    467   MoveMouse(top_container_bounds_in_screen.x(),
    468             top_container_bounds_in_screen.bottom() + 50);
    469   EXPECT_FALSE(controller()->IsRevealed());
    470 }
    471 
    472 // Test mouse event processing for top-of-screen reveal triggering when the user
    473 // has a vertical display layout (primary display above/below secondary display)
    474 // and the immersive fullscreen window is on the bottom display.
    475 TEST_F(ImmersiveFullscreenControllerTest, MouseEventsVerticalDisplayLayout) {
    476   if (!SupportsMultipleDisplays())
    477     return;
    478 
    479   // Set up initial state.
    480   UpdateDisplay("800x600,800x600");
    481   ash::DisplayLayout display_layout(ash::DisplayLayout::TOP, 0);
    482   ash::Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
    483       display_layout);
    484 
    485   SetEnabled(true);
    486   ASSERT_TRUE(controller()->IsEnabled());
    487   ASSERT_FALSE(controller()->IsRevealed());
    488 
    489   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
    490   ASSERT_EQ(root_windows[0],
    491             top_container()->GetWidget()->GetNativeWindow()->GetRootWindow());
    492 
    493   gfx::Rect primary_root_window_bounds_in_screen =
    494       root_windows[0]->GetBoundsInScreen();
    495   // Do not set |x| to the root window's x position because the display's
    496   // corners have special behavior.
    497   int x = primary_root_window_bounds_in_screen.x() + 10;
    498   // The y position of the top edge of the primary display.
    499   int y_top_edge = primary_root_window_bounds_in_screen.y();
    500 
    501   aura::test::EventGenerator& event_generator(GetEventGenerator());
    502 
    503   // Moving right below the top edge starts the hover timer running. We
    504   // cannot use MoveMouse() because MoveMouse() stops the timer if it started
    505   // running.
    506   event_generator.MoveMouseTo(x, y_top_edge + 1);
    507   EXPECT_TRUE(top_edge_hover_timer_running());
    508   EXPECT_EQ(y_top_edge + 1,
    509             aura::Env::GetInstance()->last_mouse_location().y());
    510 
    511   // The timer should continue running if the user moves the mouse to the top
    512   // edge even though the mouse is warped to the secondary display.
    513   event_generator.MoveMouseTo(x, y_top_edge);
    514   EXPECT_TRUE(top_edge_hover_timer_running());
    515   EXPECT_NE(y_top_edge,
    516             aura::Env::GetInstance()->last_mouse_location().y());
    517 
    518   // The timer should continue running if the user overshoots the top edge
    519   // a bit.
    520   event_generator.MoveMouseTo(x, y_top_edge - 2);
    521   EXPECT_TRUE(top_edge_hover_timer_running());
    522 
    523   // The timer should stop running if the user overshoots the top edge by
    524   // a lot.
    525   event_generator.MoveMouseTo(x, y_top_edge - 20);
    526   EXPECT_FALSE(top_edge_hover_timer_running());
    527 
    528   // The timer should not start if the user moves the mouse to the bottom of the
    529   // secondary display without crossing the top edge first.
    530   event_generator.MoveMouseTo(x, y_top_edge - 2);
    531 
    532   // Reveal the top-of-window views by overshooting the top edge slightly.
    533   event_generator.MoveMouseTo(x, y_top_edge + 1);
    534   // MoveMouse() runs the timer task.
    535   MoveMouse(x, y_top_edge - 2);
    536   EXPECT_TRUE(controller()->IsRevealed());
    537 
    538   // The top-of-window views should stay revealed if the user moves the mouse
    539   // around in the bottom region of the secondary display.
    540   event_generator.MoveMouseTo(x + 10, y_top_edge - 3);
    541   EXPECT_TRUE(controller()->IsRevealed());
    542 
    543   // The top-of-window views should hide if the user moves the mouse away from
    544   // the bottom region of the secondary display.
    545   event_generator.MoveMouseTo(x, y_top_edge - 20);
    546   EXPECT_FALSE(controller()->IsRevealed());
    547 
    548   // Test that it is possible to reveal the top-of-window views by overshooting
    549   // the top edge slightly when the top container's widget is not active.
    550   views::Widget* popup_widget = views::Widget::CreateWindowWithContextAndBounds(
    551       NULL,
    552       CurrentContext(),
    553       gfx::Rect(0, 200, 100, 100));
    554   popup_widget->Show();
    555   ASSERT_FALSE(top_container()->GetWidget()->IsActive());
    556   ASSERT_FALSE(top_container()->GetBoundsInScreen().Intersects(
    557       popup_widget->GetWindowBoundsInScreen()));
    558   event_generator.MoveMouseTo(x, y_top_edge + 1);
    559   MoveMouse(x, y_top_edge - 2);
    560   EXPECT_TRUE(controller()->IsRevealed());
    561 }
    562 
    563 // Test behavior when the mouse becomes hovered without moving.
    564 TEST_F(ImmersiveFullscreenControllerTest, MouseHoveredWithoutMoving) {
    565   SetEnabled(true);
    566   scoped_ptr<ImmersiveRevealedLock> lock;
    567 
    568   // 1) Test that if the mouse becomes hovered without the mouse moving due to a
    569   // lock causing the top-of-window views to be revealed (and the mouse
    570   // happening to be near the top of the screen), the top-of-window views do not
    571   // hide till the mouse moves off of the top-of-window views.
    572   SetHovered(true);
    573   EXPECT_FALSE(controller()->IsRevealed());
    574   lock.reset(controller()->GetRevealedLock(
    575       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    576   EXPECT_TRUE(controller()->IsRevealed());
    577   lock.reset();
    578   EXPECT_TRUE(controller()->IsRevealed());
    579   SetHovered(false);
    580   EXPECT_FALSE(controller()->IsRevealed());
    581 
    582   // 2) Test that if the mouse becomes hovered without moving because of a
    583   // reveal in ImmersiveFullscreenController::SetEnabled(true) and there are no
    584   // locks keeping the top-of-window views revealed, that mouse hover does not
    585   // prevent the top-of-window views from closing.
    586   SetEnabled(false);
    587   SetHovered(true);
    588   EXPECT_FALSE(controller()->IsRevealed());
    589   SetEnabled(true);
    590   EXPECT_FALSE(controller()->IsRevealed());
    591 
    592   // 3) Test that if the mouse becomes hovered without moving because of a
    593   // reveal in ImmersiveFullscreenController::SetEnabled(true) and there is a
    594   // lock keeping the top-of-window views revealed, that the top-of-window views
    595   // do not hide till the mouse moves off of the top-of-window views.
    596   SetEnabled(false);
    597   SetHovered(true);
    598   lock.reset(controller()->GetRevealedLock(
    599       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    600   EXPECT_FALSE(controller()->IsRevealed());
    601   SetEnabled(true);
    602   EXPECT_TRUE(controller()->IsRevealed());
    603   lock.reset();
    604   EXPECT_TRUE(controller()->IsRevealed());
    605   SetHovered(false);
    606   EXPECT_FALSE(controller()->IsRevealed());
    607 }
    608 
    609 // Test revealing the top-of-window views using one modality and ending
    610 // the reveal via another. For instance, initiating the reveal via a SWIPE_OPEN
    611 // edge gesture, switching to using the mouse and ending the reveal by moving
    612 // the mouse off of the top-of-window views.
    613 TEST_F(ImmersiveFullscreenControllerTest, DifferentModalityEnterExit) {
    614   SetEnabled(true);
    615   EXPECT_TRUE(controller()->IsEnabled());
    616   EXPECT_FALSE(controller()->IsRevealed());
    617 
    618   // Initiate reveal via gesture, end reveal via mouse.
    619   AttemptReveal(MODALITY_GESTURE);
    620   EXPECT_TRUE(controller()->IsRevealed());
    621   MoveMouse(1, 1);
    622   EXPECT_TRUE(controller()->IsRevealed());
    623   AttemptUnreveal(MODALITY_MOUSE);
    624   EXPECT_FALSE(controller()->IsRevealed());
    625 
    626   // Initiate reveal via gesture, end reveal via touch.
    627   AttemptReveal(MODALITY_GESTURE);
    628   EXPECT_TRUE(controller()->IsRevealed());
    629   AttemptUnreveal(MODALITY_TOUCH);
    630   EXPECT_FALSE(controller()->IsRevealed());
    631 
    632   // Initiate reveal via mouse, end reveal via gesture.
    633   AttemptReveal(MODALITY_MOUSE);
    634   EXPECT_TRUE(controller()->IsRevealed());
    635   AttemptUnreveal(MODALITY_GESTURE);
    636   EXPECT_FALSE(controller()->IsRevealed());
    637 
    638   // Initiate reveal via mouse, end reveal via touch.
    639   AttemptReveal(MODALITY_MOUSE);
    640   EXPECT_TRUE(controller()->IsRevealed());
    641   AttemptUnreveal(MODALITY_TOUCH);
    642   EXPECT_FALSE(controller()->IsRevealed());
    643 }
    644 
    645 // Test when the SWIPE_CLOSE edge gesture closes the top-of-window views.
    646 TEST_F(ImmersiveFullscreenControllerTest, EndRevealViaGesture) {
    647   SetEnabled(true);
    648   EXPECT_TRUE(controller()->IsEnabled());
    649   EXPECT_FALSE(controller()->IsRevealed());
    650 
    651   // A gesture should be able to close the top-of-window views when
    652   // top-of-window views have focus.
    653   AttemptReveal(MODALITY_MOUSE);
    654   top_container()->RequestFocus();
    655   EXPECT_TRUE(controller()->IsRevealed());
    656   AttemptUnreveal(MODALITY_GESTURE);
    657   EXPECT_FALSE(controller()->IsRevealed());
    658 
    659   // The top-of-window views should no longer have focus. Clearing focus is
    660   // important because it closes focus-related popup windows like the touch
    661   // selection handles.
    662   EXPECT_FALSE(top_container()->HasFocus());
    663 
    664   // If some other code is holding onto a lock, a gesture should not be able to
    665   // end the reveal.
    666   AttemptReveal(MODALITY_MOUSE);
    667   scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
    668       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    669   EXPECT_TRUE(controller()->IsRevealed());
    670   AttemptUnreveal(MODALITY_GESTURE);
    671   EXPECT_TRUE(controller()->IsRevealed());
    672   lock.reset();
    673   EXPECT_FALSE(controller()->IsRevealed());
    674 }
    675 
    676 // Do not test under windows because focus testing is not reliable on
    677 // Windows. (crbug.com/79493)
    678 #if !defined(OS_WIN)
    679 
    680 // Test how focus and activation affects whether the top-of-window views are
    681 // revealed.
    682 TEST_F(ImmersiveFullscreenControllerTest, Focus) {
    683   // Add views to the view hierarchy which we will focus and unfocus during the
    684   // test.
    685   views::View* child_view = new views::View();
    686   child_view->SetBounds(0, 0, 10, 10);
    687   child_view->SetFocusable(true);
    688   top_container()->AddChildView(child_view);
    689   views::View* unrelated_view = new views::View();
    690   unrelated_view->SetBounds(0, 100, 10, 10);
    691   unrelated_view->SetFocusable(true);
    692   top_container()->parent()->AddChildView(unrelated_view);
    693   views::FocusManager* focus_manager =
    694       top_container()->GetWidget()->GetFocusManager();
    695 
    696   SetEnabled(true);
    697 
    698   // 1) Test that the top-of-window views stay revealed as long as either a
    699   // |child_view| has focus or the mouse is hovered above the top-of-window
    700   // views.
    701   AttemptReveal(MODALITY_MOUSE);
    702   child_view->RequestFocus();
    703   focus_manager->ClearFocus();
    704   EXPECT_TRUE(controller()->IsRevealed());
    705   child_view->RequestFocus();
    706   SetHovered(false);
    707   EXPECT_TRUE(controller()->IsRevealed());
    708   focus_manager->ClearFocus();
    709   EXPECT_FALSE(controller()->IsRevealed());
    710 
    711   // 2) Test that focusing |unrelated_view| hides the top-of-window views.
    712   // Note: In this test we can cheat and trigger a reveal via focus because
    713   // the top container does not hide when the top-of-window views are not
    714   // revealed.
    715   child_view->RequestFocus();
    716   EXPECT_TRUE(controller()->IsRevealed());
    717   unrelated_view->RequestFocus();
    718   EXPECT_FALSE(controller()->IsRevealed());
    719 
    720   // 3) Test that a loss of focus of |child_view| to |unrelated_view|
    721   // while immersive mode is disabled is properly registered.
    722   child_view->RequestFocus();
    723   EXPECT_TRUE(controller()->IsRevealed());
    724   SetEnabled(false);
    725   EXPECT_FALSE(controller()->IsRevealed());
    726   unrelated_view->RequestFocus();
    727   SetEnabled(true);
    728   EXPECT_FALSE(controller()->IsRevealed());
    729 
    730   // Repeat test but with a revealed lock acquired when immersive mode is
    731   // disabled because the code path is different.
    732   child_view->RequestFocus();
    733   EXPECT_TRUE(controller()->IsRevealed());
    734   SetEnabled(false);
    735   scoped_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
    736       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    737   EXPECT_FALSE(controller()->IsRevealed());
    738   unrelated_view->RequestFocus();
    739   SetEnabled(true);
    740   EXPECT_TRUE(controller()->IsRevealed());
    741   lock.reset();
    742   EXPECT_FALSE(controller()->IsRevealed());
    743 }
    744 
    745 // Test how transient windows affect whether the top-of-window views are
    746 // revealed.
    747 TEST_F(ImmersiveFullscreenControllerTest, Transient) {
    748   views::Widget* top_container_widget = top_container()->GetWidget();
    749 
    750   SetEnabled(true);
    751   ASSERT_FALSE(controller()->IsRevealed());
    752 
    753   // 1) Test that a transient window which is not a bubble does not trigger a
    754   // reveal but does keep the top-of-window views revealed if they are already
    755   // revealed.
    756   views::Widget::InitParams transient_params;
    757   transient_params.ownership =
    758       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    759   transient_params.parent = top_container_widget->GetNativeView();
    760   transient_params.bounds = gfx::Rect(0, 100, 100, 100);
    761   scoped_ptr<views::Widget> transient_widget(new views::Widget());
    762   transient_widget->Init(transient_params);
    763 
    764   EXPECT_FALSE(controller()->IsRevealed());
    765   AttemptReveal(MODALITY_MOUSE);
    766   EXPECT_TRUE(controller()->IsRevealed());
    767   transient_widget->Show();
    768   SetHovered(false);
    769   EXPECT_TRUE(controller()->IsRevealed());
    770   transient_widget.reset();
    771   EXPECT_FALSE(controller()->IsRevealed());
    772 
    773   // 2) Test that activating a non-transient window does not keep the
    774   // top-of-window views revealed.
    775   views::Widget::InitParams non_transient_params;
    776   non_transient_params.ownership =
    777       views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    778   non_transient_params.context = top_container_widget->GetNativeView();
    779   non_transient_params.bounds = gfx::Rect(0, 100, 100, 100);
    780   scoped_ptr<views::Widget> non_transient_widget(new views::Widget());
    781   non_transient_widget->Init(non_transient_params);
    782 
    783   EXPECT_FALSE(controller()->IsRevealed());
    784   AttemptReveal(MODALITY_MOUSE);
    785   EXPECT_TRUE(controller()->IsRevealed());
    786   non_transient_widget->Show();
    787   SetHovered(false);
    788   EXPECT_FALSE(controller()->IsRevealed());
    789 }
    790 
    791 // Test how bubbles affect whether the top-of-window views are revealed.
    792 TEST_F(ImmersiveFullscreenControllerTest, Bubbles) {
    793   scoped_ptr<ImmersiveRevealedLock> revealed_lock;
    794   views::Widget* top_container_widget = top_container()->GetWidget();
    795 
    796   // Add views to the view hierarchy to which we will anchor bubbles.
    797   views::View* child_view = new views::View();
    798   child_view->SetBounds(0, 0, 10, 10);
    799   top_container()->AddChildView(child_view);
    800   views::View* unrelated_view = new views::View();
    801   unrelated_view->SetBounds(0, 100, 10, 10);
    802   top_container()->parent()->AddChildView(unrelated_view);
    803 
    804   SetEnabled(true);
    805   ASSERT_FALSE(controller()->IsRevealed());
    806 
    807   // 1) Test that a bubble anchored to a child of the top container triggers
    808   // a reveal and keeps the top-of-window views revealed for the duration of
    809   // its visibility.
    810   views::Widget* bubble_widget1(views::BubbleDelegateView::CreateBubble(
    811       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE)));
    812   bubble_widget1->Show();
    813   EXPECT_TRUE(controller()->IsRevealed());
    814 
    815   // Activating |top_container_widget| will close |bubble_widget1|.
    816   top_container_widget->Activate();
    817   AttemptReveal(MODALITY_MOUSE);
    818   revealed_lock.reset(controller()->GetRevealedLock(
    819       ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
    820   EXPECT_TRUE(controller()->IsRevealed());
    821 
    822   views::Widget* bubble_widget2 = views::BubbleDelegateView::CreateBubble(
    823       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
    824   bubble_widget2->Show();
    825   EXPECT_TRUE(controller()->IsRevealed());
    826   revealed_lock.reset();
    827   SetHovered(false);
    828   EXPECT_TRUE(controller()->IsRevealed());
    829   bubble_widget2->Close();
    830   EXPECT_FALSE(controller()->IsRevealed());
    831 
    832   // 2) Test that transitioning from keeping the top-of-window views revealed
    833   // because of a bubble to keeping the top-of-window views revealed because of
    834   // mouse hover by activating |top_container_widget| works.
    835   views::Widget* bubble_widget3 = views::BubbleDelegateView::CreateBubble(
    836       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
    837   bubble_widget3->Show();
    838   SetHovered(true);
    839   EXPECT_TRUE(controller()->IsRevealed());
    840   top_container_widget->Activate();
    841   EXPECT_TRUE(controller()->IsRevealed());
    842 
    843   // 3) Test that the top-of-window views stay revealed as long as at least one
    844   // bubble anchored to a child of the top container is visible.
    845   SetHovered(false);
    846   EXPECT_FALSE(controller()->IsRevealed());
    847 
    848   views::BubbleDelegateView* bubble_delegate4(new views::BubbleDelegateView(
    849       child_view, views::BubbleBorder::NONE));
    850   bubble_delegate4->set_use_focusless(true);
    851   views::Widget* bubble_widget4(views::BubbleDelegateView::CreateBubble(
    852       bubble_delegate4));
    853   bubble_widget4->Show();
    854 
    855   views::BubbleDelegateView* bubble_delegate5(new views::BubbleDelegateView(
    856       child_view, views::BubbleBorder::NONE));
    857   bubble_delegate5->set_use_focusless(true);
    858   views::Widget* bubble_widget5(views::BubbleDelegateView::CreateBubble(
    859       bubble_delegate5));
    860   bubble_widget5->Show();
    861 
    862   EXPECT_TRUE(controller()->IsRevealed());
    863   bubble_widget4->Hide();
    864   EXPECT_TRUE(controller()->IsRevealed());
    865   bubble_widget5->Hide();
    866   EXPECT_FALSE(controller()->IsRevealed());
    867   bubble_widget5->Show();
    868   EXPECT_TRUE(controller()->IsRevealed());
    869 
    870   // 4) Test that visibility changes which occur while immersive fullscreen is
    871   // disabled are handled upon reenabling immersive fullscreen.
    872   SetEnabled(false);
    873   bubble_widget5->Hide();
    874   SetEnabled(true);
    875   EXPECT_FALSE(controller()->IsRevealed());
    876 
    877   // We do not need |bubble_widget4| or |bubble_widget5| anymore, close them.
    878   bubble_widget4->Close();
    879   bubble_widget5->Close();
    880 
    881   // 5) Test that a bubble added while immersive fullscreen is disabled is
    882   // handled upon reenabling immersive fullscreen.
    883   SetEnabled(false);
    884 
    885   views::Widget* bubble_widget6 = views::BubbleDelegateView::CreateBubble(
    886       new views::BubbleDelegateView(child_view, views::BubbleBorder::NONE));
    887   bubble_widget6->Show();
    888 
    889   SetEnabled(true);
    890   EXPECT_TRUE(controller()->IsRevealed());
    891 
    892   bubble_widget6->Close();
    893 
    894   // 6) Test that a bubble which is not anchored to a child of the
    895   // TopContainerView does not trigger a reveal or keep the
    896   // top-of-window views revealed if they are already revealed.
    897   views::Widget* bubble_widget7 = views::BubbleDelegateView::CreateBubble(
    898       new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
    899   bubble_widget7->Show();
    900   EXPECT_FALSE(controller()->IsRevealed());
    901 
    902   // Activating |top_container_widget| will close |bubble_widget6|.
    903   top_container_widget->Activate();
    904   AttemptReveal(MODALITY_MOUSE);
    905   EXPECT_TRUE(controller()->IsRevealed());
    906 
    907   views::Widget* bubble_widget8 = views::BubbleDelegateView::CreateBubble(
    908       new views::BubbleDelegateView(unrelated_view, views::BubbleBorder::NONE));
    909   bubble_widget8->Show();
    910   SetHovered(false);
    911   EXPECT_FALSE(controller()->IsRevealed());
    912   bubble_widget8->Close();
    913 }
    914 
    915 #endif  // defined(OS_WIN)
    916 
    917 // Test that the shelf is set to auto hide as long as the window is in
    918 // immersive fullscreen and that the shelf's state before entering immersive
    919 // fullscreen is restored upon exiting immersive fullscreen.
    920 TEST_F(ImmersiveFullscreenControllerTest, Shelf) {
    921   ash::internal::ShelfLayoutManager* shelf =
    922       ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    923 
    924   // Shelf is visible by default.
    925   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    926   ASSERT_FALSE(controller()->IsEnabled());
    927   ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
    928 
    929   // Entering immersive fullscreen sets the shelf to auto hide.
    930   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    931   SetEnabled(true);
    932   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    933 
    934   // Disabling immersive fullscreen puts it back.
    935   SetEnabled(false);
    936   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
    937   ASSERT_FALSE(controller()->IsEnabled());
    938   EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
    939 
    940   // The user could toggle the shelf auto-hide behavior.
    941   shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
    942   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    943 
    944   // Entering immersive fullscreen keeps auto-hide.
    945   window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
    946   SetEnabled(true);
    947   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    948 
    949   // Disabling immersive fullscreen maintains the user's auto-hide selection.
    950   SetEnabled(false);
    951   window()->SetProperty(aura::client::kShowStateKey,
    952                         ui::SHOW_STATE_NORMAL);
    953   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    954 }
    955 
    956 }  // namespase ash
    957 
    958 #endif  // defined(OS_CHROMEOS)
    959