| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; | 7 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; |
| 8 | 8 |
| 9 import android.support.test.InstrumentationRegistry; |
| 9 import android.support.test.filters.SmallTest; | 10 import android.support.test.filters.SmallTest; |
| 10 | 11 |
| 11 import junit.framework.Assert; | 12 import org.junit.Assert; |
| 13 import org.junit.Before; |
| 14 import org.junit.Rule; |
| 15 import org.junit.Test; |
| 16 import org.junit.runner.RunWith; |
| 12 | 17 |
| 13 import org.chromium.base.annotations.SuppressFBWarnings; | 18 import org.chromium.base.annotations.SuppressFBWarnings; |
| 14 import org.chromium.base.test.util.CommandLineFlags; | 19 import org.chromium.base.test.util.CommandLineFlags; |
| 15 import org.chromium.base.test.util.Feature; | 20 import org.chromium.base.test.util.Feature; |
| 16 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; | 21 import org.chromium.content.browser.JavaBridgeTestCommon.Controller; |
| 22 import org.chromium.content.browser.test.ContentJUnit4ClassRunner; |
| 17 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; | 23 import org.chromium.content.browser.test.util.TestCallbackHelperContainer; |
| 18 import org.chromium.content_public.browser.LoadUrlParams; | 24 import org.chromium.content_public.browser.LoadUrlParams; |
| 19 | 25 |
| 20 import java.lang.annotation.ElementType; | 26 import java.lang.annotation.ElementType; |
| 21 import java.lang.annotation.Retention; | 27 import java.lang.annotation.Retention; |
| 22 import java.lang.annotation.RetentionPolicy; | 28 import java.lang.annotation.RetentionPolicy; |
| 23 import java.lang.annotation.Target; | 29 import java.lang.annotation.Target; |
| 24 import java.lang.ref.WeakReference; | 30 import java.lang.ref.WeakReference; |
| 25 import java.util.concurrent.CountDownLatch; | 31 import java.util.concurrent.CountDownLatch; |
| 26 | 32 |
| 27 /** | 33 /** |
| 28 * Part of the test suite for the Java Bridge. Tests a number of features includ
ing ... | 34 * Part of the test suite for the Java Bridge. Tests a number of features includ
ing ... |
| 29 * - The type of injected objects | 35 * - The type of injected objects |
| 30 * - The type of their methods | 36 * - The type of their methods |
| 31 * - Replacing objects | 37 * - Replacing objects |
| 32 * - Removing objects | 38 * - Removing objects |
| 33 * - Access control | 39 * - Access control |
| 34 * - Calling methods on returned objects | 40 * - Calling methods on returned objects |
| 35 * - Multiply injected objects | 41 * - Multiply injected objects |
| 36 * - Threading | 42 * - Threading |
| 37 * - Inheritance | 43 * - Inheritance |
| 38 */ | 44 */ |
| 45 @RunWith(ContentJUnit4ClassRunner.class) |
| 39 @SuppressFBWarnings( | 46 @SuppressFBWarnings( |
| 40 {"UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS", "URF_UNREAD_PUBLIC_OR_PROT
ECTED_FIELD"}) | 47 {"UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS", "URF_UNREAD_PUBLIC_OR_PROT
ECTED_FIELD"}) |
| 41 public class JavaBridgeBasicsTest extends JavaBridgeTestBase { | 48 public class JavaBridgeBasicsTest { |
| 49 @Rule |
| 50 public JavaBridgeActivityTestRule mActivityTestRule = |
| 51 new JavaBridgeActivityTestRule().shouldSetUp(false); |
| 52 |
| 42 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 53 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
| 43 private static class TestController extends Controller { | 54 private static class TestController extends Controller { |
| 44 private int mIntValue; | 55 private int mIntValue; |
| 45 private long mLongValue; | 56 private long mLongValue; |
| 46 private String mStringValue; | 57 private String mStringValue; |
| 47 private boolean mBooleanValue; | 58 private boolean mBooleanValue; |
| 48 | 59 |
| 49 public synchronized void setIntValue(int x) { | 60 public synchronized void setIntValue(int x) { |
| 50 mIntValue = x; | 61 mIntValue = x; |
| 51 notifyResultIsReady(); | 62 notifyResultIsReady(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 } | 97 } |
| 87 | 98 |
| 88 private static class ObjectWithStaticMethod { | 99 private static class ObjectWithStaticMethod { |
| 89 public static String staticMethod() { | 100 public static String staticMethod() { |
| 90 return "foo"; | 101 return "foo"; |
| 91 } | 102 } |
| 92 } | 103 } |
| 93 | 104 |
| 94 TestController mTestController; | 105 TestController mTestController; |
| 95 | 106 |
| 96 @Override | 107 @Before |
| 97 protected void setUp() throws Exception { | 108 public void setUp() throws Exception { |
| 98 super.setUp(); | 109 mActivityTestRule.setUpContentView(); |
| 99 mTestController = new TestController(); | 110 mTestController = new TestController(); |
| 100 injectObjectAndReload(mTestController, "testController"); | 111 mActivityTestRule.injectObjectAndReload(mTestController, "testController
"); |
| 101 } | 112 } |
| 102 | 113 |
| 103 // Note that this requires that we can pass a JavaScript string to Java. | 114 // Note that this requires that we can pass a JavaScript string to Java. |
| 104 protected String executeJavaScriptAndGetStringResult(String script) throws T
hrowable { | 115 protected String executeJavaScriptAndGetStringResult(String script) throws T
hrowable { |
| 105 executeJavaScript("testController.setStringValue(" + script + ");"); | 116 mActivityTestRule.executeJavaScript("testController.setStringValue(" + s
cript + ");"); |
| 106 return mTestController.waitForStringValue(); | 117 return mTestController.waitForStringValue(); |
| 107 } | 118 } |
| 108 | 119 |
| 109 // Note that this requires that we can pass a JavaScript boolean to Java. | 120 // Note that this requires that we can pass a JavaScript boolean to Java. |
| 110 private void executeAndSetIfException(String script) throws Throwable { | 121 private void executeAndSetIfException(String script) throws Throwable { |
| 111 executeJavaScript("try {" | 122 mActivityTestRule.executeJavaScript("try {" + script + ";" |
| 112 + script + ";" | |
| 113 + " testController.setBooleanValue(false);" | 123 + " testController.setBooleanValue(false);" |
| 114 + "} catch (exception) {" | 124 + "} catch (exception) {" |
| 115 + " testController.setBooleanValue(true);" | 125 + " testController.setBooleanValue(true);" |
| 116 + "}"); | 126 + "}"); |
| 117 } | 127 } |
| 118 | 128 |
| 119 private void assertRaisesException(String script) throws Throwable { | 129 private void assertRaisesException(String script) throws Throwable { |
| 120 executeAndSetIfException(script); | 130 executeAndSetIfException(script); |
| 121 assertTrue(mTestController.waitForBooleanValue()); | 131 Assert.assertTrue(mTestController.waitForBooleanValue()); |
| 122 } | 132 } |
| 123 | 133 |
| 124 private void assertNoRaisedException(String script) throws Throwable { | 134 private void assertNoRaisedException(String script) throws Throwable { |
| 125 executeAndSetIfException(script); | 135 executeAndSetIfException(script); |
| 126 assertFalse(mTestController.waitForBooleanValue()); | 136 Assert.assertFalse(mTestController.waitForBooleanValue()); |
| 127 } | 137 } |
| 128 | 138 |
| 139 @Test |
| 129 @SmallTest | 140 @SmallTest |
| 130 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 141 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 131 public void testTypeOfInjectedObject() throws Throwable { | 142 public void testTypeOfInjectedObject() throws Throwable { |
| 132 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 143 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 133 } | 144 } |
| 134 | 145 |
| 146 @Test |
| 135 @SmallTest | 147 @SmallTest |
| 136 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 148 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 137 public void testAdditionNotReflectedUntilReload() throws Throwable { | 149 public void testAdditionNotReflectedUntilReload() throws Throwable { |
| 138 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 150 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 139 runTestOnUiThread(new Runnable() { | 151 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 140 @Override | 152 @Override |
| 141 public void run() { | 153 public void run() { |
| 142 getContentViewCore().addPossiblyUnsafeJavascriptInterface( | 154 mActivityTestRule.getContentViewCore().addPossiblyUnsafeJavascri
ptInterface( |
| 143 new Object(), "testObject", null); | 155 new Object(), "testObject", null); |
| 144 } | 156 } |
| 145 }); | 157 }); |
| 146 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 158 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 147 synchronousPageReload(); | 159 mActivityTestRule.synchronousPageReload(); |
| 148 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 160 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 149 } | 161 } |
| 150 | 162 |
| 163 @Test |
| 151 @SmallTest | 164 @SmallTest |
| 152 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 165 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 153 public void testRemovalNotReflectedUntilReload() throws Throwable { | 166 public void testRemovalNotReflectedUntilReload() throws Throwable { |
| 154 injectObjectAndReload(new Object() { | 167 mActivityTestRule.injectObjectAndReload(new Object() { |
| 155 public void method() { | 168 public void method() { |
| 156 mTestController.setStringValue("I'm here"); | 169 mTestController.setStringValue("I'm here"); |
| 157 } | 170 } |
| 158 }, "testObject"); | 171 }, "testObject"); |
| 159 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 172 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 160 executeJavaScript("testObject.method()"); | 173 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 161 assertEquals("I'm here", mTestController.waitForStringValue()); | 174 Assert.assertEquals("I'm here", mTestController.waitForStringValue()); |
| 162 runTestOnUiThread(new Runnable() { | 175 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 163 @Override | 176 @Override |
| 164 public void run() { | 177 public void run() { |
| 165 getContentViewCore().removeJavascriptInterface("testObject"); | 178 mActivityTestRule.getContentViewCore().removeJavascriptInterface
("testObject"); |
| 166 } | 179 } |
| 167 }); | 180 }); |
| 168 // Check that the Java object is being held by the Java bridge, thus it'
s not | 181 // Check that the Java object is being held by the Java bridge, thus it'
s not |
| 169 // collected. Note that despite that what JavaDoc says about invoking "g
c()", both Dalvik | 182 // collected. Note that despite that what JavaDoc says about invoking "g
c()", both Dalvik |
| 170 // and ART actually run the collector if called via Runtime. | 183 // and ART actually run the collector if called via Runtime. |
| 171 Runtime.getRuntime().gc(); | 184 Runtime.getRuntime().gc(); |
| 172 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 185 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 173 executeJavaScript("testObject.method()"); | 186 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 174 assertEquals("I'm here", mTestController.waitForStringValue()); | 187 Assert.assertEquals("I'm here", mTestController.waitForStringValue()); |
| 175 synchronousPageReload(); | 188 mActivityTestRule.synchronousPageReload(); |
| 176 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 189 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 177 } | 190 } |
| 178 | 191 |
| 192 @Test |
| 179 @SmallTest | 193 @SmallTest |
| 180 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 194 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 181 public void testRemoveObjectNotAdded() throws Throwable { | 195 public void testRemoveObjectNotAdded() throws Throwable { |
| 182 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = | 196 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = |
| 183 getTestCallBackHelperContainer().getOnPageFinishedHelper(); | 197 mActivityTestRule.getTestCallBackHelperContainer().getOnPageFini
shedHelper(); |
| 184 int currentCallCount = onPageFinishedHelper.getCallCount(); | 198 int currentCallCount = onPageFinishedHelper.getCallCount(); |
| 185 runTestOnUiThread(new Runnable() { | 199 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 186 @Override | 200 @Override |
| 187 public void run() { | 201 public void run() { |
| 188 getContentViewCore().removeJavascriptInterface("foo"); | 202 mActivityTestRule.getContentViewCore().removeJavascriptInterface
("foo"); |
| 189 getContentViewCore().getWebContents().getNavigationController().
reload(true); | 203 mActivityTestRule.getContentViewCore() |
| 204 .getWebContents() |
| 205 .getNavigationController() |
| 206 .reload(true); |
| 190 } | 207 } |
| 191 }); | 208 }); |
| 192 onPageFinishedHelper.waitForCallback(currentCallCount); | 209 onPageFinishedHelper.waitForCallback(currentCallCount); |
| 193 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof fo
o")); | 210 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof foo")); |
| 194 } | 211 } |
| 195 | 212 |
| 213 @Test |
| 196 @SmallTest | 214 @SmallTest |
| 197 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 215 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 198 public void testTypeOfMethod() throws Throwable { | 216 public void testTypeOfMethod() throws Throwable { |
| 199 assertEquals("function", | 217 Assert.assertEquals("function", |
| 200 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); | 218 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); |
| 201 } | 219 } |
| 202 | 220 |
| 221 @Test |
| 203 @SmallTest | 222 @SmallTest |
| 204 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 223 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 205 public void testTypeOfInvalidMethod() throws Throwable { | 224 public void testTypeOfInvalidMethod() throws Throwable { |
| 206 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stController.foo")); | 225 Assert.assertEquals( |
| 226 "undefined", executeJavaScriptAndGetStringResult("typeof testCon
troller.foo")); |
| 207 } | 227 } |
| 208 | 228 |
| 229 @Test |
| 209 @SmallTest | 230 @SmallTest |
| 210 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 231 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 211 public void testCallingInvalidMethodRaisesException() throws Throwable { | 232 public void testCallingInvalidMethodRaisesException() throws Throwable { |
| 212 assertRaisesException("testController.foo()"); | 233 assertRaisesException("testController.foo()"); |
| 213 } | 234 } |
| 214 | 235 |
| 236 @Test |
| 215 @SmallTest | 237 @SmallTest |
| 216 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 238 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 217 public void testUncaughtJavaExceptionRaisesJavaScriptException() throws Thro
wable { | 239 public void testUncaughtJavaExceptionRaisesJavaScriptException() throws Thro
wable { |
| 218 injectObjectAndReload(new Object() { | 240 mActivityTestRule.injectObjectAndReload(new Object() { |
| 219 public void method() { | 241 public void method() { |
| 220 throw new RuntimeException("foo"); | 242 throw new RuntimeException("foo"); |
| 221 } | 243 } |
| 222 }, "testObject"); | 244 }, "testObject"); |
| 223 assertRaisesException("testObject.method()"); | 245 assertRaisesException("testObject.method()"); |
| 224 } | 246 } |
| 225 | 247 |
| 248 @Test |
| 226 @SmallTest | 249 @SmallTest |
| 227 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 250 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 228 public void testCallingAsConstructorRaisesException() throws Throwable { | 251 public void testCallingAsConstructorRaisesException() throws Throwable { |
| 229 assertRaisesException("new testController.setStringValue('foo')"); | 252 assertRaisesException("new testController.setStringValue('foo')"); |
| 230 } | 253 } |
| 231 | 254 |
| 255 @Test |
| 232 @SmallTest | 256 @SmallTest |
| 233 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 257 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 234 public void testCallingOnNonInjectedObjectRaisesException() throws Throwable
{ | 258 public void testCallingOnNonInjectedObjectRaisesException() throws Throwable
{ |
| 235 assertRaisesException("testController.setStringValue.call({}, 'foo')"); | 259 assertRaisesException("testController.setStringValue.call({}, 'foo')"); |
| 236 } | 260 } |
| 237 | 261 |
| 262 @Test |
| 238 @SmallTest | 263 @SmallTest |
| 239 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 264 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 240 public void testCallingOnInstanceOfOtherClassRaisesException() throws Throwa
ble { | 265 public void testCallingOnInstanceOfOtherClassRaisesException() throws Throwa
ble { |
| 241 injectObjectAndReload(new Object(), "testObject"); | 266 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 242 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 267 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 243 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 268 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 244 assertEquals("function", | 269 Assert.assertEquals("function", |
| 245 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); | 270 executeJavaScriptAndGetStringResult("typeof testController.setSt
ringValue")); |
| 246 assertRaisesException("testController.setStringValue.call(testObject, 'f
oo')"); | 271 assertRaisesException("testController.setStringValue.call(testObject, 'f
oo')"); |
| 247 } | 272 } |
| 248 | 273 |
| 249 // Note that this requires that we can pass a JavaScript string to Java. | 274 // Note that this requires that we can pass a JavaScript string to Java. |
| 275 @Test |
| 250 @SmallTest | 276 @SmallTest |
| 251 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 277 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 252 public void testTypeOfStaticMethod() throws Throwable { | 278 public void testTypeOfStaticMethod() throws Throwable { |
| 253 injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); | 279 mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "t
estObject"); |
| 254 executeJavaScript("testController.setStringValue(typeof testObject.stati
cMethod)"); | 280 mActivityTestRule.executeJavaScript( |
| 255 assertEquals("function", mTestController.waitForStringValue()); | 281 "testController.setStringValue(typeof testObject.staticMethod)")
; |
| 282 Assert.assertEquals("function", mTestController.waitForStringValue()); |
| 256 } | 283 } |
| 257 | 284 |
| 258 // Note that this requires that we can pass a JavaScript string to Java. | 285 // Note that this requires that we can pass a JavaScript string to Java. |
| 286 @Test |
| 259 @SmallTest | 287 @SmallTest |
| 260 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 288 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 261 public void testCallStaticMethod() throws Throwable { | 289 public void testCallStaticMethod() throws Throwable { |
| 262 injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); | 290 mActivityTestRule.injectObjectAndReload(new ObjectWithStaticMethod(), "t
estObject"); |
| 263 executeJavaScript("testController.setStringValue(testObject.staticMethod
())"); | 291 mActivityTestRule.executeJavaScript( |
| 264 assertEquals("foo", mTestController.waitForStringValue()); | 292 "testController.setStringValue(testObject.staticMethod())"); |
| 293 Assert.assertEquals("foo", mTestController.waitForStringValue()); |
| 265 } | 294 } |
| 266 | 295 |
| 296 @Test |
| 267 @SmallTest | 297 @SmallTest |
| 268 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 298 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 269 public void testPrivateMethodNotExposed() throws Throwable { | 299 public void testPrivateMethodNotExposed() throws Throwable { |
| 270 injectObjectAndReload(new Object() { | 300 mActivityTestRule.injectObjectAndReload(new Object() { |
| 271 private void method() {} | 301 private void method() {} |
| 272 protected void method2() {} | 302 protected void method2() {} |
| 273 }, "testObject"); | 303 }, "testObject"); |
| 274 assertEquals("undefined", | 304 Assert.assertEquals( |
| 275 executeJavaScriptAndGetStringResult("typeof testObject.method"))
; | 305 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method")); |
| 276 assertEquals("undefined", | 306 Assert.assertEquals( |
| 277 executeJavaScriptAndGetStringResult("typeof testObject.method2")
); | 307 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method2")); |
| 278 } | 308 } |
| 279 | 309 |
| 310 @Test |
| 280 @SmallTest | 311 @SmallTest |
| 281 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 312 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 282 public void testReplaceInjectedObject() throws Throwable { | 313 public void testReplaceInjectedObject() throws Throwable { |
| 283 injectObjectAndReload(new Object() { | 314 mActivityTestRule.injectObjectAndReload(new Object() { |
| 284 public void method() { | 315 public void method() { |
| 285 mTestController.setStringValue("object 1"); | 316 mTestController.setStringValue("object 1"); |
| 286 } | 317 } |
| 287 }, "testObject"); | 318 }, "testObject"); |
| 288 executeJavaScript("testObject.method()"); | 319 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 289 assertEquals("object 1", mTestController.waitForStringValue()); | 320 Assert.assertEquals("object 1", mTestController.waitForStringValue()); |
| 290 | 321 |
| 291 injectObjectAndReload(new Object() { | 322 mActivityTestRule.injectObjectAndReload(new Object() { |
| 292 public void method() { | 323 public void method() { |
| 293 mTestController.setStringValue("object 2"); | 324 mTestController.setStringValue("object 2"); |
| 294 } | 325 } |
| 295 }, "testObject"); | 326 }, "testObject"); |
| 296 executeJavaScript("testObject.method()"); | 327 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 297 assertEquals("object 2", mTestController.waitForStringValue()); | 328 Assert.assertEquals("object 2", mTestController.waitForStringValue()); |
| 298 } | 329 } |
| 299 | 330 |
| 331 @Test |
| 300 @SmallTest | 332 @SmallTest |
| 301 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 333 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 302 public void testInjectNullObjectIsIgnored() throws Throwable { | 334 public void testInjectNullObjectIsIgnored() throws Throwable { |
| 303 injectObjectAndReload(null, "testObject"); | 335 mActivityTestRule.injectObjectAndReload(null, "testObject"); |
| 304 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject")); | 336 Assert.assertEquals("undefined", executeJavaScriptAndGetStringResult("ty
peof testObject")); |
| 305 } | 337 } |
| 306 | 338 |
| 339 @Test |
| 307 @SmallTest | 340 @SmallTest |
| 308 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 341 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 309 public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwa
ble { | 342 public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwa
ble { |
| 310 injectObjectAndReload(new Object(), "testObject"); | 343 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 311 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 344 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 312 injectObjectAndReload(null, "testObject"); | 345 mActivityTestRule.injectObjectAndReload(null, "testObject"); |
| 313 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testO
bject")); | 346 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testObject")); |
| 314 } | 347 } |
| 315 | 348 |
| 349 @Test |
| 316 @SmallTest | 350 @SmallTest |
| 317 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 351 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 318 public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws
Throwable { | 352 public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws
Throwable { |
| 319 injectObjectAndReload(new Object() { | 353 mActivityTestRule.injectObjectAndReload(new Object() { |
| 320 public void method() { | 354 public void method() { |
| 321 mTestController.setStringValue("0 args"); | 355 mTestController.setStringValue("0 args"); |
| 322 } | 356 } |
| 323 | 357 |
| 324 public void method(int x) { | 358 public void method(int x) { |
| 325 mTestController.setStringValue("1 arg"); | 359 mTestController.setStringValue("1 arg"); |
| 326 } | 360 } |
| 327 | 361 |
| 328 public void method(int x, int y) { | 362 public void method(int x, int y) { |
| 329 mTestController.setStringValue("2 args"); | 363 mTestController.setStringValue("2 args"); |
| 330 } | 364 } |
| 331 }, "testObject"); | 365 }, "testObject"); |
| 332 executeJavaScript("testObject.method()"); | 366 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 333 assertEquals("0 args", mTestController.waitForStringValue()); | 367 Assert.assertEquals("0 args", mTestController.waitForStringValue()); |
| 334 executeJavaScript("testObject.method(42)"); | 368 mActivityTestRule.executeJavaScript("testObject.method(42)"); |
| 335 assertEquals("1 arg", mTestController.waitForStringValue()); | 369 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 336 executeJavaScript("testObject.method(null)"); | 370 mActivityTestRule.executeJavaScript("testObject.method(null)"); |
| 337 assertEquals("1 arg", mTestController.waitForStringValue()); | 371 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 338 executeJavaScript("testObject.method(undefined)"); | 372 mActivityTestRule.executeJavaScript("testObject.method(undefined)"); |
| 339 assertEquals("1 arg", mTestController.waitForStringValue()); | 373 Assert.assertEquals("1 arg", mTestController.waitForStringValue()); |
| 340 executeJavaScript("testObject.method(42, 42)"); | 374 mActivityTestRule.executeJavaScript("testObject.method(42, 42)"); |
| 341 assertEquals("2 args", mTestController.waitForStringValue()); | 375 Assert.assertEquals("2 args", mTestController.waitForStringValue()); |
| 342 } | 376 } |
| 343 | 377 |
| 378 @Test |
| 344 @SmallTest | 379 @SmallTest |
| 345 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 380 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 346 public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws
Throwable { | 381 public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws
Throwable { |
| 347 assertRaisesException("testController.setIntValue()"); | 382 assertRaisesException("testController.setIntValue()"); |
| 348 assertRaisesException("testController.setIntValue(42, 42)"); | 383 assertRaisesException("testController.setIntValue(42, 42)"); |
| 349 } | 384 } |
| 350 | 385 |
| 386 @Test |
| 351 @SmallTest | 387 @SmallTest |
| 352 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 388 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 353 public void testObjectPersistsAcrossPageLoads() throws Throwable { | 389 public void testObjectPersistsAcrossPageLoads() throws Throwable { |
| 354 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 390 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 355 synchronousPageReload(); | 391 mActivityTestRule.synchronousPageReload(); |
| 356 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 392 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 357 } | 393 } |
| 358 | 394 |
| 395 @Test |
| 359 @SmallTest | 396 @SmallTest |
| 360 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 397 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 361 public void testCustomPropertiesCleanedUpOnPageReloads() throws Throwable { | 398 public void testCustomPropertiesCleanedUpOnPageReloads() throws Throwable { |
| 362 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 399 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 363 executeJavaScript("testController.myProperty = 42;"); | 400 mActivityTestRule.executeJavaScript("testController.myProperty = 42;"); |
| 364 assertEquals("42", executeJavaScriptAndGetStringResult("testController.m
yProperty")); | 401 Assert.assertEquals("42", executeJavaScriptAndGetStringResult("testContr
oller.myProperty")); |
| 365 synchronousPageReload(); | 402 mActivityTestRule.synchronousPageReload(); |
| 366 assertEquals("object", executeJavaScriptAndGetStringResult("typeof testC
ontroller")); | 403 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f testController")); |
| 367 assertEquals("undefined", executeJavaScriptAndGetStringResult("testContr
oller.myProperty")); | 404 Assert.assertEquals( |
| 405 "undefined", executeJavaScriptAndGetStringResult("testController
.myProperty")); |
| 368 } | 406 } |
| 369 | 407 |
| 408 @Test |
| 370 @SmallTest | 409 @SmallTest |
| 371 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 410 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 372 public void testSameObjectInjectedMultipleTimes() throws Throwable { | 411 public void testSameObjectInjectedMultipleTimes() throws Throwable { |
| 373 class TestObject { | 412 class TestObject { |
| 374 private int mNumMethodInvocations; | 413 private int mNumMethodInvocations; |
| 375 | 414 |
| 376 public void method() { | 415 public void method() { |
| 377 mTestController.setIntValue(++mNumMethodInvocations); | 416 mTestController.setIntValue(++mNumMethodInvocations); |
| 378 } | 417 } |
| 379 } | 418 } |
| 380 final TestObject testObject = new TestObject(); | 419 final TestObject testObject = new TestObject(); |
| 381 injectObjectsAndReload(testObject, "testObject1", testObject, "testObjec
t2", null); | 420 mActivityTestRule.injectObjectsAndReload( |
| 382 executeJavaScript("testObject1.method()"); | 421 testObject, "testObject1", testObject, "testObject2", null); |
| 383 assertEquals(1, mTestController.waitForIntValue()); | 422 mActivityTestRule.executeJavaScript("testObject1.method()"); |
| 384 executeJavaScript("testObject2.method()"); | 423 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 385 assertEquals(2, mTestController.waitForIntValue()); | 424 mActivityTestRule.executeJavaScript("testObject2.method()"); |
| 425 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 386 } | 426 } |
| 387 | 427 |
| 428 @Test |
| 388 @SmallTest | 429 @SmallTest |
| 389 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 430 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 390 public void testCallMethodOnReturnedObject() throws Throwable { | 431 public void testCallMethodOnReturnedObject() throws Throwable { |
| 391 injectObjectAndReload(new Object() { | 432 mActivityTestRule.injectObjectAndReload(new Object() { |
| 392 public Object getInnerObject() { | 433 public Object getInnerObject() { |
| 393 return new Object() { | 434 return new Object() { |
| 394 public void method(int x) { | 435 public void method(int x) { |
| 395 mTestController.setIntValue(x); | 436 mTestController.setIntValue(x); |
| 396 } | 437 } |
| 397 }; | 438 }; |
| 398 } | 439 } |
| 399 }, "testObject"); | 440 }, "testObject"); |
| 400 executeJavaScript("testObject.getInnerObject().method(42)"); | 441 mActivityTestRule.executeJavaScript("testObject.getInnerObject().method(
42)"); |
| 401 assertEquals(42, mTestController.waitForIntValue()); | 442 Assert.assertEquals(42, mTestController.waitForIntValue()); |
| 402 } | 443 } |
| 403 | 444 |
| 445 @Test |
| 404 @SmallTest | 446 @SmallTest |
| 405 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 447 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 406 public void testReturnedObjectInjectedElsewhere() throws Throwable { | 448 public void testReturnedObjectInjectedElsewhere() throws Throwable { |
| 407 class InnerObject { | 449 class InnerObject { |
| 408 private int mNumMethodInvocations; | 450 private int mNumMethodInvocations; |
| 409 | 451 |
| 410 public void method() { | 452 public void method() { |
| 411 mTestController.setIntValue(++mNumMethodInvocations); | 453 mTestController.setIntValue(++mNumMethodInvocations); |
| 412 } | 454 } |
| 413 } | 455 } |
| 414 final InnerObject innerObject = new InnerObject(); | 456 final InnerObject innerObject = new InnerObject(); |
| 415 final Object object = new Object() { | 457 final Object object = new Object() { |
| 416 public InnerObject getInnerObject() { | 458 public InnerObject getInnerObject() { |
| 417 return innerObject; | 459 return innerObject; |
| 418 } | 460 } |
| 419 }; | 461 }; |
| 420 injectObjectsAndReload(object, "testObject", innerObject, "innerObject",
null); | 462 mActivityTestRule.injectObjectsAndReload( |
| 421 executeJavaScript("testObject.getInnerObject().method()"); | 463 object, "testObject", innerObject, "innerObject", null); |
| 422 assertEquals(1, mTestController.waitForIntValue()); | 464 mActivityTestRule.executeJavaScript("testObject.getInnerObject().method(
)"); |
| 423 executeJavaScript("innerObject.method()"); | 465 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 424 assertEquals(2, mTestController.waitForIntValue()); | 466 mActivityTestRule.executeJavaScript("innerObject.method()"); |
| 467 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 425 } | 468 } |
| 426 | 469 |
| 427 // Verify that Java objects returned from bridge object methods are derefere
nced | 470 // Verify that Java objects returned from bridge object methods are derefere
nced |
| 428 // on the Java side once they have been fully dereferenced on the JS side. | 471 // on the Java side once they have been fully dereferenced on the JS side. |
| 429 // Failing this test would mean that methods returning objects effectively c
reate a memory | 472 // Failing this test would mean that methods returning objects effectively c
reate a memory |
| 430 // leak. | 473 // leak. |
| 474 @Test |
| 431 @SmallTest | 475 @SmallTest |
| 432 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 476 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 433 @CommandLineFlags.Add("js-flags=--expose-gc") | 477 @CommandLineFlags.Add("js-flags=--expose-gc") |
| 434 public void testReturnedObjectIsGarbageCollected() throws Throwable { | 478 public void testReturnedObjectIsGarbageCollected() throws Throwable { |
| 435 // Make sure V8 exposes "gc" property on the global object (enabled with
--expose-gc flag) | 479 Assert.assertEquals("function", executeJavaScriptAndGetStringResult("typ
eof gc")); |
| 436 assertEquals("function", executeJavaScriptAndGetStringResult("typeof gc"
)); | |
| 437 class InnerObject { | 480 class InnerObject { |
| 438 } | 481 } |
| 439 class TestObject { | 482 class TestObject { |
| 440 public InnerObject getInnerObject() { | 483 public InnerObject getInnerObject() { |
| 441 InnerObject inner = new InnerObject(); | 484 InnerObject inner = new InnerObject(); |
| 442 mWeakRefForInner = new WeakReference<InnerObject>(inner); | 485 mWeakRefForInner = new WeakReference<InnerObject>(inner); |
| 443 return inner; | 486 return inner; |
| 444 } | 487 } |
| 445 // A weak reference is used to check InnerObject instance reachabili
ty. | 488 // A weak reference is used to check InnerObject instance reachabili
ty. |
| 446 WeakReference<InnerObject> mWeakRefForInner; | 489 WeakReference<InnerObject> mWeakRefForInner; |
| 447 } | 490 } |
| 448 TestObject object = new TestObject(); | 491 TestObject object = new TestObject(); |
| 449 injectObjectAndReload(object, "testObject"); | 492 mActivityTestRule.injectObjectAndReload(object, "testObject"); |
| 450 // Initially, store a reference to the inner object in JS to make sure i
t's not | 493 // Initially, store a reference to the inner object in JS to make sure i
t's not |
| 451 // garbage-collected prematurely. | 494 // garbage-collected prematurely. |
| 452 assertEquals("object", executeJavaScriptAndGetStringResult( | 495 Assert.assertEquals("object", |
| 453 "(function() { " | 496 executeJavaScriptAndGetStringResult("(function() { " |
| 454 + "globalInner = testObject.getInnerObject(); return typ
eof globalInner; " | 497 + "globalInner = testObject.getInnerObject(); return typ
eof globalInner; " |
| 455 + "})()")); | 498 + "})()")); |
| 456 assertTrue(object.mWeakRefForInner.get() != null); | 499 Assert.assertTrue(object.mWeakRefForInner.get() != null); |
| 457 // Check that returned Java object is being held by the Java bridge, thu
s it's not | 500 // Check that returned Java object is being held by the Java bridge, thu
s it's not |
| 458 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik | 501 // collected. Note that despite that what JavaDoc says about invoking "
gc()", both Dalvik |
| 459 // and ART actually run the collector. | 502 // and ART actually run the collector. |
| 460 Runtime.getRuntime().gc(); | 503 Runtime.getRuntime().gc(); |
| 461 assertTrue(object.mWeakRefForInner.get() != null); | 504 Assert.assertTrue(object.mWeakRefForInner.get() != null); |
| 462 // Now dereference the inner object in JS and run GC to collect the inte
rface object. | 505 // Now dereference the inner object in JS and run GC to collect the inte
rface object. |
| 463 assertEquals("true", executeJavaScriptAndGetStringResult( | 506 Assert.assertEquals("true", |
| 464 "(function() { " | 507 executeJavaScriptAndGetStringResult("(function() { " |
| 465 + "delete globalInner; gc(); return (typeof globalInner
== 'undefined'); " | 508 + "delete globalInner; gc(); return (typeof globalInner
== 'undefined'); " |
| 466 + "})()")); | 509 + "})()")); |
| 467 // Force GC on the Java side again. The bridge had to release the inner
object, so it must | 510 // Force GC on the Java side again. The bridge had to release the inner
object, so it must |
| 468 // be collected this time. | 511 // be collected this time. |
| 469 Runtime.getRuntime().gc(); | 512 Runtime.getRuntime().gc(); |
| 470 assertEquals(null, object.mWeakRefForInner.get()); | 513 Assert.assertEquals(null, object.mWeakRefForInner.get()); |
| 471 } | 514 } |
| 472 | 515 |
| 516 @Test |
| 473 @SmallTest | 517 @SmallTest |
| 474 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 518 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 475 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { | 519 public void testSameReturnedObjectUsesSameWrapper() throws Throwable { |
| 476 class InnerObject { | 520 class InnerObject { |
| 477 } | 521 } |
| 478 final InnerObject innerObject = new InnerObject(); | 522 final InnerObject innerObject = new InnerObject(); |
| 479 final Object injectedTestObject = new Object() { | 523 final Object injectedTestObject = new Object() { |
| 480 public InnerObject getInnerObject() { | 524 public InnerObject getInnerObject() { |
| 481 return innerObject; | 525 return innerObject; |
| 482 } | 526 } |
| 483 }; | 527 }; |
| 484 injectObjectAndReload(injectedTestObject, "injectedTestObject"); | 528 mActivityTestRule.injectObjectAndReload(injectedTestObject, "injectedTes
tObject"); |
| 485 executeJavaScript("inner1 = injectedTestObject.getInnerObject()"); | 529 mActivityTestRule.executeJavaScript("inner1 = injectedTestObject.getInne
rObject()"); |
| 486 executeJavaScript("inner2 = injectedTestObject.getInnerObject()"); | 530 mActivityTestRule.executeJavaScript("inner2 = injectedTestObject.getInne
rObject()"); |
| 487 assertEquals("object", executeJavaScriptAndGetStringResult("typeof inner
1")); | 531 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f inner1")); |
| 488 assertEquals("object", executeJavaScriptAndGetStringResult("typeof inner
2")); | 532 Assert.assertEquals("object", executeJavaScriptAndGetStringResult("typeo
f inner2")); |
| 489 assertEquals("true", executeJavaScriptAndGetStringResult("inner1 === inn
er2")); | 533 Assert.assertEquals("true", executeJavaScriptAndGetStringResult("inner1
=== inner2")); |
| 490 } | 534 } |
| 491 | 535 |
| 536 @Test |
| 492 @SmallTest | 537 @SmallTest |
| 493 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 538 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 494 public void testMethodInvokedOnBackgroundThread() throws Throwable { | 539 public void testMethodInvokedOnBackgroundThread() throws Throwable { |
| 495 injectObjectAndReload(new Object() { | 540 mActivityTestRule.injectObjectAndReload(new Object() { |
| 496 public void captureThreadId() { | 541 public void captureThreadId() { |
| 497 mTestController.setLongValue(Thread.currentThread().getId()); | 542 mTestController.setLongValue(Thread.currentThread().getId()); |
| 498 } | 543 } |
| 499 }, "testObject"); | 544 }, "testObject"); |
| 500 executeJavaScript("testObject.captureThreadId()"); | 545 mActivityTestRule.executeJavaScript("testObject.captureThreadId()"); |
| 501 final long threadId = mTestController.waitForLongValue(); | 546 final long threadId = mTestController.waitForLongValue(); |
| 502 assertFalse(threadId == Thread.currentThread().getId()); | 547 Assert.assertFalse(threadId == Thread.currentThread().getId()); |
| 503 runTestOnUiThread(new Runnable() { | 548 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 504 @Override | 549 @Override |
| 505 public void run() { | 550 public void run() { |
| 506 assertFalse(threadId == Thread.currentThread().getId()); | 551 Assert.assertFalse(threadId == Thread.currentThread().getId()); |
| 507 } | 552 } |
| 508 }); | 553 }); |
| 509 } | 554 } |
| 510 | 555 |
| 556 @Test |
| 511 @SmallTest | 557 @SmallTest |
| 512 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 558 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 513 public void testBlockingUiThreadDoesNotBlockCallsFromJs() throws Throwable { | 559 public void testBlockingUiThreadDoesNotBlockCallsFromJs() throws Throwable { |
| 514 class TestObject { | 560 class TestObject { |
| 515 private CountDownLatch mLatch; | 561 private CountDownLatch mLatch; |
| 516 public TestObject() { | 562 public TestObject() { |
| 517 mLatch = new CountDownLatch(1); | 563 mLatch = new CountDownLatch(1); |
| 518 } | 564 } |
| 519 public boolean waitOnTheLatch() throws Exception { | 565 public boolean waitOnTheLatch() throws Exception { |
| 520 return mLatch.await(scaleTimeout(10000), | 566 return mLatch.await(scaleTimeout(10000), |
| 521 java.util.concurrent.TimeUnit.MILLISECONDS); | 567 java.util.concurrent.TimeUnit.MILLISECONDS); |
| 522 } | 568 } |
| 523 public void unlockTheLatch() throws Exception { | 569 public void unlockTheLatch() throws Exception { |
| 524 mTestController.setStringValue("unlocked"); | 570 mTestController.setStringValue("unlocked"); |
| 525 mLatch.countDown(); | 571 mLatch.countDown(); |
| 526 } | 572 } |
| 527 } | 573 } |
| 528 final TestObject testObject = new TestObject(); | 574 final TestObject testObject = new TestObject(); |
| 529 injectObjectAndReload(testObject, "testObject"); | 575 mActivityTestRule.injectObjectAndReload(testObject, "testObject"); |
| 530 runTestOnUiThread(new Runnable() { | 576 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 531 @Override | 577 @Override |
| 532 public void run() { | 578 public void run() { |
| 533 // loadUrl is asynchronous, the JS code will start running on th
e renderer | 579 // loadUrl is asynchronous, the JS code will start running on th
e renderer |
| 534 // thread. As soon as we exit loadUrl, the browser UI thread wil
l be stuck waiting | 580 // thread. As soon as we exit loadUrl, the browser UI thread wil
l be stuck waiting |
| 535 // on the latch. If blocking the browser thread blocks Java Brid
ge, then the call | 581 // on the latch. If blocking the browser thread blocks Java Brid
ge, then the call |
| 536 // to "unlockTheLatch()" will be executed after the waiting time
out, thus the | 582 // to "unlockTheLatch()" will be executed after the waiting time
out, thus the |
| 537 // string value will not yet be updated by the injected object. | 583 // string value will not yet be updated by the injected object. |
| 538 mTestController.setStringValue("locked"); | 584 mTestController.setStringValue("locked"); |
| 539 getWebContents().getNavigationController().loadUrl(new LoadUrlPa
rams( | 585 mActivityTestRule.getWebContents().getNavigationController().loa
dUrl( |
| 540 "javascript:(function() { testObject.unlockTheLatch() })
()")); | 586 new LoadUrlParams( |
| 587 "javascript:(function() { testObject.unlockTheLa
tch() })()")); |
| 541 try { | 588 try { |
| 542 assertTrue(testObject.waitOnTheLatch()); | 589 Assert.assertTrue(testObject.waitOnTheLatch()); |
| 543 } catch (Exception e) { | 590 } catch (Exception e) { |
| 544 android.util.Log.e("JavaBridgeBasicsTest", "Wait exception",
e); | 591 android.util.Log.e("JavaBridgeBasicsTest", "Wait exception",
e); |
| 545 Assert.fail("Wait exception"); | 592 Assert.fail("Wait exception"); |
| 546 } | 593 } |
| 547 assertEquals("unlocked", mTestController.getStringValue()); | 594 Assert.assertEquals("unlocked", mTestController.getStringValue()
); |
| 548 } | 595 } |
| 549 }); | 596 }); |
| 550 } | 597 } |
| 551 | 598 |
| 599 @Test |
| 552 @SmallTest | 600 @SmallTest |
| 553 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 601 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 554 public void testPublicInheritedMethod() throws Throwable { | 602 public void testPublicInheritedMethod() throws Throwable { |
| 555 class Base { | 603 class Base { |
| 556 public void method(int x) { | 604 public void method(int x) { |
| 557 mTestController.setIntValue(x); | 605 mTestController.setIntValue(x); |
| 558 } | 606 } |
| 559 } | 607 } |
| 560 class Derived extends Base { | 608 class Derived extends Base { |
| 561 } | 609 } |
| 562 injectObjectAndReload(new Derived(), "testObject"); | 610 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 563 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.method")); | 611 Assert.assertEquals( |
| 564 executeJavaScript("testObject.method(42)"); | 612 "function", executeJavaScriptAndGetStringResult("typeof testObje
ct.method")); |
| 565 assertEquals(42, mTestController.waitForIntValue()); | 613 mActivityTestRule.executeJavaScript("testObject.method(42)"); |
| 614 Assert.assertEquals(42, mTestController.waitForIntValue()); |
| 566 } | 615 } |
| 567 | 616 |
| 617 @Test |
| 568 @SmallTest | 618 @SmallTest |
| 569 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 619 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 570 public void testPrivateInheritedMethod() throws Throwable { | 620 public void testPrivateInheritedMethod() throws Throwable { |
| 571 class Base { | 621 class Base { |
| 572 private void method() {} | 622 private void method() {} |
| 573 } | 623 } |
| 574 class Derived extends Base { | 624 class Derived extends Base { |
| 575 } | 625 } |
| 576 injectObjectAndReload(new Derived(), "testObject"); | 626 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 577 assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof te
stObject.method")); | 627 Assert.assertEquals( |
| 628 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.method")); |
| 578 } | 629 } |
| 579 | 630 |
| 631 @Test |
| 580 @SmallTest | 632 @SmallTest |
| 581 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 633 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 582 public void testOverriddenMethod() throws Throwable { | 634 public void testOverriddenMethod() throws Throwable { |
| 583 class Base { | 635 class Base { |
| 584 public void method() { | 636 public void method() { |
| 585 mTestController.setStringValue("base"); | 637 mTestController.setStringValue("base"); |
| 586 } | 638 } |
| 587 } | 639 } |
| 588 class Derived extends Base { | 640 class Derived extends Base { |
| 589 @Override | 641 @Override |
| 590 public void method() { | 642 public void method() { |
| 591 mTestController.setStringValue("derived"); | 643 mTestController.setStringValue("derived"); |
| 592 } | 644 } |
| 593 } | 645 } |
| 594 injectObjectAndReload(new Derived(), "testObject"); | 646 mActivityTestRule.injectObjectAndReload(new Derived(), "testObject"); |
| 595 executeJavaScript("testObject.method()"); | 647 mActivityTestRule.executeJavaScript("testObject.method()"); |
| 596 assertEquals("derived", mTestController.waitForStringValue()); | 648 Assert.assertEquals("derived", mTestController.waitForStringValue()); |
| 597 } | 649 } |
| 598 | 650 |
| 651 @Test |
| 599 @SmallTest | 652 @SmallTest |
| 600 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 653 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 601 public void testEnumerateMembers() throws Throwable { | 654 public void testEnumerateMembers() throws Throwable { |
| 602 injectObjectAndReload(new Object() { | 655 mActivityTestRule.injectObjectAndReload(new Object() { |
| 603 public void method() {} | 656 public void method() {} |
| 604 private void privateMethod() {} | 657 private void privateMethod() {} |
| 605 @SuppressFBWarnings("UUF_UNUSED") | 658 @SuppressFBWarnings("UUF_UNUSED") |
| 606 public int field; | 659 public int field; |
| 607 @SuppressFBWarnings("UUF_UNUSED") | 660 @SuppressFBWarnings("UUF_UNUSED") |
| 608 private int mPrivateField; | 661 private int mPrivateField; |
| 609 }, "testObject"); | 662 }, "testObject"); |
| 610 executeJavaScript( | 663 mActivityTestRule.executeJavaScript("var result = \"\"; " |
| 611 "var result = \"\"; " | |
| 612 + "for (x in testObject) { result += \" \" + x } " | 664 + "for (x in testObject) { result += \" \" + x } " |
| 613 + "testController.setStringValue(result);"); | 665 + "testController.setStringValue(result);"); |
| 614 assertEquals(" equals getClass hashCode method notify notifyAll toString
wait", | 666 Assert.assertEquals(" equals getClass hashCode method notify notifyAll t
oString wait", |
| 615 mTestController.waitForStringValue()); | 667 mTestController.waitForStringValue()); |
| 616 } | 668 } |
| 617 | 669 |
| 670 @Test |
| 618 @SmallTest | 671 @SmallTest |
| 619 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 672 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 620 public void testReflectPublicMethod() throws Throwable { | 673 public void testReflectPublicMethod() throws Throwable { |
| 621 injectObjectAndReload(new Object() { | 674 mActivityTestRule.injectObjectAndReload(new Object() { |
| 622 public Class<?> myGetClass() { | 675 public Class<?> myGetClass() { |
| 623 return getClass(); | 676 return getClass(); |
| 624 } | 677 } |
| 625 | 678 |
| 626 public String method() { | 679 public String method() { |
| 627 return "foo"; | 680 return "foo"; |
| 628 } | 681 } |
| 629 }, "testObject"); | 682 }, "testObject"); |
| 630 assertEquals("foo", executeJavaScriptAndGetStringResult( | 683 Assert.assertEquals("foo", |
| 631 "testObject.myGetClass().getMethod('method', null).invoke(testOb
ject, null)" | 684 executeJavaScriptAndGetStringResult( |
| 632 + ".toString()")); | 685 "testObject.myGetClass().getMethod('method', null).invok
e(testObject, null)" |
| 686 + ".toString()")); |
| 633 } | 687 } |
| 634 | 688 |
| 689 @Test |
| 635 @SmallTest | 690 @SmallTest |
| 636 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 691 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 637 public void testReflectPublicField() throws Throwable { | 692 public void testReflectPublicField() throws Throwable { |
| 638 injectObjectAndReload(new Object() { | 693 mActivityTestRule.injectObjectAndReload(new Object() { |
| 639 public Class<?> myGetClass() { | 694 public Class<?> myGetClass() { |
| 640 return getClass(); | 695 return getClass(); |
| 641 } | 696 } |
| 642 | 697 |
| 643 public String field = "foo"; | 698 public String field = "foo"; |
| 644 }, "testObject"); | 699 }, "testObject"); |
| 645 assertEquals("foo", executeJavaScriptAndGetStringResult( | 700 Assert.assertEquals("foo", |
| 646 "testObject.myGetClass().getField('field').get(testObject).toStr
ing()")); | 701 executeJavaScriptAndGetStringResult( |
| 702 "testObject.myGetClass().getField('field').get(testObjec
t).toString()")); |
| 647 } | 703 } |
| 648 | 704 |
| 705 @Test |
| 649 @SmallTest | 706 @SmallTest |
| 650 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 707 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 651 public void testReflectPrivateMethodRaisesException() throws Throwable { | 708 public void testReflectPrivateMethodRaisesException() throws Throwable { |
| 652 injectObjectAndReload(new Object() { | 709 mActivityTestRule.injectObjectAndReload(new Object() { |
| 653 public Class<?> myGetClass() { | 710 public Class<?> myGetClass() { |
| 654 return getClass(); | 711 return getClass(); |
| 655 } | 712 } |
| 656 | 713 |
| 657 private void method() {}; | 714 private void method() {}; |
| 658 }, "testObject"); | 715 }, "testObject"); |
| 659 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); | 716 assertRaisesException("testObject.myGetClass().getMethod('method', null)
"); |
| 660 // getDeclaredMethod() is able to access a private method, but invoke() | 717 // getDeclaredMethod() is able to access a private method, but invoke() |
| 661 // throws a Java exception. | 718 // throws a Java exception. |
| 662 assertRaisesException( | 719 assertRaisesException( |
| 663 "testObject.myGetClass().getDeclaredMethod('method', null)." | 720 "testObject.myGetClass().getDeclaredMethod('method', null)." |
| 664 + "invoke(testObject, null)"); | 721 + "invoke(testObject, null)"); |
| 665 } | 722 } |
| 666 | 723 |
| 724 @Test |
| 667 @SmallTest | 725 @SmallTest |
| 668 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 726 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 669 public void testReflectPrivateFieldRaisesException() throws Throwable { | 727 public void testReflectPrivateFieldRaisesException() throws Throwable { |
| 670 injectObjectAndReload(new Object() { | 728 mActivityTestRule.injectObjectAndReload(new Object() { |
| 671 public Class<?> myGetClass() { | 729 public Class<?> myGetClass() { |
| 672 return getClass(); | 730 return getClass(); |
| 673 } | 731 } |
| 674 | 732 |
| 675 @SuppressFBWarnings("UUF_UNUSED") | 733 @SuppressFBWarnings("UUF_UNUSED") |
| 676 private int mField; | 734 private int mField; |
| 677 }, "testObject"); | 735 }, "testObject"); |
| 678 String fieldName = "mField"; | 736 String fieldName = "mField"; |
| 679 assertRaisesException("testObject.myGetClass().getField('" + fieldName +
"')"); | 737 assertRaisesException("testObject.myGetClass().getField('" + fieldName +
"')"); |
| 680 // getDeclaredField() is able to access a private field, but getInt() | 738 // getDeclaredField() is able to access a private field, but getInt() |
| 681 // throws a Java exception. | 739 // throws a Java exception. |
| 682 assertNoRaisedException("testObject.myGetClass().getDeclaredField('" + f
ieldName + "')"); | 740 assertNoRaisedException("testObject.myGetClass().getDeclaredField('" + f
ieldName + "')"); |
| 683 assertRaisesException( | 741 assertRaisesException( |
| 684 "testObject.myGetClass().getDeclaredField('" + fieldName + "').g
etInt(testObject)"); | 742 "testObject.myGetClass().getDeclaredField('" + fieldName + "').g
etInt(testObject)"); |
| 685 } | 743 } |
| 686 | 744 |
| 745 @Test |
| 687 @SmallTest | 746 @SmallTest |
| 688 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 747 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 689 public void testAllowNonAnnotatedMethods() throws Throwable { | 748 public void testAllowNonAnnotatedMethods() throws Throwable { |
| 690 injectObjectAndReload(new Object() { | 749 mActivityTestRule.injectObjectAndReload(new Object() { |
| 691 public String allowed() { | 750 public String allowed() { |
| 692 return "foo"; | 751 return "foo"; |
| 693 } | 752 } |
| 694 }, "testObject", null); | 753 }, "testObject", null); |
| 695 | 754 |
| 696 // Test calling a method of an explicitly inherited class (Base#allowed(
)). | 755 // Test calling a method of an explicitly inherited class (Base#allowed(
)). |
| 697 assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.allo
wed()")); | 756 Assert.assertEquals("foo", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 698 | 757 |
| 699 // Test calling a method of an implicitly inherited class (Object#toStri
ng()). | 758 // Test calling a method of an implicitly inherited class (Object#toStri
ng()). |
| 700 assertEquals("string", executeJavaScriptAndGetStringResult("typeof testO
bject.toString()")); | 759 Assert.assertEquals( |
| 760 "string", executeJavaScriptAndGetStringResult("typeof testObject
.toString()")); |
| 701 } | 761 } |
| 702 | 762 |
| 763 @Test |
| 703 @SmallTest | 764 @SmallTest |
| 704 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 765 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 705 public void testAllowOnlyAnnotatedMethods() throws Throwable { | 766 public void testAllowOnlyAnnotatedMethods() throws Throwable { |
| 706 injectObjectAndReload(new Object() { | 767 mActivityTestRule.injectObjectAndReload(new Object() { |
| 707 @JavascriptInterface | 768 @JavascriptInterface |
| 708 public String allowed() { | 769 public String allowed() { |
| 709 return "foo"; | 770 return "foo"; |
| 710 } | 771 } |
| 711 | 772 |
| 712 public String disallowed() { | 773 public String disallowed() { |
| 713 return "bar"; | 774 return "bar"; |
| 714 } | 775 } |
| 715 }, "testObject", JavascriptInterface.class); | 776 }, "testObject", JavascriptInterface.class); |
| 716 | 777 |
| 717 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and | 778 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and |
| 718 // should not be able to be called. | 779 // should not be able to be called. |
| 719 assertRaisesException("testObject.getClass()"); | 780 assertRaisesException("testObject.getClass()"); |
| 720 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 781 Assert.assertEquals( |
| 721 "typeof testObject.getClass")); | 782 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.getClass")); |
| 722 | 783 |
| 723 // allowed() is marked with the @JavascriptInterface annotation and shou
ld be allowed to be | 784 // allowed() is marked with the @JavascriptInterface annotation and shou
ld be allowed to be |
| 724 // called. | 785 // called. |
| 725 assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.allo
wed()")); | 786 Assert.assertEquals("foo", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 726 | 787 |
| 727 // disallowed() is not marked with the @JavascriptInterface annotation a
nd should not be | 788 // disallowed() is not marked with the @JavascriptInterface annotation a
nd should not be |
| 728 // able to be called. | 789 // able to be called. |
| 729 assertRaisesException("testObject.disallowed()"); | 790 assertRaisesException("testObject.disallowed()"); |
| 730 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 791 Assert.assertEquals( |
| 731 "typeof testObject.disallowed")); | 792 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.disallowed")); |
| 732 } | 793 } |
| 733 | 794 |
| 795 @Test |
| 734 @SmallTest | 796 @SmallTest |
| 735 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 797 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 736 public void testAnnotationRequirementRetainsPropertyAcrossObjects() throws T
hrowable { | 798 public void testAnnotationRequirementRetainsPropertyAcrossObjects() throws T
hrowable { |
| 737 class Test { | 799 class Test { |
| 738 @JavascriptInterface | 800 @JavascriptInterface |
| 739 public String safe() { | 801 public String safe() { |
| 740 return "foo"; | 802 return "foo"; |
| 741 } | 803 } |
| 742 | 804 |
| 743 public String unsafe() { | 805 public String unsafe() { |
| 744 return "bar"; | 806 return "bar"; |
| 745 } | 807 } |
| 746 } | 808 } |
| 747 | 809 |
| 748 class TestReturner { | 810 class TestReturner { |
| 749 @JavascriptInterface | 811 @JavascriptInterface |
| 750 public Test getTest() { | 812 public Test getTest() { |
| 751 return new Test(); | 813 return new Test(); |
| 752 } | 814 } |
| 753 } | 815 } |
| 754 | 816 |
| 755 // First test with safe mode off. | 817 // First test with safe mode off. |
| 756 injectObjectAndReload(new TestReturner(), "unsafeTestObject", null); | 818 mActivityTestRule.injectObjectAndReload(new TestReturner(), "unsafeTestO
bject", null); |
| 757 | 819 |
| 758 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. | 820 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. |
| 759 assertEquals("foo", executeJavaScriptAndGetStringResult( | 821 Assert.assertEquals( |
| 760 "unsafeTestObject.getTest().safe()")); | 822 "foo", executeJavaScriptAndGetStringResult("unsafeTestObject.get
Test().safe()")); |
| 761 // unsafe() should be able to be called because we are not in safe mode. | 823 // unsafe() should be able to be called because we are not in safe mode. |
| 762 assertEquals("bar", executeJavaScriptAndGetStringResult( | 824 Assert.assertEquals( |
| 763 "unsafeTestObject.getTest().unsafe()")); | 825 "bar", executeJavaScriptAndGetStringResult("unsafeTestObject.get
Test().unsafe()")); |
| 764 | 826 |
| 765 // Now test with safe mode on. | 827 // Now test with safe mode on. |
| 766 injectObjectAndReload(new TestReturner(), "safeTestObject", JavascriptIn
terface.class); | 828 mActivityTestRule.injectObjectAndReload( |
| 829 new TestReturner(), "safeTestObject", JavascriptInterface.class)
; |
| 767 | 830 |
| 768 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. | 831 // safe() should be able to be called regardless of whether or not we ar
e in safe mode. |
| 769 assertEquals("foo", executeJavaScriptAndGetStringResult( | 832 Assert.assertEquals( |
| 770 "safeTestObject.getTest().safe()")); | 833 "foo", executeJavaScriptAndGetStringResult("safeTestObject.getTe
st().safe()")); |
| 771 // unsafe() should not be able to be called because we are in safe mode. | 834 // unsafe() should not be able to be called because we are in safe mode. |
| 772 assertRaisesException("safeTestObject.getTest().unsafe()"); | 835 assertRaisesException("safeTestObject.getTest().unsafe()"); |
| 773 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 836 Assert.assertEquals("undefined", |
| 774 "typeof safeTestObject.getTest().unsafe")); | 837 executeJavaScriptAndGetStringResult("typeof safeTestObject.getTe
st().unsafe")); |
| 775 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and | 838 // getClass() is an Object method and does not have the @JavascriptInter
face annotation and |
| 776 // should not be able to be called. | 839 // should not be able to be called. |
| 777 assertRaisesException("safeTestObject.getTest().getClass()"); | 840 assertRaisesException("safeTestObject.getTest().getClass()"); |
| 778 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 841 Assert.assertEquals("undefined", |
| 779 "typeof safeTestObject.getTest().getClass")); | 842 executeJavaScriptAndGetStringResult("typeof safeTestObject.getTe
st().getClass")); |
| 780 } | 843 } |
| 781 | 844 |
| 845 @Test |
| 782 @SmallTest | 846 @SmallTest |
| 783 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 847 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 784 public void testAnnotationDoesNotGetInherited() throws Throwable { | 848 public void testAnnotationDoesNotGetInherited() throws Throwable { |
| 785 class Base { | 849 class Base { |
| 786 @JavascriptInterface | 850 @JavascriptInterface |
| 787 public void base() { } | 851 public void base() { } |
| 788 } | 852 } |
| 789 | 853 |
| 790 class Child extends Base { | 854 class Child extends Base { |
| 791 @Override | 855 @Override |
| 792 public void base() { } | 856 public void base() { } |
| 793 } | 857 } |
| 794 | 858 |
| 795 injectObjectAndReload(new Child(), "testObject", JavascriptInterface.cla
ss); | 859 mActivityTestRule.injectObjectAndReload( |
| 860 new Child(), "testObject", JavascriptInterface.class); |
| 796 | 861 |
| 797 // base() is inherited. The inherited method does not have the @Javascr
iptInterface | 862 // base() is inherited. The inherited method does not have the @Javascr
iptInterface |
| 798 // annotation and should not be able to be called. | 863 // annotation and should not be able to be called. |
| 799 assertRaisesException("testObject.base()"); | 864 assertRaisesException("testObject.base()"); |
| 800 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 865 Assert.assertEquals( |
| 801 "typeof testObject.base")); | 866 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.base")); |
| 802 } | 867 } |
| 803 | 868 |
| 804 @SuppressWarnings("javadoc") | 869 @SuppressWarnings("javadoc") |
| 805 @Retention(RetentionPolicy.RUNTIME) | 870 @Retention(RetentionPolicy.RUNTIME) |
| 806 @Target({ElementType.METHOD}) | 871 @Target({ElementType.METHOD}) |
| 807 @interface TestAnnotation { | 872 @interface TestAnnotation { |
| 808 } | 873 } |
| 809 | 874 |
| 875 @Test |
| 810 @SmallTest | 876 @SmallTest |
| 811 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 877 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 812 public void testCustomAnnotationRestriction() throws Throwable { | 878 public void testCustomAnnotationRestriction() throws Throwable { |
| 813 class Test { | 879 class Test { |
| 814 @TestAnnotation | 880 @TestAnnotation |
| 815 public String checkTestAnnotationFoo() { | 881 public String checkTestAnnotationFoo() { |
| 816 return "bar"; | 882 return "bar"; |
| 817 } | 883 } |
| 818 | 884 |
| 819 @JavascriptInterface | 885 @JavascriptInterface |
| 820 public String checkJavascriptInterfaceFoo() { | 886 public String checkJavascriptInterfaceFoo() { |
| 821 return "bar"; | 887 return "bar"; |
| 822 } | 888 } |
| 823 } | 889 } |
| 824 | 890 |
| 825 // Inject javascriptInterfaceObj and require the JavascriptInterface ann
otation. | 891 // Inject javascriptInterfaceObj and require the JavascriptInterface ann
otation. |
| 826 injectObjectAndReload(new Test(), "javascriptInterfaceObj", JavascriptIn
terface.class); | 892 mActivityTestRule.injectObjectAndReload( |
| 893 new Test(), "javascriptInterfaceObj", JavascriptInterface.class)
; |
| 827 | 894 |
| 828 // Test#testAnnotationFoo() should fail, as it isn't annotated with Java
scriptInterface. | 895 // Test#testAnnotationFoo() should fail, as it isn't annotated with Java
scriptInterface. |
| 829 assertRaisesException("javascriptInterfaceObj.checkTestAnnotationFoo()")
; | 896 assertRaisesException("javascriptInterfaceObj.checkTestAnnotationFoo()")
; |
| 830 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 897 Assert.assertEquals("undefined", |
| 831 "typeof javascriptInterfaceObj.checkTestAnnotationFoo")); | 898 executeJavaScriptAndGetStringResult( |
| 899 "typeof javascriptInterfaceObj.checkTestAnnotationFoo"))
; |
| 832 | 900 |
| 833 // Test#javascriptInterfaceFoo() should pass, as it is annotated with Ja
vascriptInterface. | 901 // Test#javascriptInterfaceFoo() should pass, as it is annotated with Ja
vascriptInterface. |
| 834 assertEquals("bar", executeJavaScriptAndGetStringResult( | 902 Assert.assertEquals("bar", |
| 835 "javascriptInterfaceObj.checkJavascriptInterfaceFoo()")); | 903 executeJavaScriptAndGetStringResult( |
| 904 "javascriptInterfaceObj.checkJavascriptInterfaceFoo()"))
; |
| 836 | 905 |
| 837 // Inject testAnnotationObj and require the TestAnnotation annotation. | 906 // Inject testAnnotationObj and require the TestAnnotation annotation. |
| 838 injectObjectAndReload(new Test(), "testAnnotationObj", TestAnnotation.cl
ass); | 907 mActivityTestRule.injectObjectAndReload( |
| 908 new Test(), "testAnnotationObj", TestAnnotation.class); |
| 839 | 909 |
| 840 // Test#testAnnotationFoo() should pass, as it is annotated with TestAnn
otation. | 910 // Test#testAnnotationFoo() should pass, as it is annotated with TestAnn
otation. |
| 841 assertEquals("bar", executeJavaScriptAndGetStringResult( | 911 Assert.assertEquals("bar", |
| 842 "testAnnotationObj.checkTestAnnotationFoo()")); | 912 executeJavaScriptAndGetStringResult("testAnnotationObj.checkTest
AnnotationFoo()")); |
| 843 | 913 |
| 844 // Test#javascriptInterfaceFoo() should fail, as it isn't annotated with
TestAnnotation. | 914 // Test#javascriptInterfaceFoo() should fail, as it isn't annotated with
TestAnnotation. |
| 845 assertRaisesException("testAnnotationObj.checkJavascriptInterfaceFoo()")
; | 915 assertRaisesException("testAnnotationObj.checkJavascriptInterfaceFoo()")
; |
| 846 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 916 Assert.assertEquals("undefined", |
| 847 "typeof testAnnotationObj.checkJavascriptInterfaceFoo")); | 917 executeJavaScriptAndGetStringResult( |
| 918 "typeof testAnnotationObj.checkJavascriptInterfaceFoo"))
; |
| 848 } | 919 } |
| 849 | 920 |
| 921 @Test |
| 850 @SmallTest | 922 @SmallTest |
| 851 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 923 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 852 public void testAddJavascriptInterfaceIsSafeByDefault() throws Throwable { | 924 public void testAddJavascriptInterfaceIsSafeByDefault() throws Throwable { |
| 853 class Test { | 925 class Test { |
| 854 public String blocked() { | 926 public String blocked() { |
| 855 return "bar"; | 927 return "bar"; |
| 856 } | 928 } |
| 857 | 929 |
| 858 @JavascriptInterface | 930 @JavascriptInterface |
| 859 public String allowed() { | 931 public String allowed() { |
| 860 return "bar"; | 932 return "bar"; |
| 861 } | 933 } |
| 862 } | 934 } |
| 863 | 935 |
| 864 // Manually inject the Test object, making sure to use the | 936 // Manually inject the Test object, making sure to use the |
| 865 // ContentViewCore#addJavascriptInterface, not the possibly unsafe versi
on. | 937 // ContentViewCore#addJavascriptInterface, not the possibly unsafe versi
on. |
| 866 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = | 938 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = |
| 867 getTestCallBackHelperContainer().getOnPageFinishedHelper(); | 939 mActivityTestRule.getTestCallBackHelperContainer().getOnPageFini
shedHelper(); |
| 868 int currentCallCount = onPageFinishedHelper.getCallCount(); | 940 int currentCallCount = onPageFinishedHelper.getCallCount(); |
| 869 runTestOnUiThread(new Runnable() { | 941 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 870 @Override | 942 @Override |
| 871 public void run() { | 943 public void run() { |
| 872 getContentViewCore().addJavascriptInterface(new Test(), | 944 mActivityTestRule.getContentViewCore().addJavascriptInterface( |
| 873 "testObject"); | 945 new Test(), "testObject"); |
| 874 getContentViewCore().getWebContents().getNavigationController().
reload(true); | 946 mActivityTestRule.getContentViewCore() |
| 947 .getWebContents() |
| 948 .getNavigationController() |
| 949 .reload(true); |
| 875 } | 950 } |
| 876 }); | 951 }); |
| 877 onPageFinishedHelper.waitForCallback(currentCallCount); | 952 onPageFinishedHelper.waitForCallback(currentCallCount); |
| 878 | 953 |
| 879 // Test#allowed() should pass, as it is annotated with JavascriptInterfa
ce. | 954 // Test#allowed() should pass, as it is annotated with JavascriptInterfa
ce. |
| 880 assertEquals("bar", executeJavaScriptAndGetStringResult( | 955 Assert.assertEquals("bar", executeJavaScriptAndGetStringResult("testObje
ct.allowed()")); |
| 881 "testObject.allowed()")); | |
| 882 | 956 |
| 883 // Test#blocked() should fail, as it isn't annotated with JavascriptInte
rface. | 957 // Test#blocked() should fail, as it isn't annotated with JavascriptInte
rface. |
| 884 assertRaisesException("testObject.blocked()"); | 958 assertRaisesException("testObject.blocked()"); |
| 885 assertEquals("undefined", executeJavaScriptAndGetStringResult( | 959 Assert.assertEquals( |
| 886 "typeof testObject.blocked")); | 960 "undefined", executeJavaScriptAndGetStringResult("typeof testObj
ect.blocked")); |
| 887 } | 961 } |
| 888 | 962 |
| 963 @Test |
| 889 @SmallTest | 964 @SmallTest |
| 890 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 965 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 891 public void testObjectsInspection() throws Throwable { | 966 public void testObjectsInspection() throws Throwable { |
| 892 class Test { | 967 class Test { |
| 893 @JavascriptInterface | 968 @JavascriptInterface |
| 894 public String m1() { | 969 public String m1() { |
| 895 return "foo"; | 970 return "foo"; |
| 896 } | 971 } |
| 897 | 972 |
| 898 @JavascriptInterface | 973 @JavascriptInterface |
| 899 public String m2() { | 974 public String m2() { |
| 900 return "bar"; | 975 return "bar"; |
| 901 } | 976 } |
| 902 | 977 |
| 903 @JavascriptInterface | 978 @JavascriptInterface |
| 904 public String m2(int x) { | 979 public String m2(int x) { |
| 905 return "bar " + x; | 980 return "bar " + x; |
| 906 } | 981 } |
| 907 } | 982 } |
| 908 | 983 |
| 909 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; | 984 final String jsObjectKeysTestTemplate = "Object.keys(%s).toString()"; |
| 910 final String jsForInTestTemplate = | 985 final String jsForInTestTemplate = |
| 911 "(function(){" | 986 "(function(){" |
| 912 + " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" | 987 + " var s=[]; for(var m in %s) s.push(m); return s.join(\",\")" |
| 913 + "})()"; | 988 + "})()"; |
| 914 final String inspectableObjectName = "testObj1"; | 989 final String inspectableObjectName = "testObj1"; |
| 915 final String nonInspectableObjectName = "testObj2"; | 990 final String nonInspectableObjectName = "testObj2"; |
| 916 | 991 |
| 917 // Inspection is enabled by default. | 992 // Inspection is enabled by default. |
| 918 injectObjectAndReload(new Test(), inspectableObjectName, JavascriptInter
face.class); | 993 mActivityTestRule.injectObjectAndReload( |
| 994 new Test(), inspectableObjectName, JavascriptInterface.class); |
| 919 | 995 |
| 920 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 996 Assert.assertEquals("m1,m2", |
| 997 executeJavaScriptAndGetStringResult( |
| 921 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); | 998 String.format(jsObjectKeysTestTemplate, inspectableObjec
tName))); |
| 922 assertEquals("m1,m2", executeJavaScriptAndGetStringResult( | 999 Assert.assertEquals("m1,m2", |
| 1000 executeJavaScriptAndGetStringResult( |
| 923 String.format(jsForInTestTemplate, inspectableObjectName
))); | 1001 String.format(jsForInTestTemplate, inspectableObjectName
))); |
| 924 | 1002 |
| 925 runTestOnUiThread(new Runnable() { | 1003 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable(
) { |
| 926 @Override | 1004 @Override |
| 927 public void run() { | 1005 public void run() { |
| 928 getContentViewCore().setAllowJavascriptInterfacesInspection(fals
e); | 1006 mActivityTestRule.getContentViewCore().setAllowJavascriptInterfa
cesInspection( |
| 1007 false); |
| 929 } | 1008 } |
| 930 }); | 1009 }); |
| 931 | 1010 |
| 932 injectObjectAndReload(new Test(), nonInspectableObjectName, JavascriptIn
terface.class); | 1011 mActivityTestRule.injectObjectAndReload( |
| 1012 new Test(), nonInspectableObjectName, JavascriptInterface.class)
; |
| 933 | 1013 |
| 934 assertEquals("", executeJavaScriptAndGetStringResult( | 1014 Assert.assertEquals("", |
| 1015 executeJavaScriptAndGetStringResult( |
| 935 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); | 1016 String.format(jsObjectKeysTestTemplate, nonInspectableOb
jectName))); |
| 936 assertEquals("", executeJavaScriptAndGetStringResult( | 1017 Assert.assertEquals("", |
| 1018 executeJavaScriptAndGetStringResult( |
| 937 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); | 1019 String.format(jsForInTestTemplate, nonInspectableObjectN
ame))); |
| 938 } | 1020 } |
| 939 | 1021 |
| 1022 @Test |
| 940 @SmallTest | 1023 @SmallTest |
| 941 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1024 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 942 public void testAccessToObjectGetClassIsBlocked() throws Throwable { | 1025 public void testAccessToObjectGetClassIsBlocked() throws Throwable { |
| 943 injectObjectAndReload(new Object(), "testObject"); | 1026 mActivityTestRule.injectObjectAndReload(new Object(), "testObject"); |
| 944 assertEquals("function", executeJavaScriptAndGetStringResult("typeof tes
tObject.getClass")); | 1027 Assert.assertEquals( |
| 1028 "function", executeJavaScriptAndGetStringResult("typeof testObje
ct.getClass")); |
| 945 assertRaisesException("testObject.getClass()"); | 1029 assertRaisesException("testObject.getClass()"); |
| 946 } | 1030 } |
| 947 | 1031 |
| 1032 @Test |
| 948 @SmallTest | 1033 @SmallTest |
| 949 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1034 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 950 public void testReplaceJavascriptInterface() throws Throwable { | 1035 public void testReplaceJavascriptInterface() throws Throwable { |
| 951 class Test { | 1036 class Test { |
| 952 public Test(int value) { | 1037 public Test(int value) { |
| 953 mValue = value; | 1038 mValue = value; |
| 954 } | 1039 } |
| 955 @JavascriptInterface | 1040 @JavascriptInterface |
| 956 public int getValue() { | 1041 public int getValue() { |
| 957 return mValue; | 1042 return mValue; |
| 958 } | 1043 } |
| 959 private int mValue; | 1044 private int mValue; |
| 960 } | 1045 } |
| 961 injectObjectAndReload(new Test(13), "testObject"); | 1046 mActivityTestRule.injectObjectAndReload(new Test(13), "testObject"); |
| 962 assertEquals("13", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); | 1047 Assert.assertEquals("13", executeJavaScriptAndGetStringResult("testObjec
t.getValue()")); |
| 963 // The documentation doesn't specify, what happens if the embedder is tr
ying | 1048 // The documentation doesn't specify, what happens if the embedder is tr
ying |
| 964 // to inject a different object under the same name. The current impleme
ntation | 1049 // to inject a different object under the same name. The current impleme
ntation |
| 965 // simply replaces the old object with the new one. | 1050 // simply replaces the old object with the new one. |
| 966 injectObjectAndReload(new Test(42), "testObject"); | 1051 mActivityTestRule.injectObjectAndReload(new Test(42), "testObject"); |
| 967 assertEquals("42", executeJavaScriptAndGetStringResult("testObject.getVa
lue()")); | 1052 Assert.assertEquals("42", executeJavaScriptAndGetStringResult("testObjec
t.getValue()")); |
| 968 } | 1053 } |
| 969 | 1054 |
| 1055 @Test |
| 970 @SmallTest | 1056 @SmallTest |
| 971 @Feature({"AndroidWebView", "Android-JavaBridge"}) | 1057 @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| 972 public void testMethodCalledOnAnotherInstance() throws Throwable { | 1058 public void testMethodCalledOnAnotherInstance() throws Throwable { |
| 973 class TestObject { | 1059 class TestObject { |
| 974 private int mIndex; | 1060 private int mIndex; |
| 975 TestObject(int index) { | 1061 TestObject(int index) { |
| 976 mIndex = index; | 1062 mIndex = index; |
| 977 } | 1063 } |
| 978 public void method() { | 1064 public void method() { |
| 979 mTestController.setIntValue(mIndex); | 1065 mTestController.setIntValue(mIndex); |
| 980 } | 1066 } |
| 981 } | 1067 } |
| 982 final TestObject testObject1 = new TestObject(1); | 1068 final TestObject testObject1 = new TestObject(1); |
| 983 final TestObject testObject2 = new TestObject(2); | 1069 final TestObject testObject2 = new TestObject(2); |
| 984 injectObjectsAndReload(testObject1, "testObject1", testObject2, "testObj
ect2", null); | 1070 mActivityTestRule.injectObjectsAndReload( |
| 985 executeJavaScript("testObject1.method()"); | 1071 testObject1, "testObject1", testObject2, "testObject2", null); |
| 986 assertEquals(1, mTestController.waitForIntValue()); | 1072 mActivityTestRule.executeJavaScript("testObject1.method()"); |
| 987 executeJavaScript("testObject2.method()"); | 1073 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 988 assertEquals(2, mTestController.waitForIntValue()); | 1074 mActivityTestRule.executeJavaScript("testObject2.method()"); |
| 989 executeJavaScript("testObject1.method.call(testObject2)"); | 1075 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 990 assertEquals(2, mTestController.waitForIntValue()); | 1076 mActivityTestRule.executeJavaScript("testObject1.method.call(testObject2
)"); |
| 991 executeJavaScript("testObject2.method.call(testObject1)"); | 1077 Assert.assertEquals(2, mTestController.waitForIntValue()); |
| 992 assertEquals(1, mTestController.waitForIntValue()); | 1078 mActivityTestRule.executeJavaScript("testObject2.method.call(testObject1
)"); |
| 1079 Assert.assertEquals(1, mTestController.waitForIntValue()); |
| 993 } | 1080 } |
| 994 } | 1081 } |
| OLD | NEW |