Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / exclusive_access / flash_fullscreen_interactive_browsertest.cc
blobd0e6b8c8c79cb33e5c668fc17969f40efab5ec71
1 // Copyright 2014 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.
5 #include "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/macros.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/time/time.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/test/base/interactive_test_utils.h"
14 #include "chrome/test/ppapi/ppapi_test.h"
15 #include "content/public/browser/render_widget_host.h"
16 #include "content/public/browser/render_widget_host_view.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/test/test_utils.h"
19 #include "third_party/skia/include/core/SkColor.h"
21 namespace {
23 #if defined(OS_MACOSX)
24 const bool kIsMacUI = true;
25 #else
26 const bool kIsMacUI = false;
27 #endif
29 // Runs the current MessageLoop until |condition| is true or timeout.
30 bool RunLoopUntil(const base::Callback<bool()>& condition) {
31 const base::TimeTicks start_time = base::TimeTicks::Now();
32 while (!condition.Run()) {
33 const base::TimeTicks current_time = base::TimeTicks::Now();
34 if (current_time - start_time > base::TimeDelta::FromSeconds(10)) {
35 ADD_FAILURE() << "Condition not met within ten seconds.";
36 return false;
39 base::MessageLoop::current()->task_runner()->PostDelayedTask(
40 FROM_HERE, base::MessageLoop::QuitClosure(),
41 base::TimeDelta::FromMilliseconds(20));
42 content::RunMessageLoop();
44 return true;
47 } // namespace
49 // A BrowserTest that opens a test page that launches a simulated fullscreen
50 // Flash plugin. The plugin responds to mouse clicks and key presses by
51 // changing color. Once launched, the browser UI can be tested to confirm the
52 // desired interactive behaviors.
53 class FlashFullscreenInteractiveBrowserTest : public OutOfProcessPPAPITest {
54 public:
55 FlashFullscreenInteractiveBrowserTest() {}
56 ~FlashFullscreenInteractiveBrowserTest() override {}
58 protected:
59 content::WebContents* GetActiveWebContents() const {
60 return browser()->tab_strip_model()->GetActiveWebContents();
63 // A simple way to convince libcontent and the browser UI that a tab is being
64 // screen captured. During tab capture, Flash fullscreen remains embedded
65 // within the tab content area of a non-fullscreened browser window.
66 void StartFakingTabCapture() {
67 GetActiveWebContents()->IncrementCapturerCount(gfx::Size(360, 240));
70 bool LaunchFlashFullscreen() {
71 // This navigates to a page that runs the simulated fullscreen Flash
72 // plugin. It will block until the plugin has completed an attempt to enter
73 // Flash fullscreen mode.
74 OutOfProcessPPAPITest::RunTest("FlashFullscreenForBrowserUI");
76 if (::testing::Test::HasFailure()) {
77 ADD_FAILURE() << ("Failed to launch simulated fullscreen Flash plugin. "
78 "Interactive UI testing cannot proceed.");
79 return false;
82 EXPECT_TRUE(ObserveTabIsInFullscreen(true));
84 return !::testing::Test::HasFailure();
87 void UseAcceleratorToOpenNewTab() {
88 content::WebContents* const old_tab_contents = GetActiveWebContents();
89 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
90 browser(), ui::VKEY_T, !kIsMacUI, false, false, kIsMacUI));
91 EXPECT_TRUE(RunLoopUntil(base::Bind(
92 &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
93 base::Unretained(this),
94 old_tab_contents,
95 false)));
98 void UseAcceleratorToSwitchToTab(int tab_index) {
99 content::WebContents* const old_tab_contents = GetActiveWebContents();
100 const ui::KeyboardCode key_code =
101 static_cast<ui::KeyboardCode>(ui::VKEY_1 + tab_index);
102 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
103 browser(), key_code, !kIsMacUI, false, false, kIsMacUI));
104 EXPECT_TRUE(RunLoopUntil(base::Bind(
105 &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
106 base::Unretained(this),
107 old_tab_contents,
108 false)));
111 void PressEscape() {
112 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
113 browser(), ui::VKEY_ESCAPE, false, false, false, false));
116 void PressSpacebar() {
117 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
118 browser(), ui::VKEY_SPACE, false, false, false, false));
121 void SpamSpacebar() {
122 for (int i = 0; i < 11; ++i)
123 PressSpacebar();
126 void ClickOnTabContainer() {
127 ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
130 void ClickOnOmnibox() {
131 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
134 bool ObserveTabIsInFullscreen(bool expected_in_fullscreen) const {
135 if (!RunLoopUntil(base::Bind(
136 &FlashFullscreenInteractiveBrowserTest::IsObservingTabInFullscreen,
137 base::Unretained(this),
138 GetActiveWebContents(),
139 expected_in_fullscreen)))
140 return false;
142 if (expected_in_fullscreen) {
143 if (!GetActiveWebContents()->GetFullscreenRenderWidgetHostView()) {
144 ADD_FAILURE()
145 << "WebContents should have a fullscreen RenderWidgetHostView.";
146 return false;
148 EXPECT_EQ(GetActiveWebContents()->GetCapturerCount() > 0,
149 !browser()
150 ->exclusive_access_manager()
151 ->fullscreen_controller()
152 ->IsWindowFullscreenForTabOrPending());
155 return true;
158 bool ObserveFlashHasFocus(content::WebContents* contents,
159 bool expected_to_have_focus) const {
160 if (!RunLoopUntil(base::Bind(
161 &FlashFullscreenInteractiveBrowserTest::IsObservingFlashHasFocus,
162 base::Unretained(this),
163 contents,
164 expected_to_have_focus)))
165 return false;
167 if (expected_to_have_focus) {
168 content::RenderWidgetHostView* const web_page_view =
169 contents->GetRenderWidgetHostView();
170 EXPECT_FALSE(web_page_view && web_page_view->HasFocus())
171 << "Both RenderWidgetHostViews cannot have focus at the same time.";
173 if (contents == GetActiveWebContents())
174 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
175 VIEW_ID_TAB_CONTAINER));
178 return true;
181 bool ObserveFlashFillColor(SkColor expected_color) const {
182 return RunLoopUntil(base::Bind(
183 &FlashFullscreenInteractiveBrowserTest::IsObservingFlashFillColor,
184 base::Unretained(this),
185 expected_color));
188 private:
189 bool IsObservingTabInFullscreen(content::WebContents* contents,
190 bool expected_in_fullscreen) const {
191 return expected_in_fullscreen ==
192 browser()
193 ->exclusive_access_manager()
194 ->fullscreen_controller()
195 ->IsFullscreenForTabOrPending(contents);
198 bool IsObservingFlashHasFocus(content::WebContents* contents,
199 bool expected_to_have_focus) const {
200 content::RenderWidgetHostView* const flash_fs_view =
201 contents->GetFullscreenRenderWidgetHostView();
202 const bool flash_has_focus = flash_fs_view && flash_fs_view->HasFocus();
203 return flash_has_focus == expected_to_have_focus;
206 bool IsObservingActiveWebContents(content::WebContents* contents,
207 bool expected_active_contents) const {
208 return (contents == GetActiveWebContents()) == expected_active_contents;
211 bool IsObservingFlashFillColor(SkColor expected_color) const {
212 content::RenderWidgetHostView* const flash_fs_view =
213 GetActiveWebContents()->GetFullscreenRenderWidgetHostView();
214 content::RenderWidgetHost* const flash_fs_host =
215 flash_fs_view ? flash_fs_view->GetRenderWidgetHost() : nullptr;
216 if (!flash_fs_host) {
217 ADD_FAILURE() << "Flash fullscreen RenderWidgetHost is gone.";
218 return false;
221 // When a widget is first shown, it can take some time before it is ready
222 // for copying from its backing store. This is a transient condition, and
223 // so it is not being treated as a test failure.
224 if (!flash_fs_host->CanCopyFromBackingStore())
225 return false;
227 // Copy and examine the upper-left pixel of the widget and compare it to the
228 // |expected_color|.
229 bool is_expected_color = false;
230 flash_fs_host->CopyFromBackingStore(
231 gfx::Rect(0, 0, 1, 1),
232 gfx::Size(1, 1),
233 base::Bind(
234 &FlashFullscreenInteractiveBrowserTest::CheckBitmapForFillColor,
235 expected_color,
236 &is_expected_color,
237 base::MessageLoop::QuitClosure()),
238 kN32_SkColorType);
239 content::RunMessageLoop();
241 return is_expected_color;
244 static void CheckBitmapForFillColor(SkColor expected_color,
245 bool* is_expected_color,
246 const base::Closure& done_cb,
247 const SkBitmap& bitmap,
248 content::ReadbackResponse response) {
249 if (response == content::READBACK_SUCCESS) {
250 SkAutoLockPixels lock_pixels(bitmap);
251 if (bitmap.width() > 0 && bitmap.height() > 0)
252 *is_expected_color = (bitmap.getColor(0, 0) == expected_color);
254 done_cb.Run();
257 DISALLOW_COPY_AND_ASSIGN(FlashFullscreenInteractiveBrowserTest);
260 // Tests that launching and exiting fullscreen-within-tab works.
261 IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
262 FullscreenWithinTab_EscapeKeyExitsFullscreen) {
263 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
264 StartFakingTabCapture();
265 ASSERT_TRUE(LaunchFlashFullscreen());
266 content::WebContents* const first_tab_contents = GetActiveWebContents();
267 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
268 PressEscape();
269 EXPECT_TRUE(ObserveTabIsInFullscreen(false));
272 // This tests that browser UI focus behavior is correct when switching between
273 // tabs; particularly, that that focus between the omnibox and tab contents is
274 // stored/restored correctly. Mouse and keyboard events are used to confirm
275 // that the widget the UI thinks is focused is the one that responds to these
276 // input events.
278 // Flaky, see http://crbug.com/444476
279 IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
280 DISABLED_FullscreenWithinTab_FocusWhenSwitchingTabs) {
281 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
282 StartFakingTabCapture();
283 ASSERT_TRUE(LaunchFlashFullscreen());
285 // Upon entering fullscreen, the Flash widget should have focus and be filled
286 // with green.
287 content::WebContents* const first_tab_contents = GetActiveWebContents();
288 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
289 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorGREEN));
291 // Pressing the spacebar on the keyboard should change the fill color to red
292 // to indicate the plugin truly does have the keyboard focus. Clicking on the
293 // view should change the fill color to blue.
294 PressSpacebar();
295 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
296 ClickOnTabContainer();
297 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
299 // Launch a new tab. The Flash widget should have lost focus.
300 UseAcceleratorToOpenNewTab();
301 content::WebContents* const second_tab_contents = GetActiveWebContents();
302 ASSERT_NE(first_tab_contents, second_tab_contents);
303 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
304 ClickOnOmnibox();
305 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
306 SpamSpacebar();
308 // Switch back to first tab. The plugin should not have responded to the key
309 // presses above (while the omnibox was focused), and should regain focus only
310 // now. Poke it with key and mouse events to confirm.
311 UseAcceleratorToSwitchToTab(0);
312 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
313 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
314 PressSpacebar();
315 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
316 ClickOnTabContainer();
317 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
319 // Click on the omnibox while still in the first tab, and the Flash widget
320 // should lose focus. Key presses should not affect the color of the Flash
321 // widget.
322 ClickOnOmnibox();
323 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
324 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
325 SpamSpacebar();
326 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
328 // Switch to the second tab, click on the web page content, and then go back
329 // to the first tab. Focus should have been restored to the omnibox when
330 // going back to the first tab, and so key presses should not change the color
331 // of the Flash widget.
332 UseAcceleratorToSwitchToTab(1);
333 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
334 ClickOnTabContainer();
335 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
336 UseAcceleratorToSwitchToTab(0);
337 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
338 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
339 SpamSpacebar();
340 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
342 // Clicking on the Flash widget should give it focus again.
343 ClickOnTabContainer();
344 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
345 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
346 PressSpacebar();
347 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
349 // Test that the Escape key is handled as an exit fullscreen command while the
350 // Flash widget has the focus.
351 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
352 PressEscape();
353 EXPECT_TRUE(ObserveTabIsInFullscreen(false));