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. 4 5package org.chromium.android_webview.test; 6 7import android.test.suitebuilder.annotation.MediumTest; 8import android.webkit.GeolocationPermissions; 9 10import org.chromium.android_webview.AwContents; 11import org.chromium.base.test.util.Feature; 12import org.chromium.content.browser.LocationProviderFactory; 13import org.chromium.content.browser.test.util.MockLocationProvider; 14 15import java.util.concurrent.Callable; 16 17/** 18 * Test suite for Geolocation in AwContents. Smoke tests for 19 * basic functionality, and tests to ensure the AwContents.onPause 20 * and onResume APIs affect Geolocation as expected. 21 */ 22public class GeolocationTest extends AwTestBase { 23 private TestAwContentsClient mContentsClient; 24 private AwContents mAwContents; 25 private MockLocationProvider mMockLocationProvider; 26 27 private static final String RAW_HTML = 28 "<!DOCTYPE html>\n" + 29 "<html>\n" + 30 " <head>\n" + 31 " <title>Geolocation</title>\n" + 32 " <script>\n" + 33 " var positionCount = 0;\n" + 34 " function gotPos(position) {\n" + 35 " positionCount++;\n" + 36 " }\n" + 37 " function initiate_getCurrentPosition() {\n" + 38 " navigator.geolocation.getCurrentPosition(\n" + 39 " gotPos, function() { }, { });\n" + 40 " }\n" + 41 " function initiate_watchPosition() {\n" + 42 " navigator.geolocation.watchPosition(\n" + 43 " gotPos, function() { }, { });\n" + 44 " }\n" + 45 " </script>\n" + 46 " </head>\n" + 47 " <body>\n" + 48 " </body>\n" + 49 "</html>"; 50 51 @Override 52 public void setUp() throws Exception { 53 super.setUp(); 54 mContentsClient = new TestAwContentsClient() { 55 @Override 56 public void onGeolocationPermissionsShowPrompt(String origin, 57 GeolocationPermissions.Callback callback) { 58 callback.invoke(origin, true, true); 59 } 60 }; 61 mAwContents = createAwTestContainerViewOnMainSync(mContentsClient).getAwContents(); 62 enableJavaScriptOnUiThread(mAwContents); 63 setupGeolocation(); 64 } 65 66 @Override 67 public void tearDown() throws Exception { 68 mMockLocationProvider.stopUpdates(); 69 super.tearDown(); 70 } 71 72 private void setupGeolocation() { 73 getInstrumentation().runOnMainSync(new Runnable() { 74 @Override 75 public void run() { 76 mAwContents.getSettings().setGeolocationEnabled(true); 77 } 78 }); 79 mMockLocationProvider = new MockLocationProvider(); 80 LocationProviderFactory.setLocationProviderImpl(mMockLocationProvider); 81 } 82 83 private int getPositionCountFromJS() { 84 int result = -1; 85 try { 86 result = Integer.parseInt(executeJavaScriptAndWaitForResult( 87 mAwContents, mContentsClient, "positionCount")); 88 } catch (Exception e) { 89 fail("Unable to get positionCount"); 90 } 91 return result; 92 } 93 94 private void ensureGeolocationRunning(final boolean running) throws Exception { 95 poll(new Callable<Boolean>() { 96 @Override 97 public Boolean call() throws Exception { 98 return mMockLocationProvider.isRunning() == running; 99 } 100 }); 101 } 102 103 104 /** 105 * Ensure that a call to navigator.getCurrentPosition works in WebView. 106 */ 107 @MediumTest 108 @Feature({"AndroidWebView"}) 109 public void testGetPosition() throws Throwable { 110 loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), 111 RAW_HTML, "text/html", false); 112 113 mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null); 114 115 poll(new Callable<Boolean>() { 116 @Override 117 public Boolean call() throws Exception { 118 return getPositionCountFromJS() == 1; 119 } 120 }); 121 122 mAwContents.evaluateJavaScript("initiate_getCurrentPosition();", null); 123 poll(new Callable<Boolean>() { 124 @Override 125 public Boolean call() throws Exception { 126 return getPositionCountFromJS() == 2; 127 } 128 }); 129 } 130 131 /** 132 * Ensure that a call to navigator.watchPosition works in WebView. 133 */ 134 @MediumTest 135 @Feature({"AndroidWebView"}) 136 public void testWatchPosition() throws Throwable { 137 loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), 138 RAW_HTML, "text/html", false); 139 140 mAwContents.evaluateJavaScript("initiate_watchPosition();", null); 141 142 poll(new Callable<Boolean>() { 143 @Override 144 public Boolean call() throws Exception { 145 return getPositionCountFromJS() > 1; 146 } 147 }); 148 } 149 150 @MediumTest 151 @Feature({"AndroidWebView"}) 152 public void testPauseGeolocationOnPause() throws Throwable { 153 // Start a watch going. 154 loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), 155 RAW_HTML, "text/html", false); 156 157 mAwContents.evaluateJavaScript("initiate_watchPosition();", null); 158 159 poll(new Callable<Boolean>() { 160 @Override 161 public Boolean call() throws Exception { 162 return getPositionCountFromJS() > 1; 163 } 164 }); 165 166 ensureGeolocationRunning(true); 167 168 getInstrumentation().runOnMainSync(new Runnable() { 169 @Override 170 public void run() { 171 mAwContents.onPause(); 172 } 173 }); 174 175 ensureGeolocationRunning(false); 176 177 try { 178 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, "positionCount = 0"); 179 } catch (Exception e) { 180 fail("Unable to clear positionCount"); 181 } 182 assertEquals(0, getPositionCountFromJS()); 183 184 getInstrumentation().runOnMainSync(new Runnable() { 185 @Override 186 public void run() { 187 mAwContents.onResume(); 188 } 189 }); 190 191 ensureGeolocationRunning(true); 192 193 poll(new Callable<Boolean>() { 194 @Override 195 public Boolean call() throws Exception { 196 return getPositionCountFromJS() > 1; 197 } 198 }); 199 } 200 201 @MediumTest 202 @Feature({"AndroidWebView"}) 203 public void testPauseAwContentsBeforeNavigating() throws Throwable { 204 getInstrumentation().runOnMainSync(new Runnable() { 205 @Override 206 public void run() { 207 mAwContents.onPause(); 208 } 209 }); 210 211 // Start a watch going. 212 loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), 213 RAW_HTML, "text/html", false); 214 215 mAwContents.evaluateJavaScript("initiate_watchPosition();", null); 216 217 assertEquals(0, getPositionCountFromJS()); 218 219 ensureGeolocationRunning(false); 220 221 getInstrumentation().runOnMainSync(new Runnable() { 222 @Override 223 public void run() { 224 mAwContents.onResume(); 225 } 226 }); 227 228 ensureGeolocationRunning(true); 229 230 poll(new Callable<Boolean>() { 231 @Override 232 public Boolean call() throws Exception { 233 return getPositionCountFromJS() > 1; 234 } 235 }); 236 } 237 238 @MediumTest 239 @Feature({"AndroidWebView"}) 240 public void testResumeWhenNotStarted() throws Throwable { 241 getInstrumentation().runOnMainSync(new Runnable() { 242 @Override 243 public void run() { 244 mAwContents.onPause(); 245 } 246 }); 247 248 loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), 249 RAW_HTML, "text/html", false); 250 251 getInstrumentation().runOnMainSync(new Runnable() { 252 @Override 253 public void run() { 254 mAwContents.onResume(); 255 } 256 }); 257 258 ensureGeolocationRunning(false); 259 } 260 261} 262