OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 package org.chromium.chrome.browser.fullscreen; |
| 6 |
| 7 import android.graphics.Rect; |
| 8 import android.graphics.Region; |
| 9 import android.os.Build; |
| 10 import android.os.SystemClock; |
| 11 import android.test.FlakyTest; |
| 12 import android.test.suitebuilder.annotation.LargeTest; |
| 13 import android.test.suitebuilder.annotation.MediumTest; |
| 14 import android.view.View; |
| 15 import android.view.ViewGroup; |
| 16 import android.view.ViewTreeObserver; |
| 17 import android.view.WindowManager; |
| 18 |
| 19 import com.google.android.apps.chrome.R; |
| 20 |
| 21 import org.chromium.base.ThreadUtils; |
| 22 import org.chromium.base.test.util.Feature; |
| 23 import org.chromium.base.test.util.UrlUtils; |
| 24 import org.chromium.chrome.browser.ChromeWebContentsDelegateAndroid; |
| 25 import org.chromium.chrome.browser.Tab; |
| 26 import org.chromium.chrome.browser.omnibox.UrlBar; |
| 27 import org.chromium.chrome.browser.tab.ChromeTab; |
| 28 import org.chromium.chrome.test.ChromeTabbedActivityTestBase; |
| 29 import org.chromium.chrome.test.util.OmniboxTestUtils; |
| 30 import org.chromium.chrome.test.util.PrerenderTestHelper; |
| 31 import org.chromium.chrome.test.util.TestHttpServerClient; |
| 32 import org.chromium.content.browser.ContentViewCore; |
| 33 import org.chromium.content.browser.test.util.Criteria; |
| 34 import org.chromium.content.browser.test.util.CriteriaHelper; |
| 35 import org.chromium.content.browser.test.util.TestTouchUtils; |
| 36 import org.chromium.content.browser.test.util.UiUtils; |
| 37 |
| 38 import java.util.concurrent.Callable; |
| 39 import java.util.concurrent.ExecutionException; |
| 40 import java.util.concurrent.atomic.AtomicInteger; |
| 41 |
| 42 /** |
| 43 * Test suite for verifying the behavior of various fullscreen actions. |
| 44 */ |
| 45 public class FullscreenManagerTest extends ChromeTabbedActivityTestBase { |
| 46 |
| 47 private static final String LONG_HTML_TEST_PAGE = UrlUtils.encodeHtmlDataUri
( |
| 48 "<html><body style='height:10000px;'></body></html>"); |
| 49 private static final String LONG_FULLSCREEN_API_HTML_TEST_PAGE = UrlUtils.en
codeHtmlDataUri( |
| 50 "<html>" |
| 51 + "<head>" |
| 52 + " <meta name=\"viewport\" " |
| 53 + " content=\"width=device-width, initial-scale=1.0, maximum-scal
e=1.0\" />" |
| 54 + " <script>" |
| 55 + " function toggleFullScreen() {" |
| 56 + " if (document.webkitIsFullScreen) {" |
| 57 + " document.webkitCancelFullScreen();" |
| 58 + " } else {" |
| 59 + " document.body.webkitRequestFullScreen();" |
| 60 + " }" |
| 61 + " };" |
| 62 + " </script>" |
| 63 + " <style>" |
| 64 + " body:-webkit-full-screen { background: red; width: 100%; }" |
| 65 + " </style>" |
| 66 + "</head>" |
| 67 + "<body style='height:10000px;' onclick='toggleFullScreen();'>" |
| 68 + "</body>" |
| 69 + "</html>"); |
| 70 |
| 71 @MediumTest |
| 72 @Feature({"Fullscreen"}) |
| 73 public void testTogglePersistentFullscreen() throws InterruptedException { |
| 74 startMainActivityWithURL(LONG_HTML_TEST_PAGE); |
| 75 |
| 76 Tab tab = getActivity().getActivityTab(); |
| 77 final ChromeWebContentsDelegateAndroid delegate = |
| 78 tab.getChromeWebContentsDelegateAndroid(); |
| 79 |
| 80 assertTrue(waitForFullscreenFlag(tab, false)); |
| 81 assertTrue(waitForPersistentFullscreen(delegate, false)); |
| 82 |
| 83 togglePersistentFullscreen(delegate, true); |
| 84 assertTrue(waitForFullscreenFlag(tab, true)); |
| 85 assertTrue(waitForPersistentFullscreen(delegate, true)); |
| 86 |
| 87 togglePersistentFullscreen(delegate, false); |
| 88 assertTrue(waitForFullscreenFlag(tab, false)); |
| 89 assertTrue(waitForPersistentFullscreen(delegate, false)); |
| 90 } |
| 91 |
| 92 @LargeTest |
| 93 @Feature({"Fullscreen"}) |
| 94 public void testPersistentFullscreenChangingUiFlags() throws InterruptedExce
ption { |
| 95 // Exiting fullscreen via UI Flags is not supported in versions prior to
MR2. |
| 96 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return; |
| 97 |
| 98 startMainActivityWithURL(LONG_HTML_TEST_PAGE); |
| 99 |
| 100 final Tab tab = getActivity().getActivityTab(); |
| 101 final ChromeWebContentsDelegateAndroid delegate = |
| 102 tab.getChromeWebContentsDelegateAndroid(); |
| 103 |
| 104 assertTrue(waitForFullscreenFlag(tab, false)); |
| 105 assertTrue(waitForPersistentFullscreen(delegate, false)); |
| 106 |
| 107 togglePersistentFullscreen(delegate, true); |
| 108 assertTrue(waitForFullscreenFlag(tab, true)); |
| 109 assertTrue(waitForPersistentFullscreen(delegate, true)); |
| 110 |
| 111 // There is a race condition in android when setting various system UI f
lags. |
| 112 // Adding this wait to allow the animation transitions to complete befor
e continuing |
| 113 // the test (See https://b/10387660) |
| 114 UiUtils.settleDownUI(getInstrumentation()); |
| 115 |
| 116 ThreadUtils.runOnUiThread(new Runnable() { |
| 117 @Override |
| 118 public void run() { |
| 119 View view = tab.getContentViewCore().getContainerView(); |
| 120 view.setSystemUiVisibility( |
| 121 view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_FULL
SCREEN); |
| 122 } |
| 123 }); |
| 124 assertTrue(waitForFullscreenFlag(tab, true)); |
| 125 assertTrue(waitForPersistentFullscreen(delegate, true)); |
| 126 } |
| 127 |
| 128 @LargeTest |
| 129 @Feature({"Fullscreen"}) |
| 130 public void testExitPersistentFullscreenAllowsManualFullscreen() |
| 131 throws InterruptedException, ExecutionException { |
| 132 startMainActivityWithURL(LONG_FULLSCREEN_API_HTML_TEST_PAGE); |
| 133 |
| 134 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 135 fullscreenManager.setAnimationDurationsForTest(1, 1); |
| 136 int topControlsHeight = fullscreenManager.getTopControlsHeight(); |
| 137 |
| 138 Tab tab = getActivity().getActivityTab(); |
| 139 View view = tab.getView(); |
| 140 final ChromeWebContentsDelegateAndroid delegate = |
| 141 tab.getChromeWebContentsDelegateAndroid(); |
| 142 |
| 143 singleClickView(view, view.getWidth() / 2, view.getHeight() / 2); |
| 144 waitForPersistentFullscreen(delegate, true); |
| 145 assertEquals((float) -topControlsHeight, waitForTopControlsPosition(-top
ControlsHeight)); |
| 146 |
| 147 TestTouchUtils.sleepForDoubleTapTimeout(getInstrumentation()); |
| 148 singleClickView(view, view.getWidth() / 2, view.getHeight() / 2); |
| 149 waitForPersistentFullscreen(delegate, false); |
| 150 waitForNoBrowserTopControlsOffset(); |
| 151 assertEquals((float) 0, waitForTopControlsPosition(0)); |
| 152 |
| 153 scrollTopControls(false); |
| 154 scrollTopControls(true); |
| 155 } |
| 156 |
| 157 /** |
| 158 * Marked flaky on 2015-05-15: http://crbug.com/488393 |
| 159 * @LargeTest |
| 160 * @Feature({"Fullscreen"}) |
| 161 */ |
| 162 @FlakyTest |
| 163 public void testManualHidingShowingTopControls() |
| 164 throws InterruptedException, ExecutionException { |
| 165 startMainActivityWithURL(LONG_HTML_TEST_PAGE); |
| 166 |
| 167 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 168 fullscreenManager.disableBrowserOverrideForTest(); |
| 169 |
| 170 assertEquals(fullscreenManager.getControlOffset(), 0f); |
| 171 |
| 172 scrollTopControls(false); |
| 173 // Reverse the scroll and ensure the controls come back into view. |
| 174 scrollTopControls(true); |
| 175 // Check that the URL bar has not grabbed focus (http://crbug/236365) |
| 176 UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
| 177 assertFalse("Url bar grabbed focus", urlBar.hasFocus()); |
| 178 } |
| 179 |
| 180 @LargeTest |
| 181 @Feature({"Fullscreen"}) |
| 182 public void testHidingTopControlsRemovesSurfaceFlingerOverlay() |
| 183 throws InterruptedException, ExecutionException { |
| 184 startMainActivityWithURL(LONG_HTML_TEST_PAGE); |
| 185 |
| 186 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 187 fullscreenManager.disableBrowserOverrideForTest(); |
| 188 |
| 189 assertEquals(fullscreenManager.getControlOffset(), 0f); |
| 190 |
| 191 // Detect layouts. Note this doesn't actually need to be atomic (just fi
nal). |
| 192 final AtomicInteger layoutCount = new AtomicInteger(); |
| 193 getActivity().getWindow().getDecorView().getViewTreeObserver().addOnGlob
alLayoutListener( |
| 194 new ViewTreeObserver.OnGlobalLayoutListener() { |
| 195 @Override |
| 196 public void onGlobalLayout() { |
| 197 layoutCount.incrementAndGet(); |
| 198 } |
| 199 }); |
| 200 |
| 201 // When the top-controls are removed, we need a layout to trigger the |
| 202 // transparent region for the app to be updated. |
| 203 scrollTopControls(false); |
| 204 boolean layoutOccured = CriteriaHelper.pollForUIThreadCriteria( |
| 205 new Criteria() { |
| 206 @Override |
| 207 public boolean isSatisfied() { |
| 208 return layoutCount.get() > 0; |
| 209 } |
| 210 }); |
| 211 assertTrue(layoutOccured); |
| 212 |
| 213 getInstrumentation().runOnMainSync(new Runnable() { |
| 214 @Override |
| 215 public void run() { |
| 216 // Check that when the top controls are gone, the entire decorVi
ew is contained |
| 217 // in the transparent region of the app. |
| 218 Rect visibleDisplayFrame = new Rect(); |
| 219 Region transparentRegion = new Region(); |
| 220 ViewGroup decorView = (ViewGroup) getActivity().getWindow().get
DecorView(); |
| 221 decorView.getWindowVisibleDisplayFrame(visibleDisplayFrame); |
| 222 decorView.gatherTransparentRegion(transparentRegion); |
| 223 assertTrue(transparentRegion.quickContains(visibleDisplayFrame))
; |
| 224 } |
| 225 }); |
| 226 |
| 227 // Additional manual test that this is working: |
| 228 // - adb shell dumpsys SurfaceFlinger |
| 229 // - Observe that there is no 'Chrome' related overlay listed, only 'Sur
faceview'. |
| 230 } |
| 231 |
| 232 @LargeTest |
| 233 @Feature({"Fullscreen"}) |
| 234 public void testManualFullscreenDisabledForChromePages() |
| 235 throws InterruptedException, ExecutionException { |
| 236 // The credits page was chosen as it is a chrome:// page that is long an
d would support |
| 237 // manual fullscreen if it were supported. |
| 238 startMainActivityWithURL("chrome://credits"); |
| 239 |
| 240 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 241 fullscreenManager.disableBrowserOverrideForTest(); |
| 242 int topControlsHeight = fullscreenManager.getTopControlsHeight(); |
| 243 |
| 244 assertEquals(fullscreenManager.getControlOffset(), 0f); |
| 245 |
| 246 float dragX = 50f; |
| 247 float dragStartY = topControlsHeight * 2; |
| 248 float dragFullY = dragStartY - topControlsHeight; |
| 249 |
| 250 long downTime = SystemClock.uptimeMillis(); |
| 251 dragStart(dragX, dragStartY, downTime); |
| 252 dragTo(dragX, dragX, dragStartY, dragFullY, 100, downTime); |
| 253 assertEquals(0f, waitForTopControlsPosition(0f)); |
| 254 dragEnd(dragX, dragFullY, downTime); |
| 255 assertEquals(0f, waitForTopControlsPosition(0f)); |
| 256 } |
| 257 |
| 258 @LargeTest |
| 259 @Feature({"Fullscreen"}) |
| 260 public void testControlsShownOnUnresponsiveRenderer() |
| 261 throws InterruptedException, ExecutionException { |
| 262 startMainActivityWithURL(LONG_HTML_TEST_PAGE); |
| 263 |
| 264 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 265 fullscreenManager.setAnimationDurationsForTest(1, 1); |
| 266 assertTrue(waitForNoBrowserTopControlsOffset()); |
| 267 assertEquals(fullscreenManager.getControlOffset(), 0f); |
| 268 |
| 269 scrollTopControls(false); |
| 270 |
| 271 Tab tab = getActivity().getActivityTab(); |
| 272 final ChromeWebContentsDelegateAndroid delegate = |
| 273 tab.getChromeWebContentsDelegateAndroid(); |
| 274 ThreadUtils.runOnUiThread(new Runnable() { |
| 275 @Override |
| 276 public void run() { |
| 277 delegate.rendererUnresponsive(); |
| 278 } |
| 279 }); |
| 280 assertEquals(0f, waitForTopControlsPosition(0f)); |
| 281 |
| 282 ThreadUtils.runOnUiThread(new Runnable() { |
| 283 @Override |
| 284 public void run() { |
| 285 delegate.rendererResponsive(); |
| 286 } |
| 287 }); |
| 288 assertTrue(waitForNoBrowserTopControlsOffset()); |
| 289 } |
| 290 |
| 291 /* |
| 292 @LargeTest |
| 293 @Feature({"Fullscreen"}) |
| 294 @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) |
| 295 crbug.com/339668 |
| 296 */ |
| 297 @FlakyTest |
| 298 public void testPrerenderedPageSupportsManualHiding() |
| 299 throws InterruptedException, ExecutionException { |
| 300 startMainActivityOnBlankPage(); |
| 301 |
| 302 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 303 fullscreenManager.disableBrowserOverrideForTest(); |
| 304 |
| 305 final Tab tab = getActivity().getActivityTab(); |
| 306 final String testUrl = TestHttpServerClient.getUrl( |
| 307 "chrome/test/data/android/very_long_google.html"); |
| 308 PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(tes
tUrl, this); |
| 309 assertTrue("loadUrl did not use pre-rendered page.", |
| 310 PrerenderTestHelper.isLoadUrlResultPrerendered(loadUrl(testUrl))
); |
| 311 |
| 312 UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
| 313 OmniboxTestUtils.toggleUrlBarFocus(urlBar, false); |
| 314 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 315 @Override |
| 316 public void run() { |
| 317 ChromeTab.fromTab(tab).processEnableFullscreenRunnableForTest(); |
| 318 } |
| 319 }); |
| 320 |
| 321 scrollTopControls(false); |
| 322 } |
| 323 |
| 324 private void scrollTopControls(boolean show) throws InterruptedException, Ex
ecutionException { |
| 325 ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenM
anager(); |
| 326 int topControlsHeight = fullscreenManager.getTopControlsHeight(); |
| 327 |
| 328 waitForPageToBeScrollable(getActivity().getActivityTab()); |
| 329 |
| 330 float dragX = 50f; |
| 331 // Use a larger scroll range than the height of the top controls to ensu
re we overcome |
| 332 // the delay in a scroll start being sent. |
| 333 float dragStartY = topControlsHeight * 3; |
| 334 float dragEndY = dragStartY - topControlsHeight * 2; |
| 335 float expectedPosition = -topControlsHeight; |
| 336 if (show) { |
| 337 expectedPosition = 0f; |
| 338 float tempDragStartY = dragStartY; |
| 339 dragStartY = dragEndY; |
| 340 dragEndY = tempDragStartY; |
| 341 } |
| 342 long downTime = SystemClock.uptimeMillis(); |
| 343 dragStart(dragX, dragStartY, downTime); |
| 344 dragTo(dragX, dragX, dragStartY, dragEndY, 100, downTime); |
| 345 assertEquals(expectedPosition, waitForTopControlsPosition(expectedPositi
on)); |
| 346 dragEnd(dragX, dragEndY, downTime); |
| 347 assertEquals(expectedPosition, waitForTopControlsPosition(expectedPositi
on)); |
| 348 } |
| 349 |
| 350 private void togglePersistentFullscreen(final ChromeWebContentsDelegateAndro
id delegate, |
| 351 final boolean state) { |
| 352 ThreadUtils.runOnUiThread(new Runnable() { |
| 353 @Override |
| 354 public void run() { |
| 355 delegate.toggleFullscreenModeForTab(state); |
| 356 } |
| 357 }); |
| 358 } |
| 359 |
| 360 private static boolean isFlagSet(int flags, int flag) { |
| 361 return (flags & flag) == flag; |
| 362 } |
| 363 |
| 364 private boolean isFullscreenFlagSet(final Tab tab, final boolean state) { |
| 365 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { |
| 366 View view = tab.getContentViewCore().getContainerView(); |
| 367 int visibility = view.getSystemUiVisibility(); |
| 368 // SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN should only be used during the t
ransition between |
| 369 // fullscreen states, so it should always be cleared when fullscreen
transitions are |
| 370 // completed. |
| 371 return (!isFlagSet(visibility, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
)) |
| 372 && (isFlagSet(visibility, View.SYSTEM_UI_FLAG_FULLSCREEN) ==
state); |
| 373 } else { |
| 374 WindowManager.LayoutParams attributes = |
| 375 getActivity().getWindow().getAttributes(); |
| 376 return isFlagSet( |
| 377 attributes.flags, WindowManager.LayoutParams.FLAG_FULLSCREEN
) == state; |
| 378 } |
| 379 } |
| 380 |
| 381 private boolean waitForFullscreenFlag(final Tab tab, final boolean state) |
| 382 throws InterruptedException { |
| 383 return CriteriaHelper.pollForCriteria(new Criteria() { |
| 384 @Override |
| 385 public boolean isSatisfied() { |
| 386 try { |
| 387 return ThreadUtils.runOnUiThread(new Callable<Boolean>() { |
| 388 @Override |
| 389 public Boolean call() throws Exception { |
| 390 return isFullscreenFlagSet(tab, state); |
| 391 } |
| 392 }).get(); |
| 393 } catch (Exception e) { |
| 394 fail(e.getMessage()); |
| 395 return false; |
| 396 } |
| 397 } |
| 398 }); |
| 399 } |
| 400 |
| 401 private boolean waitForPersistentFullscreen(final ChromeWebContentsDelegateA
ndroid delegate, |
| 402 final boolean state) throws InterruptedException { |
| 403 return CriteriaHelper.pollForCriteria(new Criteria() { |
| 404 @Override |
| 405 public boolean isSatisfied() { |
| 406 try { |
| 407 return ThreadUtils.runOnUiThread(new Callable<Boolean>() { |
| 408 @Override |
| 409 public Boolean call() throws Exception { |
| 410 return state == delegate.isFullscreenForTabOrPending
(); |
| 411 } |
| 412 }).get(); |
| 413 } catch (Exception e) { |
| 414 fail(e.getMessage()); |
| 415 return false; |
| 416 } |
| 417 } |
| 418 }); |
| 419 } |
| 420 |
| 421 private float waitForTopControlsPosition(final float position) |
| 422 throws InterruptedException, ExecutionException { |
| 423 final ChromeFullscreenManager fullscreenManager = getActivity().getFulls
creenManager(); |
| 424 CriteriaHelper.pollForCriteria(new Criteria() { |
| 425 @Override |
| 426 public boolean isSatisfied() { |
| 427 try { |
| 428 return ThreadUtils.runOnUiThread(new Callable<Boolean>() { |
| 429 @Override |
| 430 public Boolean call() throws Exception { |
| 431 return position == fullscreenManager.getControlOffse
t(); |
| 432 } |
| 433 }).get(); |
| 434 } catch (Exception e) { |
| 435 fail(e.getMessage()); |
| 436 return false; |
| 437 } |
| 438 } |
| 439 }); |
| 440 return ThreadUtils.runOnUiThread(new Callable<Float>() { |
| 441 @Override |
| 442 public Float call() throws Exception { |
| 443 return fullscreenManager.getControlOffset(); |
| 444 } |
| 445 }).get(); |
| 446 } |
| 447 |
| 448 private boolean waitForNoBrowserTopControlsOffset() throws InterruptedExcept
ion { |
| 449 final ChromeFullscreenManager fullscreenManager = getActivity().getFulls
creenManager(); |
| 450 return CriteriaHelper.pollForCriteria(new Criteria() { |
| 451 @Override |
| 452 public boolean isSatisfied() { |
| 453 try { |
| 454 return ThreadUtils.runOnUiThread(new Callable<Boolean>() { |
| 455 @Override |
| 456 public Boolean call() throws Exception { |
| 457 return !fullscreenManager.hasBrowserControlOffsetOve
rride(); |
| 458 } |
| 459 }).get(); |
| 460 } catch (Exception e) { |
| 461 fail(e.getMessage()); |
| 462 return false; |
| 463 } |
| 464 } |
| 465 }); |
| 466 } |
| 467 |
| 468 private boolean waitForPageToBeScrollable(final Tab tab) throws InterruptedE
xception { |
| 469 return CriteriaHelper.pollForCriteria(new Criteria() { |
| 470 @Override |
| 471 public boolean isSatisfied() { |
| 472 try { |
| 473 return ThreadUtils.runOnUiThread(new Callable<Boolean>() { |
| 474 @Override |
| 475 public Boolean call() throws Exception { |
| 476 ContentViewCore contentViewCore = tab.getContentView
Core(); |
| 477 return contentViewCore.computeVerticalScrollRange() |
| 478 > contentViewCore.getContainerView().getHeig
ht(); |
| 479 } |
| 480 }).get(); |
| 481 } catch (Exception e) { |
| 482 fail(e.getMessage()); |
| 483 return false; |
| 484 } |
| 485 } |
| 486 }); |
| 487 } |
| 488 |
| 489 @Override |
| 490 protected void startMainActivityWithURL(String url) throws InterruptedExcept
ion { |
| 491 super.startMainActivityWithURL(url); |
| 492 final Tab tab = getActivity().getActivityTab(); |
| 493 ThreadUtils.runOnUiThread(new Runnable() { |
| 494 @Override |
| 495 public void run() { |
| 496 ChromeTab.fromTab(tab).processEnableFullscreenRunnableForTest(); |
| 497 } |
| 498 }); |
| 499 } |
| 500 |
| 501 @Override |
| 502 public void startMainActivity() throws InterruptedException { |
| 503 // Each test will start itself with the appropriate test page. |
| 504 } |
| 505 } |
OLD | NEW |