immersive_mode_controller_ash_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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
26class 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.
107TEST_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.
200TEST_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.
214TEST_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.
228TEST_F(ImmersiveModeControllerAshTest, TabAndBrowserFullscreen) {
229  AddTab(browser(), GURL("about:blank"));
230
231  // The shelf should start out as visible.
232  ash::internal::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
265class 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.
281TEST_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