50129bd07d662c41e9efc88e4e2f50493b6daaaa
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwZoomTest.java
1 // Copyright 2012 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.android_webview.test;
6
7 import android.app.Activity;
8 import android.content.pm.ActivityInfo;
9 import android.test.suitebuilder.annotation.SmallTest;
10 import android.view.View;
11 import android.view.ViewConfiguration;
12
13 import org.chromium.android_webview.AwContents;
14 import org.chromium.android_webview.AwSettings;
15 import org.chromium.base.ThreadUtils;
16 import org.chromium.base.test.util.Feature;
17
18 import java.util.Locale;
19 import java.util.concurrent.Callable;
20
21 /**
22  * A test suite for zooming-related methods and settings.
23  */
24 public class AwZoomTest extends AwTestBase {
25     private TestAwContentsClient mContentsClient;
26     private AwContents mAwContents;
27     private static final float MAXIMUM_SCALE = 2.0f;
28
29     @Override
30     public void setUp() throws Exception {
31         super.setUp();
32         mContentsClient = new TestAwContentsClient();
33         final AwTestContainerView testContainerView =
34                 createAwTestContainerViewOnMainSync(mContentsClient);
35         mAwContents = testContainerView.getAwContents();
36     }
37
38     private String getZoomableHtml(float scale) {
39         final int divWidthPercent = (int) (100.0f / scale);
40         return String.format(Locale.US, "<html><head><meta name=\"viewport\" content=\"" +
41                 "width=device-width, minimum-scale=%f, maximum-scale=%f, initial-scale=%f" +
42                 "\"/></head><body style='margin:0'>" +
43                 "<div style='width:%d%%;height:100px;border:1px solid black'>Zoomable</div>" +
44                 "</body></html>",
45                 scale, MAXIMUM_SCALE, scale, divWidthPercent);
46     }
47
48     private String getNonZoomableHtml() {
49         // This page can't be zoomed because its viewport fully occupies
50         // view area and is explicitly made non user-scalable.
51         return "<html><head>" +
52                 "<meta name=\"viewport\" " +
53                 "content=\"width=device-width,height=device-height," +
54                 "initial-scale=1,maximum-scale=1,user-scalable=no\">" +
55                 "</head><body>Non-zoomable</body></html>";
56     }
57
58     private boolean isMultiTouchZoomSupportedOnUiThread() throws Throwable {
59         return runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
60             @Override
61             public Boolean call() throws Exception {
62                 return mAwContents.isMultiTouchZoomSupported();
63             }
64         });
65     }
66
67     private int getVisibilityOnUiThread(final View view) throws Throwable {
68         return runTestOnUiThreadAndGetResult(new Callable<Integer>() {
69             @Override
70             public Integer call() throws Exception {
71                 return view.getVisibility();
72             }
73         });
74     }
75
76     private View getZoomControlsOnUiThread() throws Throwable {
77         return runTestOnUiThreadAndGetResult(new Callable<View>() {
78             @Override
79             public View call() throws Exception {
80                 return mAwContents.getZoomControlsForTest();
81             }
82         });
83     }
84
85     private void invokeZoomPickerOnUiThread() throws Throwable {
86         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
87             @Override
88             public void run() {
89                 mAwContents.invokeZoomPicker();
90             }
91         });
92     }
93
94     private void zoomInOnUiThreadAndWait() throws Throwable {
95         final float previousScale = getPixelScaleOnUiThread(mAwContents);
96         assertTrue(runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
97             @Override
98             public Boolean call() throws Exception {
99                 return mAwContents.zoomIn();
100             }
101         }));
102         // The zoom level is updated asynchronously.
103         waitForScaleChange(previousScale);
104     }
105
106     private void zoomOutOnUiThreadAndWait() throws Throwable {
107         final float previousScale = getPixelScaleOnUiThread(mAwContents);
108         assertTrue(runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
109             @Override
110             public Boolean call() throws Exception {
111                 return mAwContents.zoomOut();
112             }
113         }));
114         // The zoom level is updated asynchronously.
115         waitForScaleChange(previousScale);
116     }
117
118     private void zoomByOnUiThreadAndWait(final float delta) throws Throwable {
119         final float previousScale = getPixelScaleOnUiThread(mAwContents);
120         assertTrue(runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
121             @Override
122             public Boolean call() throws Exception {
123                 return mAwContents.zoomBy(delta);
124             }
125         }));
126         // The zoom level is updated asynchronously.
127         waitForScaleChange(previousScale);
128     }
129
130     private void waitForScaleChange(final float previousScale) throws Throwable {
131         poll(new Callable<Boolean>() {
132             @Override
133             public Boolean call() throws Exception {
134                 return previousScale != getPixelScaleOnUiThread(mAwContents);
135             }
136         });
137     }
138
139     private void waitForScaleToBecome(final float expectedScale) throws Throwable {
140         poll(new Callable<Boolean>() {
141             @Override
142             public Boolean call() throws Exception {
143                 return expectedScale == getScaleOnUiThread(mAwContents);
144             }
145         });
146     }
147
148     private void waitUntilCanNotZoom() throws Throwable {
149         poll(new Callable<Boolean>() {
150             @Override
151             public Boolean call() throws Exception {
152                 return !canZoomInOnUiThread(mAwContents) &&
153                         !canZoomOutOnUiThread(mAwContents);
154             }
155         });
156     }
157
158     private void runMagnificationTest() throws Throwable {
159         getAwSettingsOnUiThread(mAwContents).setUseWideViewPort(true);
160         assertFalse("Should not be able to zoom in", canZoomInOnUiThread(mAwContents));
161         final float pageMinimumScale = 0.5f;
162         loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
163                 getZoomableHtml(pageMinimumScale), "text/html", false);
164         waitForScaleToBecome(pageMinimumScale);
165         assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
166         assertFalse("Should not be able to zoom out", canZoomOutOnUiThread(mAwContents));
167
168         while (canZoomInOnUiThread(mAwContents)) {
169             zoomInOnUiThreadAndWait();
170         }
171         assertTrue("Should be able to zoom out", canZoomOutOnUiThread(mAwContents));
172
173         while (canZoomOutOnUiThread(mAwContents)) {
174             zoomOutOnUiThreadAndWait();
175         }
176         assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
177
178         zoomByOnUiThreadAndWait(4.0f);
179         waitForScaleToBecome(MAXIMUM_SCALE);
180
181         zoomByOnUiThreadAndWait(0.5f);
182         waitForScaleToBecome(MAXIMUM_SCALE * 0.5f);
183
184         zoomByOnUiThreadAndWait(0.01f);
185         waitForScaleToBecome(pageMinimumScale);
186     }
187
188     @SmallTest
189     @Feature({"AndroidWebView"})
190     public void testMagnification() throws Throwable {
191         getAwSettingsOnUiThread(mAwContents).setSupportZoom(true);
192         runMagnificationTest();
193     }
194
195     // According to Android CTS test, zoomIn/Out must work
196     // even if supportZoom is turned off.
197     @SmallTest
198     @Feature({"AndroidWebView"})
199     public void testMagnificationWithZoomSupportOff() throws Throwable {
200         getAwSettingsOnUiThread(mAwContents).setSupportZoom(false);
201         runMagnificationTest();
202     }
203
204     @SmallTest
205     @Feature({"AndroidWebView"})
206     public void testZoomUsingMultiTouch() throws Throwable {
207         AwSettings webSettings = getAwSettingsOnUiThread(mAwContents);
208         loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
209                 getZoomableHtml(0.5f), "text/html", false);
210
211         assertTrue(webSettings.supportZoom());
212         assertFalse(webSettings.getBuiltInZoomControls());
213         assertFalse(isMultiTouchZoomSupportedOnUiThread());
214
215         webSettings.setBuiltInZoomControls(true);
216         assertTrue(isMultiTouchZoomSupportedOnUiThread());
217
218         webSettings.setSupportZoom(false);
219         assertFalse(isMultiTouchZoomSupportedOnUiThread());
220     }
221
222     @SmallTest
223     @Feature({"AndroidWebView"})
224     public void testZoomControls() throws Throwable {
225         AwSettings webSettings = getAwSettingsOnUiThread(mAwContents);
226         webSettings.setUseWideViewPort(true);
227         assertFalse("Should not be able to zoom in", canZoomInOnUiThread(mAwContents));
228         final float pageMinimumScale = 0.5f;
229         loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
230                 getZoomableHtml(pageMinimumScale), "text/html", false);
231         waitForScaleToBecome(pageMinimumScale);
232         // It must be possible to zoom in (or zoom out) for zoom controls to be shown
233         assertTrue("Should be able to zoom in", canZoomInOnUiThread(mAwContents));
234
235         assertTrue(webSettings.supportZoom());
236         webSettings.setBuiltInZoomControls(true);
237         webSettings.setDisplayZoomControls(false);
238
239         // With DisplayZoomControls set to false, attempts to display zoom
240         // controls must be ignored.
241         assertNull(getZoomControlsOnUiThread());
242         invokeZoomPickerOnUiThread();
243         assertNull(getZoomControlsOnUiThread());
244
245         webSettings.setDisplayZoomControls(true);
246         assertNull(getZoomControlsOnUiThread());
247         invokeZoomPickerOnUiThread();
248         View zoomControls = getZoomControlsOnUiThread();
249         assertEquals(View.VISIBLE, getVisibilityOnUiThread(zoomControls));
250     }
251
252     @SmallTest
253     @Feature({"AndroidWebView"})
254     public void testZoomControlsOnNonZoomableContent() throws Throwable {
255         AwSettings webSettings = getAwSettingsOnUiThread(mAwContents);
256         loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
257                 getNonZoomableHtml(), "text/html", false);
258
259         // ContentView must update itself according to the viewport setup.
260         waitUntilCanNotZoom();
261
262         assertTrue(webSettings.supportZoom());
263         webSettings.setBuiltInZoomControls(true);
264         webSettings.setDisplayZoomControls(true);
265         assertNull(getZoomControlsOnUiThread());
266         invokeZoomPickerOnUiThread();
267         View zoomControls = getZoomControlsOnUiThread();
268         assertEquals(View.GONE, getVisibilityOnUiThread(zoomControls));
269     }
270
271     @SmallTest
272     @Feature({"AndroidWebView"})
273     public void testZoomControlsOnOrientationChange() throws Throwable {
274         AwSettings webSettings = getAwSettingsOnUiThread(mAwContents);
275         loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
276                 getZoomableHtml(0.5f), "text/html", false);
277
278         assertTrue(webSettings.supportZoom());
279         webSettings.setBuiltInZoomControls(true);
280         webSettings.setDisplayZoomControls(true);
281         invokeZoomPickerOnUiThread();
282
283         // Now force an orientation change, and try to display the zoom picker
284         // again. Make sure that we don't crash when the ZoomPicker registers
285         // it's receiver.
286
287         Activity activity = getActivity();
288         int orientation = activity.getRequestedOrientation();
289         activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
290         activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
291         activity.setRequestedOrientation(orientation);
292         invokeZoomPickerOnUiThread();
293
294         // We may crash shortly (as the zoom picker has a short delay in it before
295         // it tries to register it's BroadcastReceiver), so sleep to verify we don't.
296         // The delay is encoded in ZoomButtonsController#ZOOM_CONTROLS_TIMEOUT,
297         // if that changes we may need to update this test.
298         Thread.sleep(ViewConfiguration.getZoomControlsTimeout());
299     }
300 }