summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/WebViewTests/Android.mk27
-rw-r--r--tests/WebViewTests/AndroidManifest.xml32
-rw-r--r--tests/WebViewTests/res/layout/webview_layout.xml25
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java343
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java650
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java100
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java199
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java117
-rw-r--r--tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java38
9 files changed, 1531 insertions, 0 deletions
diff --git a/tests/WebViewTests/Android.mk b/tests/WebViewTests/Android.mk
new file mode 100644
index 0000000..b118845
--- /dev/null
+++ b/tests/WebViewTests/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := WebViewTests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/WebViewTests/AndroidManifest.xml b/tests/WebViewTests/AndroidManifest.xml
new file mode 100644
index 0000000..8b080c1
--- /dev/null
+++ b/tests/WebViewTests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2011 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.webviewtests">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="WebViewStubActivity" android:label="WebViewStubActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.TEST" />
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.webviewtests"
+ android:label="Tests for android.webkit.WebView" />
+</manifest>
diff --git a/tests/WebViewTests/res/layout/webview_layout.xml b/tests/WebViewTests/res/layout/webview_layout.xml
new file mode 100644
index 0000000..d266d21
--- /dev/null
+++ b/tests/WebViewTests/res/layout/webview_layout.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <WebView android:id="@+id/web_page"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
new file mode 100644
index 0000000..143221d
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Part of the test suite for the WebView's Java Bridge. Tests a number of features including ...
+ * - The type of injected objects
+ * - The type of their methods
+ * - Replacing objects
+ * - Removing objects
+ * - Access control
+ * - Calling methods on returned objects
+ * - Multiply injected objects
+ * - Threading
+ * - Inheritance
+ *
+ * To run this test ...
+ * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeBasicsTest \
+ * com.android.webviewtests/android.test.InstrumentationTestRunner
+ */
+
+package com.android.webviewtests;
+
+public class JavaBridgeBasicsTest extends JavaBridgeTestBase {
+ private class TestController extends Controller {
+ private int mIntValue;
+ private long mLongValue;
+ private String mStringValue;
+
+ public synchronized void setIntValue(int x) {
+ mIntValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setLongValue(long x) {
+ mLongValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setStringValue(String x) {
+ mStringValue = x;
+ notifyResultIsReady();
+ }
+
+ public synchronized int waitForIntValue() {
+ waitForResult();
+ return mIntValue;
+ }
+ public synchronized long waitForLongValue() {
+ waitForResult();
+ return mLongValue;
+ }
+ public synchronized String waitForStringValue() {
+ waitForResult();
+ return mStringValue;
+ }
+ }
+
+ TestController mTestController;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestController = new TestController();
+ setUpWebView(mTestController, "testController");
+ }
+
+ // Note that this requires that we can pass a JavaScript string to Java.
+ protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
+ executeJavaScript("testController.setStringValue(" + script + ");");
+ return mTestController.waitForStringValue();
+ }
+
+ protected void injectObjectAndReload(final Object object, final String name) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().addJavascriptInterface(object, name);
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ }
+
+ public void testTypeOfInjectedObject() throws Throwable {
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
+ }
+
+ public void testAdditionNotReflectedUntilReload() throws Throwable {
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().addJavascriptInterface(new Object(), "testObject");
+ }
+ });
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+ }
+
+ public void testRemovalNotReflectedUntilReload() throws Throwable {
+ injectObjectAndReload(new Object(), "testObject");
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().removeJavascriptInterface("testObject");
+ }
+ });
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
+ }
+
+ public void testRemoveObjectNotAdded() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().removeJavascriptInterface("foo");
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof foo"));
+ }
+
+ public void testTypeOfMethod() throws Throwable {
+ assertEquals("function",
+ executeJavaScriptAndGetStringResult("typeof testController.setStringValue"));
+ }
+
+ public void testPrivateMethodNotExposed() throws Throwable {
+ injectObjectAndReload(new Object() {
+ private void method() {}
+ }, "testObject");
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.method"));
+ }
+
+ public void testReplaceInjectedObject() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public void method() { mTestController.setStringValue("object 1"); }
+ }, "testObject");
+ executeJavaScript("testObject.method()");
+ assertEquals("object 1", mTestController.waitForStringValue());
+
+ injectObjectAndReload(new Object() {
+ public void method() { mTestController.setStringValue("object 2"); }
+ }, "testObject");
+ executeJavaScript("testObject.method()");
+ assertEquals("object 2", mTestController.waitForStringValue());
+ }
+
+ public void testInjectNullObjectIsIgnored() throws Throwable {
+ injectObjectAndReload(null, "testObject");
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
+ }
+
+ public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable {
+ injectObjectAndReload(new Object(), "testObject");
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+ injectObjectAndReload(null, "testObject");
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+ }
+
+ public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public void method() { mTestController.setStringValue("0 args"); }
+ public void method(int x) { mTestController.setStringValue("1 arg"); }
+ public void method(int x, int y) { mTestController.setStringValue("2 args"); }
+ }, "testObject");
+ executeJavaScript("testObject.method()");
+ assertEquals("0 args", mTestController.waitForStringValue());
+ executeJavaScript("testObject.method(42)");
+ assertEquals("1 arg", mTestController.waitForStringValue());
+ executeJavaScript("testObject.method(null)");
+ assertEquals("1 arg", mTestController.waitForStringValue());
+ executeJavaScript("testObject.method(undefined)");
+ assertEquals("1 arg", mTestController.waitForStringValue());
+ executeJavaScript("testObject.method(42, 42)");
+ assertEquals("2 args", mTestController.waitForStringValue());
+ }
+
+ public void testObjectPersistsAcrossPageLoads() throws Throwable {
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
+ }
+
+ public void testSameObjectInjectedMultipleTimes() throws Throwable {
+ class TestObject {
+ private int mNumMethodInvocations;
+ public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
+ }
+ final TestObject testObject = new TestObject();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().addJavascriptInterface(testObject, "testObject1");
+ getWebView().addJavascriptInterface(testObject, "testObject2");
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ executeJavaScript("testObject1.method()");
+ assertEquals(1, mTestController.waitForIntValue());
+ executeJavaScript("testObject2.method()");
+ assertEquals(2, mTestController.waitForIntValue());
+ }
+
+ public void testCallMethodOnReturnedObject() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public Object getInnerObject() {
+ return new Object() {
+ public void method(int x) { mTestController.setIntValue(x); }
+ };
+ }
+ }, "testObject");
+ executeJavaScript("testObject.getInnerObject().method(42)");
+ assertEquals(42, mTestController.waitForIntValue());
+ }
+
+ public void testReturnedObjectInjectedElsewhere() throws Throwable {
+ class InnerObject {
+ private int mNumMethodInvocations;
+ public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
+ }
+ final InnerObject innerObject = new InnerObject();
+ final Object object = new Object() {
+ public InnerObject getInnerObject() {
+ return innerObject;
+ }
+ };
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().addJavascriptInterface(object, "testObject");
+ getWebView().addJavascriptInterface(innerObject, "innerObject");
+ getWebView().reload();
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ executeJavaScript("testObject.getInnerObject().method()");
+ assertEquals(1, mTestController.waitForIntValue());
+ executeJavaScript("innerObject.method()");
+ assertEquals(2, mTestController.waitForIntValue());
+ }
+
+ public void testMethodInvokedOnBackgroundThread() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public void captureThreadId() {
+ mTestController.setLongValue(Thread.currentThread().getId());
+ }
+ }, "testObject");
+ executeJavaScript("testObject.captureThreadId()");
+ final long threadId = mTestController.waitForLongValue();
+ assertFalse(threadId == Thread.currentThread().getId());
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(threadId == Thread.currentThread().getId());
+ }
+ });
+ }
+
+ public void testPublicInheritedMethod() throws Throwable {
+ class Base {
+ public void method(int x) { mTestController.setIntValue(x); }
+ }
+ class Derived extends Base {
+ }
+ injectObjectAndReload(new Derived(), "testObject");
+ assertEquals("function", executeJavaScriptAndGetStringResult("typeof testObject.method"));
+ executeJavaScript("testObject.method(42)");
+ assertEquals(42, mTestController.waitForIntValue());
+ }
+
+ public void testPrivateInheritedMethod() throws Throwable {
+ class Base {
+ private void method() {}
+ }
+ class Derived extends Base {
+ }
+ injectObjectAndReload(new Derived(), "testObject");
+ assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject.method"));
+ }
+
+ public void testOverriddenMethod() throws Throwable {
+ class Base {
+ public void method() { mTestController.setStringValue("base"); }
+ }
+ class Derived extends Base {
+ public void method() { mTestController.setStringValue("derived"); }
+ }
+ injectObjectAndReload(new Derived(), "testObject");
+ executeJavaScript("testObject.method()");
+ assertEquals("derived", mTestController.waitForStringValue());
+ }
+
+ public void testEnumerateMembers() throws Throwable {
+ injectObjectAndReload(new Object() {
+ public void method() {}
+ private void privateMethod() {}
+ public int field;
+ private int privateField;
+ }, "testObject");
+ executeJavaScript(
+ "var result = \"\"; " +
+ "for (x in testObject) { result += \" \" + x } " +
+ "testController.setStringValue(result);");
+ // LIVECONNECT_COMPLIANCE: Should be able to enumerate members.
+ assertEquals("", mTestController.waitForStringValue());
+ }
+}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java
new file mode 100644
index 0000000..34b3432
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Part of the test suite for the WebView's Java Bridge. This class tests that
+ * we correctly convert JavaScript values to Java values when passing them to
+ * the methods of injected Java objects.
+ *
+ * The conversions should follow
+ * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
+ * which the implementation differs from the spec are marked with
+ * LIVECONNECT_COMPLIANCE.
+ * FIXME: Consider making our implementation more compliant, if it will not
+ * break backwards-compatibility. See b/4408210.
+ *
+ * To run this test ...
+ * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeCoercionTest \
+ * com.android.webviewtests/android.test.InstrumentationTestRunner
+ */
+
+package com.android.webviewtests;
+
+public class JavaBridgeCoercionTest extends JavaBridgeTestBase {
+ private class TestObject extends Controller {
+ private Object objectInstance;
+ private CustomType customTypeInstance;
+ private CustomType2 customType2Instance;
+
+ private boolean mBooleanValue;
+ private byte mByteValue;
+ private char mCharValue;
+ private short mShortValue;
+ private int mIntValue;
+ private long mLongValue;
+ private float mFloatValue;
+ private double mDoubleValue;
+ // TODO: Test passing to methods with array parameters.
+ private String mStringValue;
+ private Object mObjectValue;
+ private CustomType mCustomTypeValue;
+
+ public TestObject() {
+ objectInstance = new Object();
+ customTypeInstance = new CustomType();
+ customType2Instance = new CustomType2();
+ }
+
+ public Object getObjectInstance() {
+ return objectInstance;
+ }
+ public CustomType getCustomTypeInstance() {
+ return customTypeInstance;
+ }
+ public CustomType2 getCustomType2Instance() {
+ return customType2Instance;
+ }
+
+ public synchronized void setBooleanValue(boolean x) {
+ mBooleanValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setByteValue(byte x) {
+ mByteValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setCharValue(char x) {
+ mCharValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setShortValue(short x) {
+ mShortValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setIntValue(int x) {
+ mIntValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setLongValue(long x) {
+ mLongValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setFloatValue(float x) {
+ mFloatValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setDoubleValue(double x) {
+ mDoubleValue = x;
+ notifyResultIsReady();
+ }
+ // TODO: Test passing to methods with array parameters.
+ public synchronized void setStringValue(String x) {
+ mStringValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setObjectValue(Object x) {
+ mObjectValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized void setCustomTypeValue(CustomType x) {
+ mCustomTypeValue = x;
+ notifyResultIsReady();
+ }
+
+ public synchronized boolean waitForBooleanValue() {
+ waitForResult();
+ return mBooleanValue;
+ }
+ public synchronized byte waitForByteValue() {
+ waitForResult();
+ return mByteValue;
+ }
+ public synchronized char waitForCharValue() {
+ waitForResult();
+ return mCharValue;
+ }
+ public synchronized short waitForShortValue() {
+ waitForResult();
+ return mShortValue;
+ }
+ public synchronized int waitForIntValue() {
+ waitForResult();
+ return mIntValue;
+ }
+ public synchronized long waitForLongValue() {
+ waitForResult();
+ return mLongValue;
+ }
+ public synchronized float waitForFloatValue() {
+ waitForResult();
+ return mFloatValue;
+ }
+ public synchronized double waitForDoubleValue() {
+ waitForResult();
+ return mDoubleValue;
+ }
+ // TODO: Test passing to methods with array parameters.
+ public synchronized String waitForStringValue() {
+ waitForResult();
+ return mStringValue;
+ }
+ public synchronized Object waitForObjectValue() {
+ waitForResult();
+ return mObjectValue;
+ }
+ public synchronized CustomType waitForCustomTypeValue() {
+ waitForResult();
+ return mCustomTypeValue;
+ }
+ }
+
+ // Two custom types used when testing passing objects.
+ private static class CustomType {
+ }
+ private static class CustomType2 {
+ }
+
+ private TestObject mTestObject;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestObject = new TestObject();
+ setUpWebView(mTestObject, "testObject");
+ }
+
+ // Test passing a JavaScript number in the int32 range to a method of an
+ // injected object.
+ public void testPassNumberInt32() throws Throwable {
+ executeJavaScript("testObject.setByteValue(42);");
+ assertEquals(42, mTestObject.waitForByteValue());
+ executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42);");
+ assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
+ executeJavaScript("testObject.setCharValue(42);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(42);");
+ assertEquals(42, mTestObject.waitForShortValue());
+ executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42);");
+ assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(42);");
+ assertEquals(42, mTestObject.waitForIntValue());
+
+ executeJavaScript("testObject.setLongValue(42);");
+ assertEquals(42, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(42);");
+ assertEquals(42.0f, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(42);");
+ assertEquals(42.0, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
+ executeJavaScript("testObject.setObjectValue(42);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ // The spec allows the JS engine flexibility in how to format the number.
+ executeJavaScript("testObject.setStringValue(42);");
+ String str = mTestObject.waitForStringValue();
+ assertTrue("42".equals(str) || "42.0".equals(str));
+
+ executeJavaScript("testObject.setBooleanValue(0);");
+ assertFalse(mTestObject.waitForBooleanValue());
+ // LIVECONNECT_COMPLIANCE: Should be true;
+ executeJavaScript("testObject.setBooleanValue(42);");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(42);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // Test passing a JavaScript number in the double range to a method of an
+ // injected object.
+ public void testPassNumberDouble() throws Throwable {
+ executeJavaScript("testObject.setByteValue(42.1);");
+ assertEquals(42, mTestObject.waitForByteValue());
+ executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42.1);");
+ assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue());
+ executeJavaScript("testObject.setByteValue(" + Integer.MAX_VALUE + " + 42.1);");
+ assertEquals(-1, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should convert to numeric char value.
+ executeJavaScript("testObject.setCharValue(42.1);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(42.1);");
+ assertEquals(42, mTestObject.waitForShortValue());
+ executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42.1);");
+ assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue());
+ executeJavaScript("testObject.setShortValue(" + Integer.MAX_VALUE + " + 42.1);");
+ assertEquals(-1, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(42.1);");
+ assertEquals(42, mTestObject.waitForIntValue());
+ executeJavaScript("testObject.setIntValue(" + Integer.MAX_VALUE + " + 42.1);");
+ assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
+
+ executeJavaScript("testObject.setLongValue(42.1);");
+ assertEquals(42, mTestObject.waitForLongValue());
+ // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE.
+ executeJavaScript("testObject.setLongValue(" + Long.MAX_VALUE + " + 42.1);");
+ assertEquals(Long.MIN_VALUE, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(42.1);");
+ assertEquals(42.1f, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(42.1);");
+ assertEquals(42.1, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
+ executeJavaScript("testObject.setObjectValue(42.1);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setStringValue(42.1);");
+ assertEquals("42.1", mTestObject.waitForStringValue());
+
+ executeJavaScript("testObject.setBooleanValue(0.0);");
+ assertFalse(mTestObject.waitForBooleanValue());
+ // LIVECONNECT_COMPLIANCE: Should be true.
+ executeJavaScript("testObject.setBooleanValue(42.1);");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(42.1);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // Test passing JavaScript NaN to a method of an injected object.
+ public void testPassNumberNaN() throws Throwable {
+ executeJavaScript("testObject.setByteValue(Number.NaN);");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ executeJavaScript("testObject.setCharValue(Number.NaN);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(Number.NaN);");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(Number.NaN);");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ executeJavaScript("testObject.setLongValue(Number.NaN);");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(Number.NaN);");
+ assertEquals(Float.NaN, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(Number.NaN);");
+ assertEquals(Double.NaN, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
+ executeJavaScript("testObject.setObjectValue(Number.NaN);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setStringValue(Number.NaN);");
+ assertEquals("NaN", mTestObject.waitForStringValue());
+
+ executeJavaScript("testObject.setBooleanValue(Number.NaN);");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(Number.NaN);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // Test passing JavaScript infinity to a method of an injected object.
+ public void testPassNumberInfinity() throws Throwable {
+ executeJavaScript("testObject.setByteValue(Infinity);");
+ assertEquals(-1, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value.
+ executeJavaScript("testObject.setCharValue(Infinity);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(Infinity);");
+ assertEquals(-1, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(Infinity);");
+ assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE.
+ executeJavaScript("testObject.setLongValue(Infinity);");
+ assertEquals(-1, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(Infinity);");
+ assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(Infinity);");
+ assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number.
+ executeJavaScript("testObject.setObjectValue(Infinity);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setStringValue(Infinity);");
+ assertEquals("Inf", mTestObject.waitForStringValue());
+
+ executeJavaScript("testObject.setBooleanValue(Infinity);");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(Infinity);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // Test passing a JavaScript boolean to a method of an injected object.
+ public void testPassBoolean() throws Throwable {
+ executeJavaScript("testObject.setBooleanValue(true);");
+ assertTrue(mTestObject.waitForBooleanValue());
+ executeJavaScript("testObject.setBooleanValue(false);");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Boolean.
+ executeJavaScript("testObject.setObjectValue(true);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setStringValue(false);");
+ assertEquals("false", mTestObject.waitForStringValue());
+ executeJavaScript("testObject.setStringValue(true);");
+ assertEquals("true", mTestObject.waitForStringValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.
+ executeJavaScript("testObject.setByteValue(true);");
+ assertEquals(0, mTestObject.waitForByteValue());
+ executeJavaScript("testObject.setByteValue(false);");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1.
+ executeJavaScript("testObject.setCharValue(true);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+ executeJavaScript("testObject.setCharValue(false);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.
+ executeJavaScript("testObject.setShortValue(true);");
+ assertEquals(0, mTestObject.waitForShortValue());
+ executeJavaScript("testObject.setShortValue(false);");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.
+ executeJavaScript("testObject.setIntValue(true);");
+ assertEquals(0, mTestObject.waitForIntValue());
+ executeJavaScript("testObject.setIntValue(false);");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.
+ executeJavaScript("testObject.setLongValue(true);");
+ assertEquals(0, mTestObject.waitForLongValue());
+ executeJavaScript("testObject.setLongValue(false);");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.0.
+ executeJavaScript("testObject.setFloatValue(true);");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+ executeJavaScript("testObject.setFloatValue(false);");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be 1.0.
+ executeJavaScript("testObject.setDoubleValue(true);");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+ executeJavaScript("testObject.setDoubleValue(false);");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(true);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // Test passing a JavaScript string to a method of an injected object.
+ public void testPassString() throws Throwable {
+ executeJavaScript("testObject.setStringValue(\"+042.10\");");
+ assertEquals("+042.10", mTestObject.waitForStringValue());
+
+ // Make sure that we distinguish between the empty string and NULL.
+ executeJavaScript("testObject.setStringValue(\"\");");
+ assertEquals("", mTestObject.waitForStringValue());
+
+ // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.String.
+ executeJavaScript("testObject.setObjectValue(\"+042.10\");");
+ assertNull(mTestObject.waitForObjectValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setByteValue(\"+042.10\");");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setShortValue(\"+042.10\");");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setIntValue(\"+042.10\");");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setLongValue(\"+042.10\");");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setFloatValue(\"+042.10\");");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type.
+ executeJavaScript("testObject.setDoubleValue(\"+042.10\");");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value.
+ executeJavaScript("testObject.setCharValue(\"+042.10\");");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setBooleanValue(\"+042.10\");");
+ assertFalse(mTestObject.waitForBooleanValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue(\"+042.10\");");
+ assertNull(mTestObject.waitForCustomTypeValue());
+ }
+
+ // TODO: Test passing arrays.
+
+ // Test passing a JavaScript object to a method of an injected object.
+ public void testPassJavaScriptObject() throws Throwable {
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setObjectValue({foo: 42});");
+ assertNull(mTestObject.waitForObjectValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCustomTypeValue({foo: 42});");
+ assertNull(mTestObject.waitForCustomTypeValue());
+
+ // LIVECONNECT_COMPLIANCE: Should call toString() on object.
+ executeJavaScript("testObject.setStringValue({foo: 42});");
+ assertEquals("undefined", mTestObject.waitForStringValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setByteValue({foo: 42});");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCharValue({foo: 42});");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setShortValue({foo: 42});");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setIntValue({foo: 42});");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setLongValue({foo: 42});");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setFloatValue({foo: 42});");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setDoubleValue({foo: 42});");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setBooleanValue({foo: 42});");
+ assertFalse(mTestObject.waitForBooleanValue());
+ }
+
+ // Test passing a Java object to a method of an injected object. Note that
+ // this test requires being able to return objects from the methods of
+ // injected objects. This is tested elsewhere.
+ public void testPassJavaObject() throws Throwable {
+ executeJavaScript("testObject.setObjectValue(testObject.getObjectInstance());");
+ assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue());
+ executeJavaScript("testObject.setObjectValue(testObject.getCustomTypeInstance());");
+ assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setCustomTypeValue(testObject.getObjectInstance());");
+ assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForCustomTypeValue());
+ executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomTypeInstance());");
+ assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForCustomTypeValue());
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception, as the types are unrelated.
+ executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomType2Instance());");
+ assertTrue(mTestObject.getCustomType2Instance() ==
+ (Object)mTestObject.waitForCustomTypeValue());
+
+ // LIVECONNECT_COMPLIANCE: Should call toString() on object.
+ executeJavaScript("testObject.setStringValue(testObject.getObjectInstance());");
+ assertEquals("undefined", mTestObject.waitForStringValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setByteValue(testObject.getObjectInstance());");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setCharValue(testObject.getObjectInstance());");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setShortValue(testObject.getObjectInstance());");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setIntValue(testObject.getObjectInstance());");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setLongValue(testObject.getObjectInstance());");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setFloatValue(testObject.getObjectInstance());");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setDoubleValue(testObject.getObjectInstance());");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception.
+ executeJavaScript("testObject.setBooleanValue(testObject.getObjectInstance());");
+ assertFalse(mTestObject.waitForBooleanValue());
+ }
+
+ // Test passing JavaScript null to a method of an injected object.
+ public void testPassNull() throws Throwable {
+ executeJavaScript("testObject.setObjectValue(null);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setCustomTypeValue(null);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+
+ executeJavaScript("testObject.setStringValue(null);");
+ assertNull(mTestObject.waitForStringValue());
+
+ executeJavaScript("testObject.setByteValue(null);");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ executeJavaScript("testObject.setCharValue(null);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(null);");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(null);");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ executeJavaScript("testObject.setLongValue(null);");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(null);");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(null);");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ executeJavaScript("testObject.setBooleanValue(null);");
+ assertFalse(mTestObject.waitForBooleanValue());
+ }
+
+ // Test passing JavaScript undefined to a method of an injected object.
+ public void testPassUndefined() throws Throwable {
+ executeJavaScript("testObject.setObjectValue(undefined);");
+ assertNull(mTestObject.waitForObjectValue());
+
+ executeJavaScript("testObject.setCustomTypeValue(undefined);");
+ assertNull(mTestObject.waitForCustomTypeValue());
+
+ // LIVECONNECT_COMPLIANCE: Should be NULL.
+ executeJavaScript("testObject.setStringValue(undefined);");
+ assertEquals("undefined", mTestObject.waitForStringValue());
+
+ executeJavaScript("testObject.setByteValue(undefined);");
+ assertEquals(0, mTestObject.waitForByteValue());
+
+ executeJavaScript("testObject.setCharValue(undefined);");
+ assertEquals('\u0000', mTestObject.waitForCharValue());
+
+ executeJavaScript("testObject.setShortValue(undefined);");
+ assertEquals(0, mTestObject.waitForShortValue());
+
+ executeJavaScript("testObject.setIntValue(undefined);");
+ assertEquals(0, mTestObject.waitForIntValue());
+
+ executeJavaScript("testObject.setLongValue(undefined);");
+ assertEquals(0, mTestObject.waitForLongValue());
+
+ executeJavaScript("testObject.setFloatValue(undefined);");
+ assertEquals(0.0f, mTestObject.waitForFloatValue());
+
+ executeJavaScript("testObject.setDoubleValue(undefined);");
+ assertEquals(0.0, mTestObject.waitForDoubleValue());
+
+ executeJavaScript("testObject.setBooleanValue(undefined);");
+ assertFalse(mTestObject.waitForBooleanValue());
+ }
+}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java
new file mode 100644
index 0000000..0ccd175
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Part of the test suite for the WebView's Java Bridge. This test tests the
+ * use of fields.
+ *
+ * To run this test ...
+ * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeFieldsTest \
+ * com.android.webviewtests/android.test.InstrumentationTestRunner
+ */
+
+package com.android.webviewtests;
+
+public class JavaBridgeFieldsTest extends JavaBridgeTestBase {
+ private class TestObject extends Controller {
+ private String mStringValue;
+
+ // These methods are used to control the test.
+ public synchronized void setStringValue(String x) {
+ mStringValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized String waitForStringValue() {
+ waitForResult();
+ return mStringValue;
+ }
+
+ public boolean booleanField = true;
+ public byte byteField = 42;
+ public char charField = '\u002A';
+ public short shortField = 42;
+ public int intField = 42;
+ public long longField = 42L;
+ public float floatField = 42.0f;
+ public double doubleField = 42.0;
+ public String stringField = "foo";
+ public Object objectField = new Object();
+ public CustomType customTypeField = new CustomType();
+ }
+
+ // A custom type used when testing passing objects.
+ private class CustomType {
+ }
+
+ TestObject mTestObject;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestObject = new TestObject();
+ setUpWebView(mTestObject, "testObject");
+ }
+
+ // Note that this requires that we can pass a JavaScript string to Java.
+ protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
+ executeJavaScript("testObject.setStringValue(" + script + ");");
+ return mTestObject.waitForStringValue();
+ }
+
+ // The Java bridge does not provide access to fields.
+ // FIXME: Consider providing support for this. See See b/4408210.
+ public void testFieldTypes() throws Throwable {
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.booleanField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.byteField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.charField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.shortField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.intField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.longField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.floatField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.doubleField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.objectField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.stringField"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.customTypeField"));
+ }
+}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java
new file mode 100644
index 0000000..44d5cc6
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Part of the test suite for the WebView's Java Bridge. This test checks that
+ * we correctly convert Java values to JavaScript values when returning them
+ * from the methods of injected Java objects.
+ *
+ * The conversions should follow
+ * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in
+ * which the implementation differs from the spec are marked with
+ * LIVECONNECT_COMPLIANCE.
+ * FIXME: Consider making our implementation more compliant, if it will not
+ * break backwards-compatibility. See b/4408210.
+ *
+ * To run this test ...
+ * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeReturnValuesTest \
+ * com.android.webviewtests/android.test.InstrumentationTestRunner
+ */
+
+package com.android.webviewtests;
+
+public class JavaBridgeReturnValuesTest extends JavaBridgeTestBase {
+ // An instance of this class is injected into the page to test returning
+ // Java values to JavaScript.
+ private class TestObject extends Controller {
+ private String mStringValue;
+ private boolean mBooleanValue;
+
+ // These four methods are used to control the test.
+ public synchronized void setStringValue(String x) {
+ mStringValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized String waitForStringValue() {
+ waitForResult();
+ return mStringValue;
+ }
+ public synchronized void setBooleanValue(boolean x) {
+ mBooleanValue = x;
+ notifyResultIsReady();
+ }
+ public synchronized boolean waitForBooleanValue() {
+ waitForResult();
+ return mBooleanValue;
+ }
+
+ public boolean getBooleanValue() {
+ return true;
+ }
+ public byte getByteValue() {
+ return 42;
+ }
+ public char getCharValue() {
+ return '\u002A';
+ }
+ public short getShortValue() {
+ return 42;
+ }
+ public int getIntValue() {
+ return 42;
+ }
+ public long getLongValue() {
+ return 42L;
+ }
+ public float getFloatValue() {
+ return 42.1f;
+ }
+ public float getFloatValueNoDecimal() {
+ return 42.0f;
+ }
+ public double getDoubleValue() {
+ return 42.1;
+ }
+ public double getDoubleValueNoDecimal() {
+ return 42.0;
+ }
+ public String getStringValue() {
+ return "foo";
+ }
+ public String getEmptyStringValue() {
+ return "";
+ }
+ public String getNullStringValue() {
+ return null;
+ }
+ public Object getObjectValue() {
+ return new Object();
+ }
+ public Object getNullObjectValue() {
+ return null;
+ }
+ public CustomType getCustomTypeValue() {
+ return new CustomType();
+ }
+ public void getVoidValue() {
+ }
+ }
+
+ // A custom type used when testing passing objects.
+ private class CustomType {
+ }
+
+ TestObject mTestObject;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestObject = new TestObject();
+ setUpWebView(mTestObject, "testObject");
+ }
+
+ // Note that this requires that we can pass a JavaScript string to Java.
+ protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
+ executeJavaScript("testObject.setStringValue(" + script + ");");
+ return mTestObject.waitForStringValue();
+ }
+
+ // Note that this requires that we can pass a JavaScript boolean to Java.
+ private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable {
+ executeJavaScript("testObject.setBooleanValue(" + script + ");");
+ return mTestObject.waitForBooleanValue();
+ }
+
+ public void testMethodReturnTypes() throws Throwable {
+ assertEquals("boolean",
+ executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()"));
+ // char values are returned to JavaScript as numbers.
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()"));
+ assertEquals("number",
+ executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()"));
+ assertEquals("string",
+ executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()"));
+ assertEquals("string",
+ executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()"));
+ // LIVECONNECT_COMPLIANCE: This should have type object.
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()"));
+ assertEquals("object",
+ executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()"));
+ assertEquals("object",
+ executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()"));
+ assertEquals("object",
+ executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()"));
+ assertEquals("undefined",
+ executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()"));
+ }
+
+ public void testMethodReturnValues() throws Throwable {
+ // We do the string comparison in JavaScript, to avoid relying on the
+ // coercion algorithm from JavaScript to Java.
+ assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()"));
+ // char values are returned to JavaScript as numbers.
+ assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult(
+ "Math.abs(42.1 - testObject.getFloatValue()) < 0.001"));
+ assertTrue(executeJavaScriptAndGetBooleanResult(
+ "42.0 === testObject.getFloatValueNoDecimal()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult(
+ "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001"));
+ assertTrue(executeJavaScriptAndGetBooleanResult(
+ "42.0 === testObject.getDoubleValueNoDecimal()"));
+ assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()"));
+ assertEquals("", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()"));
+ assertTrue(executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()"));
+ }
+}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java
new file mode 100644
index 0000000..a9ab3b7
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Common functionality for testing the WebView's Java Bridge.
+ */
+
+package com.android.webviewtests;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import junit.framework.Assert;
+
+public class JavaBridgeTestBase extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
+ protected class TestWebViewClient extends WebViewClient {
+ private boolean mIsPageFinished;
+ @Override
+ public synchronized void onPageFinished(WebView webView, String url) {
+ mIsPageFinished = true;
+ notify();
+ }
+ public synchronized void waitForOnPageFinished() throws RuntimeException {
+ while (!mIsPageFinished) {
+ try {
+ wait(5000);
+ } catch (Exception e) {
+ continue;
+ }
+ if (!mIsPageFinished) {
+ throw new RuntimeException("Timed out waiting for onPageFinished()");
+ }
+ }
+ mIsPageFinished = false;
+ }
+ }
+
+ protected class Controller {
+ private boolean mIsResultReady;
+
+ protected synchronized void notifyResultIsReady() {
+ mIsResultReady = true;
+ notify();
+ }
+ protected synchronized void waitForResult() {
+ while (!mIsResultReady) {
+ try {
+ wait(5000);
+ } catch (Exception e) {
+ continue;
+ }
+ if (!mIsResultReady) {
+ Assert.fail("Wait timed out");
+ }
+ }
+ mIsResultReady = false;
+ }
+ }
+
+ protected TestWebViewClient mWebViewClient;
+
+ public JavaBridgeTestBase() {
+ super(WebViewStubActivity.class);
+ }
+
+ // Sets up the WebView and injects the supplied object. Intended to be called from setUp().
+ protected void setUpWebView(final Object object, final String name) throws Exception {
+ mWebViewClient = new TestWebViewClient();
+ // This starts the activity, so must be called on the test thread.
+ final WebViewStubActivity activity = getActivity();
+ // On the UI thread, load an empty page and wait for it to finish
+ // loading so that the Java object is injected.
+ try {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ WebView webView = activity.getWebView();
+ webView.addJavascriptInterface(object, name);
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.setWebViewClient(mWebViewClient);
+ webView.loadData("<html><head></head><body></body></html>", "text/html", null);
+ }
+ });
+ mWebViewClient.waitForOnPageFinished();
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to set up WebView: " + Log.getStackTraceString(e));
+ }
+ }
+
+ protected void executeJavaScript(final String script) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getWebView().loadUrl("javascript:" + script);
+ }
+ });
+ }
+
+ protected WebView getWebView() {
+ return getActivity().getWebView();
+ }
+}
diff --git a/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java b/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java
new file mode 100644
index 0000000..ccfd3d5
--- /dev/null
+++ b/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.webviewtests;
+
+import com.android.webviewtests.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.webkit.WebView;
+
+public class WebViewStubActivity extends Activity {
+ private WebView mWebView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.webview_layout);
+ mWebView = (WebView) findViewById(R.id.web_page);
+ }
+
+ public WebView getWebView() {
+ return mWebView;
+ }
+}