Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: chrome/browser/ui/fullscreen/flash_fullscreen_interactive_browsertest.cc

Issue 670653005: Fix Flash fullscreen focus regressions, and add interactive_ui_tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove consts in ObjC code. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
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/fullscreen/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"
20
21 namespace {
22
23 #if defined(OS_MACOSX)
24 const bool kIsMacUI = true;
25 #else
26 const bool kIsMacUI = false;
27 #endif
28
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;
37 }
38
39 base::MessageLoop::current()->PostDelayedTask(
40 FROM_HERE,
41 base::MessageLoop::QuitClosure(),
42 base::TimeDelta::FromMilliseconds(20));
43 content::RunMessageLoop();
44 }
45 return true;
46 }
47
48 } // namespace
49
50 // A BrowserTest that opens a test page that launches a simulated fullscreen
51 // Flash plugin. The plugin responds to mouse clicks and key presses by
52 // changing color. Once launched, the browser UI can be tested to confirm the
53 // desired interactive behaviors.
54 class FlashFullscreenInteractiveBrowserTest : public OutOfProcessPPAPITest {
55 public:
56 FlashFullscreenInteractiveBrowserTest() {}
57 virtual ~FlashFullscreenInteractiveBrowserTest() {}
58
59 protected:
60 content::WebContents* GetActiveWebContents() const {
61 return browser()->tab_strip_model()->GetActiveWebContents();
62 }
63
64 // A simple way to convince libcontent and the browser UI that a tab is being
65 // screen captured. During tab capture, Flash fullscreen remains embedded
66 // within the tab content area of a non-fullscreened browser window.
67 void StartFakingTabCapture() {
68 GetActiveWebContents()->IncrementCapturerCount(gfx::Size(360, 240));
69 }
70
71 bool LaunchFlashFullscreen() {
72 // This navigates to a page that runs the simulated fullscreen Flash
73 // plugin. It will block until the plugin has completed an attempt to enter
74 // Flash fullscreen mode.
75 OutOfProcessPPAPITest::RunTest("FlashFullscreenForBrowserUI");
76
77 if (::testing::Test::HasFailure()) {
78 ADD_FAILURE() << ("Failed to launch simulated fullscreen Flash plugin. "
79 "Interactive UI testing cannot proceed.");
80 return false;
81 }
82
83 EXPECT_TRUE(ObserveTabIsInFullscreen(true));
84
85 return !::testing::Test::HasFailure();
86 }
87
88 void UseAcceleratorToOpenNewTab() {
89 content::WebContents* const old_tab_contents = GetActiveWebContents();
90 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
91 browser(), ui::VKEY_T, !kIsMacUI, false, false, kIsMacUI));
92 EXPECT_TRUE(RunLoopUntil(base::Bind(
93 &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
94 base::Unretained(this),
95 old_tab_contents,
96 false)));
97 }
98
99 void UseAcceleratorToSwitchToTab(int tab_index) {
100 content::WebContents* const old_tab_contents = GetActiveWebContents();
101 const ui::KeyboardCode key_code =
102 static_cast<ui::KeyboardCode>(ui::VKEY_1 + tab_index);
103 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
104 browser(), key_code, !kIsMacUI, false, false, kIsMacUI));
105 EXPECT_TRUE(RunLoopUntil(base::Bind(
106 &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
107 base::Unretained(this),
108 old_tab_contents,
109 false)));
110 }
111
112 void PressEscape() {
113 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
114 browser(), ui::VKEY_ESCAPE, false, false, false, false));
115 }
116
117 void PressSpacebar() {
118 EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
119 browser(), ui::VKEY_SPACE, false, false, false, false));
120 }
121
122 void SpamSpacebar() {
123 for (int i = 0; i < 11; ++i)
124 PressSpacebar();
125 }
126
127 void ClickOnTabContainer() {
128 ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
129 }
130
131 void ClickOnOmnibox() {
132 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
133 }
134
135 bool ObserveTabIsInFullscreen(bool expected_in_fullscreen) const {
136 if (!RunLoopUntil(base::Bind(
137 &FlashFullscreenInteractiveBrowserTest::IsObservingTabInFullscreen,
138 base::Unretained(this),
139 GetActiveWebContents(),
140 expected_in_fullscreen)))
141 return false;
142
143 if (expected_in_fullscreen) {
144 if (!GetActiveWebContents()->GetFullscreenRenderWidgetHostView()) {
145 ADD_FAILURE()
146 << "WebContents should have a fullscreen RenderWidgetHostView.";
147 return false;
148 }
149 EXPECT_EQ(GetActiveWebContents()->GetCapturerCount() > 0,
150 !browser()->fullscreen_controller()->
151 IsWindowFullscreenForTabOrPending());
152 }
153
154 return true;
155 }
156
157 bool ObserveFlashHasFocus(content::WebContents* contents,
158 bool expected_to_have_focus) const {
159 if (!RunLoopUntil(base::Bind(
160 &FlashFullscreenInteractiveBrowserTest::IsObservingFlashHasFocus,
161 base::Unretained(this),
162 contents,
163 expected_to_have_focus)))
164 return false;
165
166 if (expected_to_have_focus) {
167 content::RenderWidgetHostView* const web_page_view =
168 contents->GetRenderWidgetHostView();
169 EXPECT_FALSE(web_page_view && web_page_view->HasFocus())
170 << "Both RenderWidgetHostViews cannot have focus at the same time.";
171
172 if (contents == GetActiveWebContents())
173 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
174 VIEW_ID_TAB_CONTAINER));
175 }
176
177 return true;
178 }
179
180 bool ObserveFlashFillColor(SkColor expected_color) const {
181 return RunLoopUntil(base::Bind(
182 &FlashFullscreenInteractiveBrowserTest::IsObservingFlashFillColor,
183 base::Unretained(this),
184 expected_color));
185 }
186
187 private:
188 bool IsObservingTabInFullscreen(content::WebContents* contents,
189 bool expected_in_fullscreen) const {
190 return expected_in_fullscreen == browser()->fullscreen_controller()->
191 IsFullscreenForTabOrPending(contents);
192 }
193
194 bool IsObservingFlashHasFocus(content::WebContents* contents,
195 bool expected_to_have_focus) const {
196 content::RenderWidgetHostView* const flash_fs_view =
197 contents->GetFullscreenRenderWidgetHostView();
198 const bool flash_has_focus = flash_fs_view && flash_fs_view->HasFocus();
199 return flash_has_focus == expected_to_have_focus;
200 }
201
202 bool IsObservingActiveWebContents(content::WebContents* contents,
203 bool expected_active_contents) const {
204 return (contents == GetActiveWebContents()) == expected_active_contents;
205 }
206
207 bool IsObservingFlashFillColor(SkColor expected_color) const {
208 content::RenderWidgetHostView* const flash_fs_view =
209 GetActiveWebContents()->GetFullscreenRenderWidgetHostView();
210 content::RenderWidgetHost* const flash_fs_host =
211 flash_fs_view ? flash_fs_view->GetRenderWidgetHost() : nullptr;
212 if (!flash_fs_host) {
213 ADD_FAILURE() << "Flash fullscreen RenderWidgetHost is gone.";
214 return false;
215 }
216
217 // When a widget is first shown, it can take some time before it is ready
218 // for copying from its backing store. This is a transient condition, and
219 // so it is not being treated as a test failure.
220 if (!flash_fs_host->CanCopyFromBackingStore())
221 return false;
222
223 // Copy and examine the upper-left pixel of the widget and compare it to the
224 // |expected_color|.
225 bool is_expected_color = false;
226 flash_fs_host->CopyFromBackingStore(
227 gfx::Rect(0, 0, 1, 1),
228 gfx::Size(1, 1),
229 base::Bind(
230 &FlashFullscreenInteractiveBrowserTest::CheckBitmapForFillColor,
231 expected_color,
232 &is_expected_color,
233 base::MessageLoop::QuitClosure()),
234 kN32_SkColorType);
235 content::RunMessageLoop();
236
237 return is_expected_color;
238 }
239
240 static void CheckBitmapForFillColor(SkColor expected_color,
241 bool* is_expected_color,
242 const base::Closure& done_cb,
243 bool success,
244 const SkBitmap& bitmap) {
245 if (success) {
246 SkAutoLockPixels lock_pixels(bitmap);
247 if (bitmap.width() > 0 && bitmap.height() > 0)
248 *is_expected_color = (bitmap.getColor(0, 0) == expected_color);
249 }
250 done_cb.Run();
251 }
252
253 DISALLOW_COPY_AND_ASSIGN(FlashFullscreenInteractiveBrowserTest);
254 };
255
256 // Tests that launching and exiting fullscreen-within-tab works.
257 IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
258 FullscreenWithinTab_EscapeKeyExitsFullscreen) {
259 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
260 StartFakingTabCapture();
261 ASSERT_TRUE(LaunchFlashFullscreen());
262 content::WebContents* const first_tab_contents = GetActiveWebContents();
263 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
264 PressEscape();
265 EXPECT_TRUE(ObserveTabIsInFullscreen(false));
266 }
267
268 // This tests that browser UI focus behavior is correct when switching between
269 // tabs; particularly, that that focus between the omnibox and tab contents is
270 // stored/restored correctly. Mouse and keyboard events are used to confirm
271 // that the widget the UI thinks is focused is the one that responds to these
272 // input events.
273 IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
274 FullscreenWithinTab_FocusWhenSwitchingTabs) {
275 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
276 StartFakingTabCapture();
277 ASSERT_TRUE(LaunchFlashFullscreen());
278
279 // Upon entering fullscreen, the Flash widget should have focus and be filled
280 // with green.
281 content::WebContents* const first_tab_contents = GetActiveWebContents();
282 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
283 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorGREEN));
284
285 // Pressing the spacebar on the keyboard should change the fill color to red
286 // to indicate the plugin truly does have the keyboard focus. Clicking on the
287 // view should change the fill color to blue.
288 PressSpacebar();
289 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
290 ClickOnTabContainer();
291 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
292
293 // Launch a new tab. The Flash widget should have lost focus.
294 UseAcceleratorToOpenNewTab();
295 content::WebContents* const second_tab_contents = GetActiveWebContents();
296 ASSERT_NE(first_tab_contents, second_tab_contents);
297 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
298 ClickOnOmnibox();
299 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
300 SpamSpacebar();
301
302 // Switch back to first tab. The plugin should not have responded to the key
303 // presses above (while the omnibox was focused), and should regain focus only
304 // now. Poke it with key and mouse events to confirm.
305 UseAcceleratorToSwitchToTab(0);
306 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
307 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
308 PressSpacebar();
309 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
310 ClickOnTabContainer();
311 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
312
313 // Click on the omnibox while still in the first tab, and the Flash widget
314 // should lose focus. Key presses should not affect the color of the Flash
315 // widget.
316 ClickOnOmnibox();
317 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
318 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
319 SpamSpacebar();
320 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
321
322 // Switch to the second tab, click on the web page content, and then go back
323 // to the first tab. Focus should have been restored to the omnibox when
324 // going back to the first tab, and so key presses should not change the color
325 // of the Flash widget.
326 UseAcceleratorToSwitchToTab(1);
327 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
328 ClickOnTabContainer();
329 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
330 UseAcceleratorToSwitchToTab(0);
331 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
332 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
333 SpamSpacebar();
334 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
335
336 // Clicking on the Flash widget should give it focus again.
337 ClickOnTabContainer();
338 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
339 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
340 PressSpacebar();
341 ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
342
343 // Test that the Escape key is handled as an exit fullscreen command while the
344 // Flash widget has the focus.
345 EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
346 PressEscape();
347 EXPECT_TRUE(ObserveTabIsInFullscreen(false));
348 }
OLDNEW
« no previous file with comments | « no previous file | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698