JavaBridgeBasicsTest.java revision f7e26448c3591989840efa65f4f3f93a294b991e
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/** 18 * Part of the test suite for the WebView's Java Bridge. Tests a number of features including ... 19 * - The type of injected objects 20 * - The type of their methods 21 * - Replacing objects 22 * - Removing objects 23 * - Access control 24 * - Calling methods on returned objects 25 * - Multiply injected objects 26 * - Threading 27 * - Inheritance 28 * 29 * To run this test ... 30 * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeBasicsTest \ 31 * com.android.webviewtests/android.test.InstrumentationTestRunner 32 */ 33 34package com.android.webviewtests; 35 36public class JavaBridgeBasicsTest extends JavaBridgeTestBase { 37 private class TestController extends Controller { 38 private int mIntValue; 39 private long mLongValue; 40 private String mStringValue; 41 42 public synchronized void setIntValue(int x) { 43 mIntValue = x; 44 notifyResultIsReady(); 45 } 46 public synchronized void setLongValue(long x) { 47 mLongValue = x; 48 notifyResultIsReady(); 49 } 50 public synchronized void setStringValue(String x) { 51 mStringValue = x; 52 notifyResultIsReady(); 53 } 54 55 public synchronized int waitForIntValue() { 56 waitForResult(); 57 return mIntValue; 58 } 59 public synchronized long waitForLongValue() { 60 waitForResult(); 61 return mLongValue; 62 } 63 public synchronized String waitForStringValue() { 64 waitForResult(); 65 return mStringValue; 66 } 67 } 68 69 TestController mTestController; 70 71 @Override 72 protected void setUp() throws Exception { 73 super.setUp(); 74 mTestController = new TestController(); 75 setUpWebView(mTestController, "testController"); 76 } 77 78 // Note that this requires that we can pass a JavaScript string to Java. 79 protected String executeJavaScriptAndGetStringResult(String script) throws Throwable { 80 executeJavaScript("testController.setStringValue(" + script + ");"); 81 return mTestController.waitForStringValue(); 82 } 83 84 protected void injectObjectAndReload(final Object object, final String name) throws Throwable { 85 runTestOnUiThread(new Runnable() { 86 @Override 87 public void run() { 88 getWebView().addJavascriptInterface(object, name); 89 getWebView().reload(); 90 } 91 }); 92 mWebViewClient.waitForOnPageFinished(); 93 } 94 95 public void testTypeOfInjectedObject() throws Throwable { 96 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); 97 } 98 99 public void testAdditionNotReflectedUntilReload() throws Throwable { 100 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); 101 runTestOnUiThread(new Runnable() { 102 @Override 103 public void run() { 104 getWebView().addJavascriptInterface(new Object(), "testObject"); 105 } 106 }); 107 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); 108 runTestOnUiThread(new Runnable() { 109 @Override 110 public void run() { 111 getWebView().reload(); 112 } 113 }); 114 mWebViewClient.waitForOnPageFinished(); 115 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); 116 } 117 118 public void testRemovalNotReflectedUntilReload() throws Throwable { 119 injectObjectAndReload(new Object(), "testObject"); 120 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); 121 runTestOnUiThread(new Runnable() { 122 @Override 123 public void run() { 124 getWebView().removeJavascriptInterface("testObject"); 125 } 126 }); 127 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); 128 runTestOnUiThread(new Runnable() { 129 @Override 130 public void run() { 131 getWebView().reload(); 132 } 133 }); 134 mWebViewClient.waitForOnPageFinished(); 135 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); 136 } 137 138 public void testRemoveObjectNotAdded() throws Throwable { 139 runTestOnUiThread(new Runnable() { 140 @Override 141 public void run() { 142 getWebView().removeJavascriptInterface("foo"); 143 getWebView().reload(); 144 } 145 }); 146 mWebViewClient.waitForOnPageFinished(); 147 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof foo")); 148 } 149 150 public void testTypeOfMethod() throws Throwable { 151 assertEquals("function", 152 executeJavaScriptAndGetStringResult("typeof testController.setStringValue")); 153 } 154 155 public void testPrivateMethodNotExposed() throws Throwable { 156 injectObjectAndReload(new Object() { 157 private void method() {} 158 }, "testObject"); 159 assertEquals("undefined", 160 executeJavaScriptAndGetStringResult("typeof testObject.method")); 161 } 162 163 public void testReplaceInjectedObject() throws Throwable { 164 injectObjectAndReload(new Object() { 165 public void method() { mTestController.setStringValue("object 1"); } 166 }, "testObject"); 167 executeJavaScript("testObject.method()"); 168 assertEquals("object 1", mTestController.waitForStringValue()); 169 170 injectObjectAndReload(new Object() { 171 public void method() { mTestController.setStringValue("object 2"); } 172 }, "testObject"); 173 executeJavaScript("testObject.method()"); 174 assertEquals("object 2", mTestController.waitForStringValue()); 175 } 176 177 public void testInjectNullObjectIsIgnored() throws Throwable { 178 injectObjectAndReload(null, "testObject"); 179 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); 180 } 181 182 public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable { 183 injectObjectAndReload(new Object(), "testObject"); 184 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); 185 injectObjectAndReload(null, "testObject"); 186 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); 187 } 188 189 public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable { 190 injectObjectAndReload(new Object() { 191 public void method() { mTestController.setStringValue("0 args"); } 192 public void method(int x) { mTestController.setStringValue("1 arg"); } 193 public void method(int x, int y) { mTestController.setStringValue("2 args"); } 194 }, "testObject"); 195 executeJavaScript("testObject.method()"); 196 assertEquals("0 args", mTestController.waitForStringValue()); 197 executeJavaScript("testObject.method(42)"); 198 assertEquals("1 arg", mTestController.waitForStringValue()); 199 executeJavaScript("testObject.method(null)"); 200 assertEquals("1 arg", mTestController.waitForStringValue()); 201 executeJavaScript("testObject.method(undefined)"); 202 assertEquals("1 arg", mTestController.waitForStringValue()); 203 executeJavaScript("testObject.method(42, 42)"); 204 assertEquals("2 args", mTestController.waitForStringValue()); 205 } 206 207 public void testObjectPersistsAcrossPageLoads() throws Throwable { 208 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); 209 runTestOnUiThread(new Runnable() { 210 @Override 211 public void run() { 212 getWebView().reload(); 213 } 214 }); 215 mWebViewClient.waitForOnPageFinished(); 216 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); 217 } 218 219 public void testSameObjectInjectedMultipleTimes() throws Throwable { 220 class TestObject { 221 private int mNumMethodInvocations; 222 public void method() { mTestController.setIntValue(++mNumMethodInvocations); } 223 } 224 final TestObject testObject = new TestObject(); 225 runTestOnUiThread(new Runnable() { 226 @Override 227 public void run() { 228 getWebView().addJavascriptInterface(testObject, "testObject1"); 229 getWebView().addJavascriptInterface(testObject, "testObject2"); 230 getWebView().reload(); 231 } 232 }); 233 mWebViewClient.waitForOnPageFinished(); 234 executeJavaScript("testObject1.method()"); 235 assertEquals(1, mTestController.waitForIntValue()); 236 executeJavaScript("testObject2.method()"); 237 assertEquals(2, mTestController.waitForIntValue()); 238 } 239 240 public void testCallMethodOnReturnedObject() throws Throwable { 241 injectObjectAndReload(new Object() { 242 public Object getInnerObject() { 243 return new Object() { 244 public void method(int x) { mTestController.setIntValue(x); } 245 }; 246 } 247 }, "testObject"); 248 executeJavaScript("testObject.getInnerObject().method(42)"); 249 assertEquals(42, mTestController.waitForIntValue()); 250 } 251 252 public void testReturnedObjectInjectedElsewhere() throws Throwable { 253 class InnerObject { 254 private int mNumMethodInvocations; 255 public void method() { mTestController.setIntValue(++mNumMethodInvocations); } 256 } 257 final InnerObject innerObject = new InnerObject(); 258 final Object object = new Object() { 259 public InnerObject getInnerObject() { 260 return innerObject; 261 } 262 }; 263 runTestOnUiThread(new Runnable() { 264 @Override 265 public void run() { 266 getWebView().addJavascriptInterface(object, "testObject"); 267 getWebView().addJavascriptInterface(innerObject, "innerObject"); 268 getWebView().reload(); 269 } 270 }); 271 mWebViewClient.waitForOnPageFinished(); 272 executeJavaScript("testObject.getInnerObject().method()"); 273 assertEquals(1, mTestController.waitForIntValue()); 274 executeJavaScript("innerObject.method()"); 275 assertEquals(2, mTestController.waitForIntValue()); 276 } 277 278 public void testMethodInvokedOnBackgroundThread() throws Throwable { 279 injectObjectAndReload(new Object() { 280 public void captureThreadId() { 281 mTestController.setLongValue(Thread.currentThread().getId()); 282 } 283 }, "testObject"); 284 executeJavaScript("testObject.captureThreadId()"); 285 final long threadId = mTestController.waitForLongValue(); 286 assertFalse(threadId == Thread.currentThread().getId()); 287 runTestOnUiThread(new Runnable() { 288 @Override 289 public void run() { 290 assertFalse(threadId == Thread.currentThread().getId()); 291 } 292 }); 293 } 294 295 public void testPublicInheritedMethod() throws Throwable { 296 class Base { 297 public void method(int x) { mTestController.setIntValue(x); } 298 } 299 class Derived extends Base { 300 } 301 injectObjectAndReload(new Derived(), "testObject"); 302 assertEquals("function", executeJavaScriptAndGetStringResult("typeof testObject.method")); 303 executeJavaScript("testObject.method(42)"); 304 assertEquals(42, mTestController.waitForIntValue()); 305 } 306 307 public void testPrivateInheritedMethod() throws Throwable { 308 class Base { 309 private void method() {} 310 } 311 class Derived extends Base { 312 } 313 injectObjectAndReload(new Derived(), "testObject"); 314 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject.method")); 315 } 316 317 public void testOverriddenMethod() throws Throwable { 318 class Base { 319 public void method() { mTestController.setStringValue("base"); } 320 } 321 class Derived extends Base { 322 public void method() { mTestController.setStringValue("derived"); } 323 } 324 injectObjectAndReload(new Derived(), "testObject"); 325 executeJavaScript("testObject.method()"); 326 assertEquals("derived", mTestController.waitForStringValue()); 327 } 328 329 public void testEnumerateMembers() throws Throwable { 330 injectObjectAndReload(new Object() { 331 public void method() {} 332 private void privateMethod() {} 333 public int field; 334 private int privateField; 335 }, "testObject"); 336 executeJavaScript( 337 "var result = \"\"; " + 338 "for (x in testObject) { result += \" \" + x } " + 339 "testController.setStringValue(result);"); 340 // LIVECONNECT_COMPLIANCE: Should be able to enumerate members. 341 assertEquals("", mTestController.waitForStringValue()); 342 } 343} 344