Home | History | Annotate | Download | only in frame
      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 "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
      6 
      7 #include "ash/ash_switches.h"
      8 #include "ash/root_window_controller.h"
      9 #include "ash/shelf/shelf_layout_manager.h"
     10 #include "ash/shelf/shelf_types.h"
     11 #include "ash/shell.h"
     12 #include "ash/test/ash_test_base.h"
     13 #include "base/command_line.h"
     14 #include "chrome/app/chrome_command_ids.h"
     15 #include "chrome/browser/ui/browser_commands.h"
     16 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
     17 #include "chrome/browser/ui/fullscreen/fullscreen_controller_test.h"
     18 #include "chrome/browser/ui/views/frame/browser_view.h"
     19 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
     20 #include "chrome/browser/ui/views/frame/top_container_view.h"
     21 #include "chrome/browser/ui/views/tabs/tab_strip.h"
     22 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
     23 #include "ui/aura/window.h"
     24 #include "ui/views/controls/webview/webview.h"
     25 
     26 class ImmersiveModeControllerAshTest : public TestWithBrowserView {
     27  public:
     28   ImmersiveModeControllerAshTest()
     29       : TestWithBrowserView(Browser::TYPE_TABBED,
     30                             chrome::HOST_DESKTOP_TYPE_ASH,
     31                             false) {
     32   }
     33   ImmersiveModeControllerAshTest(
     34       Browser::Type browser_type,
     35       chrome::HostDesktopType host_desktop_type,
     36       bool hosted_app)
     37       : TestWithBrowserView(browser_type,
     38                             host_desktop_type,
     39                             hosted_app) {
     40   }
     41   virtual ~ImmersiveModeControllerAshTest() {}
     42 
     43   // TestWithBrowserView override:
     44   virtual void SetUp() OVERRIDE {
     45     TestWithBrowserView::SetUp();
     46 
     47     browser()->window()->Show();
     48 
     49     controller_ = browser_view()->immersive_mode_controller();
     50     controller_->SetupForTest();
     51   }
     52 
     53   // Returns the bounds of |view| in widget coordinates.
     54   gfx::Rect GetBoundsInWidget(views::View* view) {
     55     return view->ConvertRectToWidget(view->GetLocalBounds());
     56   }
     57 
     58   // Toggle the browser's fullscreen state.
     59   void ToggleFullscreen() {
     60     // NOTIFICATION_FULLSCREEN_CHANGED is sent asynchronously. The notification
     61     // is used to trigger changes in whether the shelf is auto hidden and
     62     // whether a "light bar" version of the tab strip is used when the
     63     // top-of-window views are hidden.
     64     scoped_ptr<FullscreenNotificationObserver> waiter(
     65         new FullscreenNotificationObserver());
     66     chrome::ToggleFullscreenMode(browser());
     67     waiter->Wait();
     68   }
     69 
     70   // Set whether the browser is in tab fullscreen.
     71   void SetTabFullscreen(bool tab_fullscreen) {
     72     content::WebContents* web_contents =
     73         browser_view()->GetContentsWebViewForTest()->GetWebContents();
     74     scoped_ptr<FullscreenNotificationObserver> waiter(
     75         new FullscreenNotificationObserver());
     76     browser()->fullscreen_controller()->ToggleFullscreenModeForTab(
     77         web_contents, tab_fullscreen);
     78     waiter->Wait();
     79   }
     80 
     81   // Attempt revealing the top-of-window views.
     82   void AttemptReveal() {
     83     if (!revealed_lock_.get()) {
     84       revealed_lock_.reset(controller_->GetRevealedLock(
     85           ImmersiveModeControllerAsh::ANIMATE_REVEAL_NO));
     86     }
     87   }
     88 
     89   // Attempt unrevealing the top-of-window views.
     90   void AttemptUnreveal() {
     91     revealed_lock_.reset();
     92   }
     93 
     94   ImmersiveModeController* controller() { return controller_; }
     95 
     96  private:
     97   // Not owned.
     98   ImmersiveModeController* controller_;
     99 
    100   scoped_ptr<ImmersiveRevealedLock> revealed_lock_;
    101 
    102   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAshTest);
    103 };
    104 
    105 // Test the layout and visibility of the tabstrip, toolbar and TopContainerView
    106 // in immersive fullscreen.
    107 TEST_F(ImmersiveModeControllerAshTest, Layout) {
    108   AddTab(browser(), GURL("about:blank"));
    109 
    110   TabStrip* tabstrip = browser_view()->tabstrip();
    111   ToolbarView* toolbar = browser_view()->toolbar();
    112   views::WebView* contents_web_view =
    113       browser_view()->GetContentsWebViewForTest();
    114 
    115   // Immersive fullscreen starts out disabled.
    116   ASSERT_FALSE(browser_view()->GetWidget()->IsFullscreen());
    117   ASSERT_FALSE(controller()->IsEnabled());
    118 
    119   // By default, the tabstrip and toolbar should be visible.
    120   EXPECT_TRUE(tabstrip->visible());
    121   EXPECT_TRUE(toolbar->visible());
    122 
    123   ToggleFullscreen();
    124   EXPECT_TRUE(browser_view()->GetWidget()->IsFullscreen());
    125   EXPECT_TRUE(controller()->IsEnabled());
    126   EXPECT_FALSE(controller()->IsRevealed());
    127 
    128   // Entering immersive fullscreen should make the tab strip use the immersive
    129   // style and hide the toolbar.
    130   EXPECT_TRUE(tabstrip->visible());
    131   EXPECT_TRUE(tabstrip->IsImmersiveStyle());
    132   EXPECT_FALSE(toolbar->visible());
    133 
    134   // The tab indicators should be flush with the top of the widget.
    135   EXPECT_EQ(0, GetBoundsInWidget(tabstrip).y());
    136 
    137   // The web contents should be immediately below the tab indicators.
    138   EXPECT_EQ(Tab::GetImmersiveHeight(),
    139             GetBoundsInWidget(contents_web_view).y());
    140 
    141   // Revealing the top-of-window views should set the tab strip back to the
    142   // normal style and show the toolbar.
    143   AttemptReveal();
    144   EXPECT_TRUE(controller()->IsRevealed());
    145   EXPECT_TRUE(tabstrip->visible());
    146   EXPECT_FALSE(tabstrip->IsImmersiveStyle());
    147   EXPECT_TRUE(toolbar->visible());
    148 
    149   // The TopContainerView should be flush with the top edge of the widget. If
    150   // it is not flush with the top edge the immersive reveal animation looks
    151   // wonky.
    152   EXPECT_EQ(0, GetBoundsInWidget(browser_view()->top_container()).y());
    153 
    154   // The web contents should be at the same y position as they were when the
    155   // top-of-window views were hidden.
    156   EXPECT_EQ(Tab::GetImmersiveHeight(),
    157             GetBoundsInWidget(contents_web_view).y());
    158 
    159   // Repeat the test for when in both immersive fullscreen and tab fullscreen.
    160   SetTabFullscreen(true);
    161   // Hide and reveal the top-of-window views so that they get relain out.
    162   AttemptUnreveal();
    163   AttemptReveal();
    164 
    165   // The tab strip and toolbar should still be visible and the TopContainerView
    166   // should still be flush with the top edge of the widget.
    167   EXPECT_TRUE(controller()->IsRevealed());
    168   EXPECT_TRUE(tabstrip->visible());
    169   EXPECT_FALSE(tabstrip->IsImmersiveStyle());
    170   EXPECT_TRUE(toolbar->visible());
    171   EXPECT_EQ(0, GetBoundsInWidget(browser_view()->top_container()).y());
    172 
    173   // The web contents should be flush with the top edge of the widget when in
    174   // both immersive and tab fullscreen.
    175   EXPECT_EQ(0, GetBoundsInWidget(contents_web_view).y());
    176 
    177   // Hide the top-of-window views. Both the tab strip and the toolbar should
    178   // hide when in both immersive and tab fullscreen.
    179   AttemptUnreveal();
    180   EXPECT_FALSE(controller()->IsRevealed());
    181   EXPECT_FALSE(tabstrip->visible());
    182   EXPECT_FALSE(toolbar->visible());
    183 
    184   // The web contents should still be flush with the edge of the widget.
    185   EXPECT_EQ(0, GetBoundsInWidget(contents_web_view).y());
    186 
    187   // Exiting both immersive and tab fullscreen should show the tab strip and
    188   // toolbar.
    189   ToggleFullscreen();
    190   EXPECT_FALSE(browser_view()->GetWidget()->IsFullscreen());
    191   EXPECT_FALSE(controller()->IsEnabled());
    192   EXPECT_FALSE(controller()->IsRevealed());
    193   EXPECT_TRUE(tabstrip->visible());
    194   EXPECT_FALSE(tabstrip->IsImmersiveStyle());
    195   EXPECT_TRUE(toolbar->visible());
    196 }
    197 
    198 // Test that the browser commands which are usually disabled in fullscreen are
    199 // are enabled in immersive fullscreen.
    200 TEST_F(ImmersiveModeControllerAshTest, EnabledCommands) {
    201   ASSERT_FALSE(controller()->IsEnabled());
    202   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPEN_CURRENT_URL));
    203   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ABOUT));
    204   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FOCUS_LOCATION));
    205 
    206   ToggleFullscreen();
    207   EXPECT_TRUE(controller()->IsEnabled());
    208   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPEN_CURRENT_URL));
    209   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_ABOUT));
    210   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FOCUS_LOCATION));
    211 }
    212 
    213 // Test that restoring a window properly exits immersive fullscreen.
    214 TEST_F(ImmersiveModeControllerAshTest, ExitUponRestore) {
    215   ASSERT_FALSE(controller()->IsEnabled());
    216   ToggleFullscreen();
    217   AttemptReveal();
    218   ASSERT_TRUE(controller()->IsEnabled());
    219   ASSERT_TRUE(controller()->IsRevealed());
    220   ASSERT_TRUE(browser_view()->GetWidget()->IsFullscreen());
    221 
    222   browser_view()->GetWidget()->Restore();
    223   EXPECT_FALSE(controller()->IsEnabled());
    224 }
    225 
    226 // Test how being simultaneously in tab fullscreen and immersive fullscreen
    227 // affects the shelf visibility and whether the tab indicators are hidden.
    228 TEST_F(ImmersiveModeControllerAshTest, TabAndBrowserFullscreen) {
    229   AddTab(browser(), GURL("about:blank"));
    230 
    231   // The shelf should start out as visible.
    232   ash::ShelfLayoutManager* shelf =
    233       ash::Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
    234   ASSERT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
    235 
    236   // 1) Test that entering tab fullscreen from immersive fullscreen hides the
    237   // tab indicators and the shelf.
    238   ToggleFullscreen();
    239   ASSERT_TRUE(controller()->IsEnabled());
    240   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    241   EXPECT_FALSE(controller()->ShouldHideTabIndicators());
    242 
    243   SetTabFullscreen(true);
    244   ASSERT_TRUE(controller()->IsEnabled());
    245   EXPECT_EQ(ash::SHELF_HIDDEN, shelf->visibility_state());
    246   EXPECT_TRUE(controller()->ShouldHideTabIndicators());
    247 
    248   // 2) Test that exiting tab fullscreen shows the tab indicators and autohides
    249   // the shelf.
    250   SetTabFullscreen(false);
    251   ASSERT_TRUE(controller()->IsEnabled());
    252   EXPECT_EQ(ash::SHELF_AUTO_HIDE, shelf->visibility_state());
    253   EXPECT_FALSE(controller()->ShouldHideTabIndicators());
    254 
    255   // 3) Test that exiting tab fullscreen and immersive fullscreen
    256   // simultaneously correctly updates the shelf visibility and whether the tab
    257   // indicators should be hidden.
    258   SetTabFullscreen(true);
    259   ToggleFullscreen();
    260   ASSERT_FALSE(controller()->IsEnabled());
    261   EXPECT_EQ(ash::SHELF_VISIBLE, shelf->visibility_state());
    262   EXPECT_TRUE(controller()->ShouldHideTabIndicators());
    263 }
    264 
    265 class ImmersiveModeControllerAshTestHostedApp
    266     : public ImmersiveModeControllerAshTest {
    267  public:
    268   ImmersiveModeControllerAshTestHostedApp()
    269       : ImmersiveModeControllerAshTest(Browser::TYPE_POPUP,
    270                                        chrome::HOST_DESKTOP_TYPE_ASH,
    271                                        true) {
    272   }
    273   virtual ~ImmersiveModeControllerAshTestHostedApp() {}
    274 
    275  private:
    276   DISALLOW_COPY_AND_ASSIGN(ImmersiveModeControllerAshTestHostedApp);
    277 };
    278 
    279 // Test the layout and visibility of the TopContainerView and web contents when
    280 // a hosted app is put into immersive fullscreen.
    281 TEST_F(ImmersiveModeControllerAshTestHostedApp, Layout) {
    282   // Add a tab because the browser starts out without any tabs at all.
    283   AddTab(browser(), GURL("about:blank"));
    284 
    285   TabStrip* tabstrip = browser_view()->tabstrip();
    286   ToolbarView* toolbar = browser_view()->toolbar();
    287   views::WebView* contents_web_view =
    288       browser_view()->GetContentsWebViewForTest();
    289   views::View* top_container = browser_view()->top_container();
    290 
    291   // Immersive fullscreen starts out disabled.
    292   ASSERT_FALSE(browser_view()->GetWidget()->IsFullscreen());
    293   ASSERT_FALSE(controller()->IsEnabled());
    294 
    295   // The tabstrip and toolbar are not visible for hosted apps.
    296   EXPECT_FALSE(tabstrip->visible());
    297   EXPECT_FALSE(toolbar->visible());
    298 
    299   // The window header should be above the web contents.
    300   int header_height = GetBoundsInWidget(contents_web_view).y();
    301 
    302   ToggleFullscreen();
    303   EXPECT_TRUE(browser_view()->GetWidget()->IsFullscreen());
    304   EXPECT_TRUE(controller()->IsEnabled());
    305   EXPECT_FALSE(controller()->IsRevealed());
    306 
    307   // Entering immersive fullscreen should make the web contents flush with the
    308   // top of the widget.
    309   EXPECT_FALSE(tabstrip->visible());
    310   EXPECT_FALSE(toolbar->visible());
    311   EXPECT_TRUE(top_container->GetVisibleBounds().IsEmpty());
    312   EXPECT_EQ(0, GetBoundsInWidget(contents_web_view).y());
    313 
    314   // Reveal the window header.
    315   AttemptReveal();
    316 
    317   // The tabstrip and toolbar should still be hidden and the web contents should
    318   // still be flush with the top of the screen.
    319   EXPECT_FALSE(tabstrip->visible());
    320   EXPECT_FALSE(toolbar->visible());
    321   EXPECT_EQ(0, GetBoundsInWidget(contents_web_view).y());
    322 
    323   // During an immersive reveal, the window header should be painted to the
    324   // TopContainerView. The TopContainerView should be flush with the top of the
    325   // widget and have |header_height|.
    326   gfx::Rect top_container_bounds_in_widget(GetBoundsInWidget(top_container));
    327   EXPECT_EQ(0, top_container_bounds_in_widget.y());
    328   EXPECT_EQ(header_height, top_container_bounds_in_widget.height());
    329 
    330   // Exit immersive fullscreen. The web contents should be back below the window
    331   // header.
    332   ToggleFullscreen();
    333   EXPECT_FALSE(browser_view()->GetWidget()->IsFullscreen());
    334   EXPECT_FALSE(controller()->IsEnabled());
    335   EXPECT_FALSE(tabstrip->visible());
    336   EXPECT_FALSE(toolbar->visible());
    337   EXPECT_EQ(header_height, GetBoundsInWidget(contents_web_view).y());
    338 }
    339