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.
5 package org.chromium.android_webview.test;
7 import android.test.suitebuilder.annotation.MediumTest;
9 import org.chromium.android_webview.AwContents;
10 import org.chromium.android_webview.AwContentsClient;
11 import org.chromium.android_webview.AwSettings;
12 import org.chromium.base.test.util.Feature;
13 import org.chromium.content.browser.test.util.CallbackHelper;
14 import org.chromium.ui.gfx.DeviceDisplayInfo;
16 import java.util.Locale;
17 import java.util.concurrent.Callable;
20 * Tests for legacy quirks (compatibility with WebView Classic).
22 public class AwLegacyQuirksTest extends AwTestBase {
25 @Feature({"AndroidWebView"})
26 public void testTargetDensityDpi() throws Throwable {
27 final TestAwContentsClient contentClient = new TestAwContentsClient();
28 final AwTestContainerView testContainerView =
29 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
30 final AwContents awContents = testContainerView.getAwContents();
31 AwSettings settings = getAwSettingsOnUiThread(awContents);
32 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
34 final String pageTemplate = "<html><head>" +
35 "<meta name='viewport' content='width=device-width, target-densityDpi=%s' />" +
36 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
37 final String pageDeviceDpi = String.format((Locale)null, pageTemplate, "device-dpi");
38 final String pageHighDpi = String.format((Locale)null, pageTemplate, "high-dpi");
39 final String pageDpi100 = String.format((Locale)null, pageTemplate, "100");
41 settings.setJavaScriptEnabled(true);
43 DeviceDisplayInfo deviceInfo =
44 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
45 loadDataSync(awContents, onPageFinishedHelper, pageDeviceDpi, "text/html", false);
46 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
47 assertEquals(deviceInfo.getDisplayWidth(), actualWidth, 10f);
49 float displayWidth = (deviceInfo.getDisplayWidth());
50 float deviceDpi = (float) (160f * deviceInfo.getDIPScale());
52 loadDataSync(awContents, onPageFinishedHelper, pageHighDpi, "text/html", false);
53 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
54 assertEquals(displayWidth * (240f / deviceDpi), actualWidth, 10f);
56 loadDataSync(awContents, onPageFinishedHelper, pageDpi100, "text/html", false);
57 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
58 assertEquals(displayWidth * (100f / deviceDpi), actualWidth, 10f);
62 @Feature({"AndroidWebView"})
63 public void testWideViewportInitialScaleDoesNotExpandFixedLayoutWidth() throws Throwable {
64 final TestAwContentsClient contentClient = new TestAwContentsClient();
65 final AwTestContainerView testContainerView =
66 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
67 final AwContents awContents = testContainerView.getAwContents();
68 AwSettings settings = getAwSettingsOnUiThread(awContents);
69 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
71 final String page = "<html><head>" +
72 "<meta name='viewport' content='width=device-width, initial-scale=0.5' />" +
73 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
75 settings.setJavaScriptEnabled(true);
76 settings.setUseWideViewPort(true);
78 DeviceDisplayInfo deviceInfo =
79 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
80 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
81 float displayWidth = (float) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
82 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
83 assertEquals(displayWidth, actualWidth, 10f);
84 assertEquals(1.0f, getScaleOnUiThread(awContents));
88 @Feature({"AndroidWebView"})
89 public void testZeroValuesQuirk() throws Throwable {
90 final TestAwContentsClient contentClient = new TestAwContentsClient();
91 final AwTestContainerView testContainerView =
92 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
93 final AwContents awContents = testContainerView.getAwContents();
94 AwSettings settings = getAwSettingsOnUiThread(awContents);
95 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
97 final String page = "<html><head>" +
98 "<meta name='viewport' content='width=0, height=0, initial-scale=0.0, " +
99 " minimum-scale=0.0, maximum-scale=0.0' />" +
100 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
102 settings.setJavaScriptEnabled(true);
104 DeviceDisplayInfo deviceInfo =
105 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
106 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
107 float displayWidth = (float) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
108 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
109 assertEquals(displayWidth, actualWidth, 10f);
110 assertEquals(1.0f, getScaleOnUiThread(awContents));
112 settings.setUseWideViewPort(true);
113 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
114 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
115 assertEquals(displayWidth, actualWidth, 10f);
116 assertEquals(1.0f, getScaleOnUiThread(awContents));
120 @Feature({"AndroidWebView"})
121 public void testScreenSizeInPhysicalPixelsQuirk() throws Throwable {
122 final TestAwContentsClient contentClient = new TestAwContentsClient();
123 final AwTestContainerView testContainerView =
124 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
125 final AwContents awContents = testContainerView.getAwContents();
126 AwSettings settings = getAwSettingsOnUiThread(awContents);
127 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
129 settings.setJavaScriptEnabled(true);
131 loadUrlSync(awContents, onPageFinishedHelper, "about:blank");
133 DeviceDisplayInfo deviceInfo =
134 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
135 float dipScale = (float) deviceInfo.getDIPScale();
136 float physicalDisplayWidth = deviceInfo.getPhysicalDisplayWidth() != 0 ?
137 deviceInfo.getPhysicalDisplayWidth() :
138 deviceInfo.getDisplayWidth();
139 float cssDisplayWidth = physicalDisplayWidth / dipScale;
140 float physicalDisplayHeight = deviceInfo.getPhysicalDisplayHeight() != 0 ?
141 deviceInfo.getPhysicalDisplayHeight() :
142 deviceInfo.getDisplayHeight();
143 float cssDisplayHeight = physicalDisplayHeight / dipScale;
145 float screenWidth = Integer.parseInt(
146 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.width"));
147 assertEquals(physicalDisplayWidth, screenWidth, 10f);
148 float screenAvailWidth = Integer.parseInt(
149 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.availWidth"));
150 assertEquals(physicalDisplayWidth, screenAvailWidth, 10f);
151 float outerWidth = Integer.parseInt(
152 executeJavaScriptAndWaitForResult(awContents, contentClient, "outerWidth"));
153 float innerWidth = Integer.parseInt(
154 executeJavaScriptAndWaitForResult(awContents, contentClient, "innerWidth"));
155 assertEquals(innerWidth * dipScale, outerWidth, 10f);
156 String deviceWidthEqualsScreenWidth = executeJavaScriptAndWaitForResult(awContents,
158 "matchMedia(\"screen and (device-width:" + (int) screenWidth + "px)\").matches");
159 assertEquals("true", deviceWidthEqualsScreenWidth);
161 float screenHeight = Integer.parseInt(
162 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.height"));
163 assertEquals(physicalDisplayHeight, screenHeight, 10f);
164 float screenAvailHeight = Integer.parseInt(
165 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.availHeight"));
166 assertEquals(physicalDisplayHeight, screenAvailHeight, 10f);
167 float outerHeight = Integer.parseInt(
168 executeJavaScriptAndWaitForResult(awContents, contentClient, "outerHeight"));
169 float innerHeight = Integer.parseInt(
170 executeJavaScriptAndWaitForResult(awContents, contentClient, "innerHeight"));
171 assertEquals(innerHeight * dipScale, outerHeight, 10f);
172 String deviceHeightEqualsScreenHeight = executeJavaScriptAndWaitForResult(awContents,
174 "matchMedia(\"screen and (device-height:" + (int) screenHeight + "px)\").matches");
175 assertEquals("true", deviceHeightEqualsScreenHeight);
179 @Feature({"AndroidWebView"})
180 public void testMetaMergeContentQuirk() throws Throwable {
181 final TestAwContentsClient contentClient = new TestAwContentsClient();
182 final AwTestContainerView testContainerView =
183 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
184 final AwContents awContents = testContainerView.getAwContents();
185 AwSettings settings = getAwSettingsOnUiThread(awContents);
186 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
188 final int pageWidth = 3000;
189 final float pageScale = 1.0f;
190 final String page = String.format((Locale)null, "<html><head>" +
191 "<meta name='viewport' content='width=%d' />" +
192 "<meta name='viewport' content='initial-scale=%.1f' />" +
193 "<meta name='viewport' content='user-scalable=0' />" +
194 "</head><body onload='document.title=document.body.clientWidth'></body></html>",
195 pageWidth, pageScale);
197 settings.setJavaScriptEnabled(true);
198 settings.setUseWideViewPort(true);
199 settings.setBuiltInZoomControls(true);
200 settings.setSupportZoom(true);
202 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
203 // ContentView must update itself according to the viewport setup.
204 // As we specify 'user-scalable=0', the page must become non-zoomable.
205 poll(new Callable<Boolean>() {
207 public Boolean call() throws Exception {
208 return !canZoomInOnUiThread(awContents) && !canZoomOutOnUiThread(awContents);
211 int width = Integer.parseInt(getTitleOnUiThread(awContents));
212 assertEquals(pageWidth, width);
213 assertEquals(pageScale, getScaleOnUiThread(awContents));
217 @Feature({"AndroidWebView"})
218 public void testMetaMergeContentQuirkOverrides() throws Throwable {
219 final TestAwContentsClient contentClient = new TestAwContentsClient();
220 final AwTestContainerView testContainerView =
221 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
222 final AwContents awContents = testContainerView.getAwContents();
223 AwSettings settings = getAwSettingsOnUiThread(awContents);
224 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
226 final int pageWidth = 3000;
227 final String page = String.format((Locale)null, "<html><head>" +
228 "<meta name='viewport' content='width=device-width' />" +
229 "<meta name='viewport' content='width=%d' />" +
230 "</head><body onload='document.title=document.body.clientWidth'></body></html>",
233 settings.setJavaScriptEnabled(true);
234 settings.setUseWideViewPort(true);
236 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
237 int width = Integer.parseInt(getTitleOnUiThread(awContents));
238 assertEquals(pageWidth, width);
242 @Feature({"AndroidWebView"})
243 public void testInitialScaleClobberQuirk() throws Throwable {
244 final TestAwContentsClient contentClient = new TestAwContentsClient();
245 final AwTestContainerView testContainerView =
246 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
247 final AwContents awContents = testContainerView.getAwContents();
248 AwSettings settings = getAwSettingsOnUiThread(awContents);
249 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
251 final String pageTemplate = "<html><head>" +
252 "<meta name='viewport' content='initial-scale=%d' />" +
254 "<div style='width:10000px;height:200px'>A big div</div>" +
256 final String pageScale4 = String.format((Locale)null, pageTemplate, 4);
257 final String page = String.format((Locale)null, pageTemplate, 1);
259 // Page scale updates are asynchronous. There is an issue that we can't
260 // reliably check, whether the scale as NOT changed (i.e. remains to be 1.0).
261 // So we first change the scale to some non-default value, and then wait
262 // until it gets back to 1.0.
263 int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
264 loadDataSync(awContents, onPageFinishedHelper, pageScale4, "text/html", false);
265 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
266 assertEquals(4.0f, getScaleOnUiThread(awContents));
267 // The following call to set initial scale will be ignored. However, a temporary
268 // page scale change may occur, and this makes the usual onScaleChanged-based workflow
269 // flaky. So instead, we are just polling the scale until it becomes 1.0.
270 settings.setInitialPageScale(50);
271 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
272 ensureScaleBecomes(1.0f, awContents);
276 @Feature({"AndroidWebView"})
277 public void testNoUserScalableQuirk() throws Throwable {
278 final TestAwContentsClient contentClient = new TestAwContentsClient();
279 final AwTestContainerView testContainerView =
280 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
281 final AwContents awContents = testContainerView.getAwContents();
282 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
284 final String pageScale4 = "<html><head>" +
285 "<meta name='viewport' content='initial-scale=4' />" +
287 "<div style='width:10000px;height:200px'>A big div</div>" +
289 final String page = "<html><head>" +
290 "<meta name='viewport' " +
291 "content='width=device-width,initial-scale=2,user-scalable=no' />" +
293 "<div style='width:10000px;height:200px'>A big div</div>" +
296 // Page scale updates are asynchronous. There is an issue that we can't
297 // reliably check, whether the scale as NOT changed (i.e. remains to be 1.0).
298 // So we first change the scale to some non-default value, and then wait
299 // until it gets back to 1.0.
300 int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
301 loadDataSync(awContents, onPageFinishedHelper, pageScale4, "text/html", false);
302 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
303 assertEquals(4.0f, getScaleOnUiThread(awContents));
304 onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
305 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
306 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
307 assertEquals(1.0f, getScaleOnUiThread(awContents));
310 // background shorthand property must not override background-size when
313 @Feature({"AndroidWebView", "Preferences"})
314 public void testUseLegacyBackgroundSizeShorthandBehavior() throws Throwable {
315 final TestAwContentsClient contentClient = new TestAwContentsClient();
316 final AwTestContainerView testContainerView =
317 createAwTestContainerViewOnMainSyncInQuirksMode(contentClient);
318 final AwContents awContents = testContainerView.getAwContents();
319 AwSettings settings = getAwSettingsOnUiThread(awContents);
320 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
321 final String expectedBackgroundSize = "cover";
322 final String page = "<html><head>" +
324 "function getBackgroundSize() {" +
325 " var e = document.getElementById('test'); " +
326 " e.style.backgroundSize = '" + expectedBackgroundSize + "';" +
327 " e.style.background = 'center red url(dummy://test.png) no-repeat border-box'; " +
328 " return e.style.backgroundSize; " +
331 "<body onload='document.title=getBackgroundSize()'>" +
332 " <div id='test'> </div>" +
334 settings.setJavaScriptEnabled(true);
335 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
336 String actualBackgroundSize = getTitleOnUiThread(awContents);
337 assertEquals(expectedBackgroundSize, actualBackgroundSize);
340 private AwTestContainerView createAwTestContainerViewOnMainSyncInQuirksMode(
341 final AwContentsClient client) throws Exception {
342 return createAwTestContainerViewOnMainSync(client, true);
345 private void ensureScaleBecomes(final float targetScale, final AwContents awContents)
347 poll(new Callable<Boolean>() {
349 public Boolean call() throws Exception {
350 return targetScale == getScaleOnUiThread(awContents);