| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser; | 5 package org.chromium.chrome.browser; |
| 6 | 6 |
| 7 import android.graphics.Rect; | 7 import android.graphics.Rect; |
| 8 import android.support.test.filters.MediumTest; | 8 import android.support.test.filters.MediumTest; |
| 9 import android.test.MoreAsserts; | 9 import android.test.MoreAsserts; |
| 10 | 10 |
| 11 import org.junit.Assert; |
| 12 import org.junit.Rule; |
| 13 import org.junit.Test; |
| 14 import org.junit.runner.RunWith; |
| 15 |
| 11 import org.chromium.base.ThreadUtils; | 16 import org.chromium.base.ThreadUtils; |
| 12 import org.chromium.base.test.util.CommandLineFlags; | 17 import org.chromium.base.test.util.CommandLineFlags; |
| 13 import org.chromium.base.test.util.RetryOnFailure; | 18 import org.chromium.base.test.util.RetryOnFailure; |
| 14 import org.chromium.base.test.util.UrlUtils; | 19 import org.chromium.base.test.util.UrlUtils; |
| 15 import org.chromium.chrome.test.ChromeActivityTestCaseBase; | 20 import org.chromium.chrome.test.ChromeActivityTestRule; |
| 21 import org.chromium.chrome.test.ChromeJUnit4ClassRunner; |
| 16 import org.chromium.content.browser.ContentViewCore; | 22 import org.chromium.content.browser.ContentViewCore; |
| 17 import org.chromium.content.browser.test.util.Criteria; | 23 import org.chromium.content.browser.test.util.Criteria; |
| 18 import org.chromium.content.browser.test.util.CriteriaHelper; | 24 import org.chromium.content.browser.test.util.CriteriaHelper; |
| 19 import org.chromium.content.browser.test.util.DOMUtils; | 25 import org.chromium.content.browser.test.util.DOMUtils; |
| 20 import org.chromium.content.browser.test.util.JavaScriptUtils; | 26 import org.chromium.content.browser.test.util.JavaScriptUtils; |
| 21 import org.chromium.content_public.browser.WebContents; | 27 import org.chromium.content_public.browser.WebContents; |
| 22 import org.chromium.ui.UiUtils; | 28 import org.chromium.ui.UiUtils; |
| 23 | 29 |
| 24 import java.util.Locale; | 30 import java.util.Locale; |
| 25 import java.util.concurrent.ExecutionException; | 31 import java.util.concurrent.ExecutionException; |
| 26 import java.util.concurrent.TimeoutException; | 32 import java.util.concurrent.TimeoutException; |
| 27 import java.util.concurrent.atomic.AtomicReference; | 33 import java.util.concurrent.atomic.AtomicReference; |
| 28 | 34 |
| 29 | 35 |
| 30 /** | 36 /** |
| 31 * Integration test to ensure that OSK resizes only the visual viewport. | 37 * Integration test to ensure that OSK resizes only the visual viewport. |
| 32 */ | 38 */ |
| 33 | 39 |
| 34 public class OSKOverscrollTest extends ChromeActivityTestCaseBase<ChromeActivity
> { | 40 @RunWith(ChromeJUnit4ClassRunner.class) |
| 41 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, |
| 42 ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG}) |
| 43 public class OSKOverscrollTest { |
| 44 @Rule |
| 45 public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = |
| 46 new ChromeActivityTestRule<>(ChromeActivity.class); |
| 47 |
| 35 private static final String FIXED_FOOTER_PAGE = UrlUtils.encodeHtmlDataUri("
" | 48 private static final String FIXED_FOOTER_PAGE = UrlUtils.encodeHtmlDataUri("
" |
| 36 + "<html>" | 49 + "<html>" |
| 37 + "<head>" | 50 + "<head>" |
| 38 + " <meta name=\"viewport\" " | 51 + " <meta name=\"viewport\" " |
| 39 + " content=\"width=device-width, initial-scale=1.0, maximum-scal
e=1.0\" />" | 52 + " content=\"width=device-width, initial-scale=1.0, maximum-scal
e=1.0\" />" |
| 40 + " <style>" | 53 + " <style>" |
| 41 + " body {" | 54 + " body {" |
| 42 + " height:1500px;" | 55 + " height:1500px;" |
| 43 + " margin:0px;" | 56 + " margin:0px;" |
| 44 + " }" | 57 + " }" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 58 + " <div id=\"footer\"></div>" | 71 + " <div id=\"footer\"></div>" |
| 59 + " </form>" | 72 + " </form>" |
| 60 + "</body>" | 73 + "</body>" |
| 61 + "</html>"); | 74 + "</html>"); |
| 62 | 75 |
| 63 // We convert CSS pixels into device pixels and compare the viewport size be
fore and after the | 76 // We convert CSS pixels into device pixels and compare the viewport size be
fore and after the |
| 64 // keyboard show. window.innerHeight returns an integer and the actual heigh
t is a floating | 77 // keyboard show. window.innerHeight returns an integer and the actual heigh
t is a floating |
| 65 // point. Need some buffer for error. | 78 // point. Need some buffer for error. |
| 66 private static final int ERROR_EPS_PIX = 1; | 79 private static final int ERROR_EPS_PIX = 1; |
| 67 | 80 |
| 68 public OSKOverscrollTest() { | |
| 69 super(ChromeActivity.class); | |
| 70 } | |
| 71 | |
| 72 @Override | |
| 73 public void startMainActivity() { | |
| 74 // Don't launch activity automatically. | |
| 75 } | |
| 76 | |
| 77 private void waitForKeyboard() { | 81 private void waitForKeyboard() { |
| 78 // Wait until the keyboard is showing. | 82 // Wait until the keyboard is showing. |
| 79 CriteriaHelper.pollUiThread(new Criteria("Keyboard was never shown.") { | 83 CriteriaHelper.pollUiThread(new Criteria("Keyboard was never shown.") { |
| 80 @Override | 84 @Override |
| 81 public boolean isSatisfied() { | 85 public boolean isSatisfied() { |
| 82 return UiUtils.isKeyboardShowing( | 86 return UiUtils.isKeyboardShowing(mActivityTestRule.getActivity()
, |
| 83 getActivity(), | 87 mActivityTestRule.getActivity() |
| 84 getActivity().getCurrentContentViewCore().getContainerVi
ew()); | 88 .getCurrentContentViewCore() |
| 89 .getContainerView()); |
| 85 } | 90 } |
| 86 }); | 91 }); |
| 87 } | 92 } |
| 88 | 93 |
| 89 private int getViewportHeight(WebContents webContents) { | 94 private int getViewportHeight(WebContents webContents) { |
| 90 try { | 95 try { |
| 91 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( | 96 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| 92 webContents, "window.innerHeight"); | 97 webContents, "window.innerHeight"); |
| 93 MoreAsserts.assertNotEqual(jsonText.trim().toLowerCase(Locale.US), "
null"); | 98 MoreAsserts.assertNotEqual(jsonText.trim().toLowerCase(Locale.US), "
null"); |
| 94 return Integer.parseInt(jsonText); | 99 return Integer.parseInt(jsonText); |
| 95 } catch (Exception ex) { | 100 } catch (Exception ex) { |
| 96 fail(ex.toString()); | 101 Assert.fail(ex.toString()); |
| 97 } | 102 } |
| 98 return -1; | 103 return -1; |
| 99 } | 104 } |
| 100 | 105 |
| 101 private boolean almostEqual(int a, int b) { | 106 private boolean almostEqual(int a, int b) { |
| 102 return Math.abs(a - b) <= ERROR_EPS_PIX; | 107 return Math.abs(a - b) <= ERROR_EPS_PIX; |
| 103 } | 108 } |
| 104 | 109 |
| 105 /** | 110 /** |
| 106 * Verify that OSK show only resizes the visual viewport when the ENABLE_OSK
_OVERSCROLL flag is | 111 * Verify that OSK show only resizes the visual viewport when the ENABLE_OSK
_OVERSCROLL flag is |
| 107 * set. | 112 * set. |
| 108 * @throws InterruptedException | 113 * @throws InterruptedException |
| 109 * @throws TimeoutException | 114 * @throws TimeoutException |
| 110 * @throws ExecutionException | 115 * @throws ExecutionException |
| 111 */ | 116 */ |
| 117 @Test |
| 112 @MediumTest | 118 @MediumTest |
| 113 @CommandLineFlags.Add({ChromeSwitches.ENABLE_OSK_OVERSCROLL}) | 119 @CommandLineFlags.Add({ChromeSwitches.ENABLE_OSK_OVERSCROLL}) |
| 114 @RetryOnFailure | 120 @RetryOnFailure |
| 115 public void testOnlyVisualViewportResizes() | 121 public void testOnlyVisualViewportResizes() |
| 116 throws InterruptedException, TimeoutException, ExecutionException { | 122 throws InterruptedException, TimeoutException, ExecutionException { |
| 117 startMainActivityWithURL(FIXED_FOOTER_PAGE); | 123 mActivityTestRule.startMainActivityWithURL(FIXED_FOOTER_PAGE); |
| 118 | 124 |
| 119 final AtomicReference<ContentViewCore> viewCoreRef = new AtomicReference
<ContentViewCore>(); | 125 final AtomicReference<ContentViewCore> viewCoreRef = new AtomicReference
<ContentViewCore>(); |
| 120 final AtomicReference<WebContents> webContentsRef = new AtomicReference<
WebContents>(); | 126 final AtomicReference<WebContents> webContentsRef = new AtomicReference<
WebContents>(); |
| 121 ThreadUtils.runOnUiThreadBlocking(new Runnable() { | 127 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 122 @Override | 128 @Override |
| 123 public void run() { | 129 public void run() { |
| 124 viewCoreRef.set(getActivity().getCurrentContentViewCore()); | 130 viewCoreRef.set(mActivityTestRule.getActivity().getCurrentConten
tViewCore()); |
| 125 webContentsRef.set(viewCoreRef.get().getWebContents()); | 131 webContentsRef.set(viewCoreRef.get().getWebContents()); |
| 126 } | 132 } |
| 127 }); | 133 }); |
| 128 | 134 |
| 129 DOMUtils.waitForNonZeroNodeBounds(webContentsRef.get(), "fn"); | 135 DOMUtils.waitForNonZeroNodeBounds(webContentsRef.get(), "fn"); |
| 130 | 136 |
| 131 // Get the position of the footer and the viewport height before bringin
g up the OSK. | 137 // Get the position of the footer and the viewport height before bringin
g up the OSK. |
| 132 Rect footerPositionBefore = DOMUtils.getNodeBounds(webContentsRef.get(),
"footer"); | 138 Rect footerPositionBefore = DOMUtils.getNodeBounds(webContentsRef.get(),
"footer"); |
| 133 final int viewportHeightBeforeCss = getViewportHeight(webContentsRef.get
()); | 139 final int viewportHeightBeforeCss = getViewportHeight(webContentsRef.get
()); |
| 134 final float cssToDevicePixFactor = viewCoreRef.get().getPageScaleFactor(
) | 140 final float cssToDevicePixFactor = viewCoreRef.get().getPageScaleFactor(
) |
| 135 * viewCoreRef.get().getDeviceScaleFactor(); | 141 * viewCoreRef.get().getDeviceScaleFactor(); |
| 136 | 142 |
| 137 // Click on the unfocused input element for the first time to focus on i
t. This brings up | 143 // Click on the unfocused input element for the first time to focus on i
t. This brings up |
| 138 // the OSK. | 144 // the OSK. |
| 139 DOMUtils.clickNode(viewCoreRef.get(), "fn"); | 145 DOMUtils.clickNode(viewCoreRef.get(), "fn"); |
| 140 | 146 |
| 141 waitForKeyboard(); | 147 waitForKeyboard(); |
| 142 | 148 |
| 143 // Get the position of the footer after bringing up the OSK. This should
be the same as the | 149 // Get the position of the footer after bringing up the OSK. This should
be the same as the |
| 144 // position before because only the visual viewport should have resized. | 150 // position before because only the visual viewport should have resized. |
| 145 Rect footerPositionAfter = DOMUtils.getNodeBounds(webContentsRef.get(),
"footer"); | 151 Rect footerPositionAfter = DOMUtils.getNodeBounds(webContentsRef.get(),
"footer"); |
| 146 assertEquals(footerPositionBefore, footerPositionAfter); | 152 Assert.assertEquals(footerPositionBefore, footerPositionAfter); |
| 147 | 153 |
| 148 CriteriaHelper.pollInstrumentationThread(new Criteria() { | 154 CriteriaHelper.pollInstrumentationThread(new Criteria() { |
| 149 @Override | 155 @Override |
| 150 public boolean isSatisfied() { | 156 public boolean isSatisfied() { |
| 151 // Verify that the size of the viewport before the OSK show is e
qual to the size of | 157 // Verify that the size of the viewport before the OSK show is e
qual to the size of |
| 152 // the viewport after the OSK show plus the size of the keyboard
. | 158 // the viewport after the OSK show plus the size of the keyboard
. |
| 153 int viewportHeightAfterCss = getViewportHeight(webContentsRef.ge
t()); | 159 int viewportHeightAfterCss = getViewportHeight(webContentsRef.ge
t()); |
| 154 int keyboardHeight = getActivity().getActivityTab().getSystemWin
dowInsetBottom(); | 160 int keyboardHeight = mActivityTestRule.getActivity() |
| 161 .getActivityTab() |
| 162 .getSystemWindowInsetBottom(); |
| 155 | 163 |
| 156 int priorHeight = (int) (viewportHeightBeforeCss * cssToDevicePi
xFactor); | 164 int priorHeight = (int) (viewportHeightBeforeCss * cssToDevicePi
xFactor); |
| 157 int afterHeightPlusKeyboard = | 165 int afterHeightPlusKeyboard = |
| 158 (int) (viewportHeightAfterCss * cssToDevicePixFactor) +
keyboardHeight; | 166 (int) (viewportHeightAfterCss * cssToDevicePixFactor) +
keyboardHeight; |
| 159 updateFailureReason("Values [" + priorHeight + "], [" + afterHei
ghtPlusKeyboard | 167 updateFailureReason("Values [" + priorHeight + "], [" + afterHei
ghtPlusKeyboard |
| 160 + "] did not match within allowed error range [" + ERROR
_EPS_PIX + "]"); | 168 + "] did not match within allowed error range [" + ERROR
_EPS_PIX + "]"); |
| 161 return almostEqual(priorHeight, afterHeightPlusKeyboard); | 169 return almostEqual(priorHeight, afterHeightPlusKeyboard); |
| 162 } | 170 } |
| 163 }); | 171 }); |
| 164 } | 172 } |
| 165 } | 173 } |
| OLD | NEW |