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.AwSettings;
11 import org.chromium.base.test.util.Feature;
12 import org.chromium.content.browser.test.util.CallbackHelper;
13 import org.chromium.ui.gfx.DeviceDisplayInfo;
15 import java.util.Locale;
16 import java.util.concurrent.Callable;
19 * Tests for usage and quirks of viewport related methods.
21 public class AwViewportTest extends AwTestBase {
24 @Feature({"AndroidWebView"})
25 public void testTargetDensityDpi() throws Throwable {
26 final TestAwContentsClient contentClient = new TestAwContentsClient();
27 final AwTestContainerView testContainerView =
28 createAwTestContainerViewOnMainSync(contentClient);
29 final AwContents awContents = testContainerView.getAwContents();
30 AwSettings settings = getAwSettingsOnUiThread(awContents);
31 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
33 final String pageTemplate = "<html><head>" +
34 "<meta name='viewport' content='width=device-width, target-densityDpi=%s' />" +
35 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
36 final String pageDeviceDpi = String.format((Locale)null, pageTemplate, "device-dpi");
37 final String pageHighDpi = String.format((Locale)null, pageTemplate, "high-dpi");
38 final String pageDpi100 = String.format((Locale)null, pageTemplate, "100");
40 settings.setJavaScriptEnabled(true);
42 DeviceDisplayInfo deviceInfo =
43 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
44 loadDataSync(awContents, onPageFinishedHelper, pageDeviceDpi, "text/html", false);
45 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
46 assertEquals(deviceInfo.getDisplayWidth(), actualWidth, 10f);
48 float displayWidth = (deviceInfo.getDisplayWidth());
49 float deviceDpi = (float) (160f * deviceInfo.getDIPScale());
51 loadDataSync(awContents, onPageFinishedHelper, pageHighDpi, "text/html", false);
52 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
53 assertEquals(displayWidth * (240f / deviceDpi), actualWidth, 10f);
55 loadDataSync(awContents, onPageFinishedHelper, pageDpi100, "text/html", false);
56 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
57 assertEquals(displayWidth * (100f / deviceDpi), actualWidth, 10f);
61 @Feature({"AndroidWebView"})
62 public void testWideViewportInitialScaleDoesNotExpandFixedLayoutWidth() throws Throwable {
63 final TestAwContentsClient contentClient = new TestAwContentsClient();
64 final AwTestContainerView testContainerView =
65 createAwTestContainerViewOnMainSync(contentClient);
66 final AwContents awContents = testContainerView.getAwContents();
67 AwSettings settings = getAwSettingsOnUiThread(awContents);
68 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
70 final String page = "<html><head>" +
71 "<meta name='viewport' content='width=device-width, initial-scale=0.5' />" +
72 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
74 settings.setJavaScriptEnabled(true);
75 settings.setUseWideViewPort(true);
77 DeviceDisplayInfo deviceInfo =
78 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
79 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
80 float displayWidth = (float) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
81 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
82 assertEquals(displayWidth, actualWidth, 10f);
83 assertEquals(1.0f, getScaleOnUiThread(awContents));
87 @Feature({"AndroidWebView"})
88 public void testZeroValuesQuirk() throws Throwable {
89 final TestAwContentsClient contentClient = new TestAwContentsClient();
90 final AwTestContainerView testContainerView =
91 createAwTestContainerViewOnMainSync(contentClient);
92 final AwContents awContents = testContainerView.getAwContents();
93 AwSettings settings = getAwSettingsOnUiThread(awContents);
94 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
96 final String page = "<html><head>" +
97 "<meta name='viewport' content='width=0, height=0, initial-scale=0.0, " +
98 " minimum-scale=0.0, maximum-scale=0.0' />" +
99 "</head><body onload='document.title=document.body.clientWidth'></body></html>";
101 settings.setJavaScriptEnabled(true);
103 DeviceDisplayInfo deviceInfo =
104 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
105 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
106 float displayWidth = (float) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
107 int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
108 assertEquals(displayWidth, actualWidth, 10f);
109 assertEquals(1.0f, getScaleOnUiThread(awContents));
111 settings.setUseWideViewPort(true);
112 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
113 actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
114 assertEquals(displayWidth, actualWidth, 10f);
115 assertEquals(1.0f, getScaleOnUiThread(awContents));
119 @Feature({"AndroidWebView"})
120 public void testScreenSizeInPhysicalPixelsQuirk() throws Throwable {
121 final TestAwContentsClient contentClient = new TestAwContentsClient();
122 final AwTestContainerView testContainerView =
123 createAwTestContainerViewOnMainSync(contentClient);
124 final AwContents awContents = testContainerView.getAwContents();
125 AwSettings settings = getAwSettingsOnUiThread(awContents);
126 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
128 settings.setJavaScriptEnabled(true);
130 loadUrlSync(awContents, onPageFinishedHelper, "about:blank");
132 DeviceDisplayInfo deviceInfo =
133 DeviceDisplayInfo.create(getInstrumentation().getTargetContext());
134 float dipScale = (float) deviceInfo.getDIPScale();
135 float physicalDisplayWidth = deviceInfo.getDisplayWidth();
136 float cssDisplayWidth = physicalDisplayWidth / dipScale;
137 float physicalDisplayHeight = deviceInfo.getDisplayHeight();
138 float cssDisplayHeight = physicalDisplayHeight / dipScale;
140 float screenWidth = Integer.parseInt(
141 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.width"));
142 assertEquals(physicalDisplayWidth, screenWidth, 10f);
143 float screenAvailWidth = Integer.parseInt(
144 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.availWidth"));
145 assertEquals(physicalDisplayWidth, screenAvailWidth, 10f);
146 float outerWidth = Integer.parseInt(
147 executeJavaScriptAndWaitForResult(awContents, contentClient, "outerWidth"));
148 float innerWidth = Integer.parseInt(
149 executeJavaScriptAndWaitForResult(awContents, contentClient, "innerWidth"));
150 assertEquals(innerWidth * dipScale, outerWidth, 10f);
151 String deviceWidthEqualsScreenWidth = executeJavaScriptAndWaitForResult(awContents,
153 "matchMedia(\"screen and (device-width:" + (int) screenWidth + "px)\").matches");
154 assertEquals("true", deviceWidthEqualsScreenWidth);
156 float screenHeight = Integer.parseInt(
157 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.height"));
158 assertEquals(physicalDisplayHeight, screenHeight, 10f);
159 float screenAvailHeight = Integer.parseInt(
160 executeJavaScriptAndWaitForResult(awContents, contentClient, "screen.availHeight"));
161 assertEquals(physicalDisplayHeight, screenAvailHeight, 10f);
162 float outerHeight = Integer.parseInt(
163 executeJavaScriptAndWaitForResult(awContents, contentClient, "outerHeight"));
164 float innerHeight = Integer.parseInt(
165 executeJavaScriptAndWaitForResult(awContents, contentClient, "innerHeight"));
166 assertEquals(innerHeight * dipScale, outerHeight, 10f);
167 String deviceHeightEqualsScreenHeight = executeJavaScriptAndWaitForResult(awContents,
169 "matchMedia(\"screen and (device-height:" + (int) screenHeight + "px)\").matches");
170 assertEquals("true", deviceHeightEqualsScreenHeight);
174 @Feature({"AndroidWebView"})
175 public void testMetaMergeContentQuirk() throws Throwable {
176 final TestAwContentsClient contentClient = new TestAwContentsClient();
177 final AwTestContainerView testContainerView =
178 createAwTestContainerViewOnMainSync(contentClient);
179 final AwContents awContents = testContainerView.getAwContents();
180 AwSettings settings = getAwSettingsOnUiThread(awContents);
181 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
183 final int pageWidth = 3000;
184 final float pageScale = 1.0f;
185 final String page = String.format((Locale)null, "<html><head>" +
186 "<meta name='viewport' content='width=%d' />" +
187 "<meta name='viewport' content='initial-scale=%.1f' />" +
188 "<meta name='viewport' content='user-scalable=0' />" +
189 "</head><body onload='document.title=document.body.clientWidth'></body></html>",
190 pageWidth, pageScale);
192 settings.setJavaScriptEnabled(true);
193 settings.setUseWideViewPort(true);
194 settings.setBuiltInZoomControls(true);
195 settings.setSupportZoom(true);
197 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
198 int width = Integer.parseInt(getTitleOnUiThread(awContents));
199 assertEquals(pageWidth, width);
200 assertEquals(pageScale, getScaleOnUiThread(awContents));
201 assertEquals(false, canZoomInOnUiThread(awContents));
202 assertEquals(false, canZoomOutOnUiThread(awContents));
206 @Feature({"AndroidWebView"})
207 public void testMetaMergeContentQuirkOverrides() throws Throwable {
208 final TestAwContentsClient contentClient = new TestAwContentsClient();
209 final AwTestContainerView testContainerView =
210 createAwTestContainerViewOnMainSync(contentClient);
211 final AwContents awContents = testContainerView.getAwContents();
212 AwSettings settings = getAwSettingsOnUiThread(awContents);
213 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
215 final int pageWidth = 3000;
216 final String page = String.format((Locale)null, "<html><head>" +
217 "<meta name='viewport' content='width=device-width' />" +
218 "<meta name='viewport' content='width=%d' />" +
219 "</head><body onload='document.title=document.body.clientWidth'></body></html>",
222 settings.setJavaScriptEnabled(true);
223 settings.setUseWideViewPort(true);
225 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
226 int width = Integer.parseInt(getTitleOnUiThread(awContents));
227 assertEquals(pageWidth, width);
231 @Feature({"AndroidWebView"})
232 public void testInitialScaleClobberQuirk() throws Throwable {
233 final TestAwContentsClient contentClient = new TestAwContentsClient();
234 final AwTestContainerView testContainerView =
235 createAwTestContainerViewOnMainSync(contentClient);
236 final AwContents awContents = testContainerView.getAwContents();
237 AwSettings settings = getAwSettingsOnUiThread(awContents);
238 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
240 final String pageTemplate = "<html><head>" +
241 "<meta name='viewport' content='initial-scale=%d' />" +
243 "<div style='width:10000px;height:200px'>A big div</div>" +
245 final String pageScale4 = String.format((Locale)null, pageTemplate, 4);
246 final String page = String.format((Locale)null, pageTemplate, 1);
248 // Page scale updates are asynchronous. There is an issue that we can't
249 // reliably check, whether the scale as NOT changed (i.e. remains to be 1.0).
250 // So we first change the scale to some non-default value, and then wait
251 // until it gets back to 1.0.
252 int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
253 loadDataSync(awContents, onPageFinishedHelper, pageScale4, "text/html", false);
254 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
255 assertEquals(4.0f, getScaleOnUiThread(awContents));
256 // The following call to set initial scale will be ignored. However, a temporary
257 // page scale change may occur, and this makes the usual onScaleChanged-based workflow
258 // flaky. So instead, we are just polling the scale until it becomes 1.0.
259 settings.setInitialPageScale(50);
260 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
261 ensureScaleBecomes(1.0f, awContents);
265 @Feature({"AndroidWebView"})
266 public void testNoUserScalableQuirk() throws Throwable {
267 final TestAwContentsClient contentClient = new TestAwContentsClient();
268 final AwTestContainerView testContainerView =
269 createAwTestContainerViewOnMainSync(contentClient);
270 final AwContents awContents = testContainerView.getAwContents();
271 CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
273 final String pageScale4 = "<html><head>" +
274 "<meta name='viewport' content='initial-scale=4' />" +
276 "<div style='width:10000px;height:200px'>A big div</div>" +
278 final String page = "<html><head>" +
279 "<meta name='viewport' " +
280 "content='width=device-width,initial-scale=2,user-scalable=no' />" +
282 "<div style='width:10000px;height:200px'>A big div</div>" +
285 // Page scale updates are asynchronous. There is an issue that we can't
286 // reliably check, whether the scale as NOT changed (i.e. remains to be 1.0).
287 // So we first change the scale to some non-default value, and then wait
288 // until it gets back to 1.0.
289 int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
290 loadDataSync(awContents, onPageFinishedHelper, pageScale4, "text/html", false);
291 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
292 assertEquals(4.0f, getScaleOnUiThread(awContents));
293 onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
294 loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
295 contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
296 assertEquals(1.0f, getScaleOnUiThread(awContents));
299 private void ensureScaleBecomes(final float targetScale, final AwContents awContents)
301 poll(new Callable<Boolean>() {
303 public Boolean call() throws Exception {
304 return targetScale == getScaleOnUiThread(awContents);