1f7e26448c3591989840efa65f4f3f93a294b991eSteve Block/*
2f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * Copyright (C) 2011 The Android Open Source Project
3f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *
4f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * Licensed under the Apache License, Version 2.0 (the "License");
5f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * you may not use this file except in compliance with the License.
6f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * You may obtain a copy of the License at
7f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *
8f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *      http://www.apache.org/licenses/LICENSE-2.0
9f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *
10f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * Unless required by applicable law or agreed to in writing, software
11f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * distributed under the License is distributed on an "AS IS" BASIS,
12f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * See the License for the specific language governing permissions and
14f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * limitations under the License.
15f7e26448c3591989840efa65f4f3f93a294b991eSteve Block */
16f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
17f7e26448c3591989840efa65f4f3f93a294b991eSteve Block/**
18f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * Part of the test suite for the WebView's Java Bridge. Tests a number of features including ...
19f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - The type of injected objects
20f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - The type of their methods
21f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Replacing objects
22f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Removing objects
23f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Access control
24f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Calling methods on returned objects
25f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Multiply injected objects
26f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Threading
27f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * - Inheritance
28f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *
29f7e26448c3591989840efa65f4f3f93a294b991eSteve Block * To run this test ...
30f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *  adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeBasicsTest \
31f7e26448c3591989840efa65f4f3f93a294b991eSteve Block *     com.android.webviewtests/android.test.InstrumentationTestRunner
32f7e26448c3591989840efa65f4f3f93a294b991eSteve Block */
33f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
34f7e26448c3591989840efa65f4f3f93a294b991eSteve Blockpackage com.android.webviewtests;
35f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
36f7e26448c3591989840efa65f4f3f93a294b991eSteve Blockpublic class JavaBridgeBasicsTest extends JavaBridgeTestBase {
37f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    private class TestController extends Controller {
38f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        private int mIntValue;
39f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        private long mLongValue;
40f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        private String mStringValue;
418e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block        private boolean mBooleanValue;
42f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
43f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized void setIntValue(int x) {
44f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            mIntValue = x;
45f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            notifyResultIsReady();
46f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
47f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized void setLongValue(long x) {
48f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            mLongValue = x;
49f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            notifyResultIsReady();
50f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
51f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized void setStringValue(String x) {
52f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            mStringValue = x;
53f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            notifyResultIsReady();
54f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
558e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block        public synchronized void setBooleanValue(boolean x) {
568e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block            mBooleanValue = x;
578e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block            notifyResultIsReady();
588e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block        }
59f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
60f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized int waitForIntValue() {
61f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            waitForResult();
62f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            return mIntValue;
63f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
64f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized long waitForLongValue() {
65f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            waitForResult();
66f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            return mLongValue;
67f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
68f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        public synchronized String waitForStringValue() {
69f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            waitForResult();
70f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            return mStringValue;
71f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
728e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block        public synchronized boolean waitForBooleanValue() {
738e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block            waitForResult();
748e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block            return mBooleanValue;
758e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block        }
76f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
77f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
7813ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    private static class ObjectWithStaticMethod {
7913ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        public static String staticMethod() {
8013ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block            return "foo";
8113ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        }
8213ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
8313ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
84f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    TestController mTestController;
85f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
86f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    @Override
87f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    protected void setUp() throws Exception {
88f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        super.setUp();
89f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mTestController = new TestController();
90f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        setUpWebView(mTestController, "testController");
91f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
92f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
93f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    // Note that this requires that we can pass a JavaScript string to Java.
94f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
95f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testController.setStringValue(" + script + ");");
96f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        return mTestController.waitForStringValue();
97f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
98f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
99f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    protected void injectObjectAndReload(final Object object, final String name) throws Throwable {
100f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
101f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
102f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
103f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(object, name);
104f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
105f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
106f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
107f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
108f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
109f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
11013ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    // Note that this requires that we can pass a JavaScript boolean to Java.
11113ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    private void assertRaisesException(String script) throws Throwable {
11213ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        executeJavaScript("try {" +
11313ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block                          script + ";" +
11413ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block                          "  testController.setBooleanValue(false);" +
11513ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block                          "} catch (exception) {" +
11613ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block                          "  testController.setBooleanValue(true);" +
11713ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block                          "}");
11813ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertTrue(mTestController.waitForBooleanValue());
11913ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
12013ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
121f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testTypeOfInjectedObject() throws Throwable {
122f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
123f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
124f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
125f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testAdditionNotReflectedUntilReload() throws Throwable {
126f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
127f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
128f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
129f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
130f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(new Object(), "testObject");
131f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
132f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
133f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
134f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
135f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
136f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
137f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
138f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
139f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
140f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
141f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
142f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
143f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
144f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testRemovalNotReflectedUntilReload() throws Throwable {
145f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object(), "testObject");
146f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
147f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
148f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
149f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
150f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().removeJavascriptInterface("testObject");
151f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
152f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
153f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
154f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
155f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
156f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
157f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
158f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
159f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
160f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
161f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
162f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
163f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
164f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testRemoveObjectNotAdded() throws Throwable {
165f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
166f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
167f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
168f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().removeJavascriptInterface("foo");
169f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
170f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
171f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
172f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
173f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof foo"));
174f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
175f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
176f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testTypeOfMethod() throws Throwable {
177f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("function",
178f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                executeJavaScriptAndGetStringResult("typeof testController.setStringValue"));
179f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
180f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
18113ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    public void testTypeOfInvalidMethod() throws Throwable {
18213ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testController.foo"));
18313ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
18413ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
18513ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    public void testCallingInvalidMethodRaisesException() throws Throwable {
18613ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertRaisesException("testController.foo()");
18713ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
18813ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
189d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    public void testUncaughtJavaExceptionRaisesJavaException() throws Throwable {
190d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        injectObjectAndReload(new Object() {
191d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block            public void method() { throw new RuntimeException("foo"); }
192d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        }, "testObject");
193d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        assertRaisesException("testObject.method()");
194d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    }
195d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block
19613ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    // Note that this requires that we can pass a JavaScript string to Java.
19713ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    public void testTypeOfStaticMethod() throws Throwable {
19813ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        injectObjectAndReload(new ObjectWithStaticMethod(), "testObject");
19913ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        executeJavaScript("testController.setStringValue(typeof testObject.staticMethod)");
20013ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertEquals("function", mTestController.waitForStringValue());
20113ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
20213ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
20313ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    // Note that this requires that we can pass a JavaScript string to Java.
20413ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    public void testCallStaticMethod() throws Throwable {
20513ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        injectObjectAndReload(new ObjectWithStaticMethod(), "testObject");
20613ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        executeJavaScript("testController.setStringValue(testObject.staticMethod())");
20713ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertEquals("foo", mTestController.waitForStringValue());
20813ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block    }
20913ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block
210f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testPrivateMethodNotExposed() throws Throwable {
211f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
212f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private void method() {}
213f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
214f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined",
215f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                executeJavaScriptAndGetStringResult("typeof testObject.method"));
216f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
217f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
218f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testReplaceInjectedObject() throws Throwable {
219f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
220f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setStringValue("object 1"); }
221f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
222f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method()");
223f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object 1", mTestController.waitForStringValue());
224f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
225f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
226f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setStringValue("object 2"); }
227f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
228f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method()");
229f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object 2", mTestController.waitForStringValue());
230f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
231f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
232f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testInjectNullObjectIsIgnored() throws Throwable {
233f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(null, "testObject");
234f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
235f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
236f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
237f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable {
238f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object(), "testObject");
239f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
240f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(null, "testObject");
241f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
242f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
243f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
244f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable {
245f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
246f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setStringValue("0 args"); }
247f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method(int x) { mTestController.setStringValue("1 arg"); }
248f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method(int x, int y) { mTestController.setStringValue("2 args"); }
249f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
250f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method()");
251f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("0 args", mTestController.waitForStringValue());
252f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method(42)");
253f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("1 arg", mTestController.waitForStringValue());
254f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method(null)");
255f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("1 arg", mTestController.waitForStringValue());
256f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method(undefined)");
257f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("1 arg", mTestController.waitForStringValue());
258f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method(42, 42)");
259f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("2 args", mTestController.waitForStringValue());
260f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
261f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
2628e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block    public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws Throwable {
26313ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertRaisesException("testController.setIntValue()");
26413ad467a91ac6d86a959b49f0168a0e6893aef2cSteve Block        assertRaisesException("testController.setIntValue(42, 42)");
2658e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block    }
2668e33fe944f9e407e1ba0c40736747c707c40acc7Steve Block
267f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testObjectPersistsAcrossPageLoads() throws Throwable {
268f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
269f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
270f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
271f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
272f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
273f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
274f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
275f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
276f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController"));
277f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
278f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
279f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testSameObjectInjectedMultipleTimes() throws Throwable {
280f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class TestObject {
281f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private int mNumMethodInvocations;
282f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
283f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
284f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        final TestObject testObject = new TestObject();
285f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
286f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
287f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
288f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(testObject, "testObject1");
289f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(testObject, "testObject2");
290f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
291f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
292f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
293f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
294f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject1.method()");
295f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(1, mTestController.waitForIntValue());
296f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject2.method()");
297f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(2, mTestController.waitForIntValue());
298f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
299f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
300f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testCallMethodOnReturnedObject() throws Throwable {
301f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
302f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public Object getInnerObject() {
303f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                return new Object() {
304f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                    public void method(int x) { mTestController.setIntValue(x); }
305f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                };
306f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
307f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
308f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.getInnerObject().method(42)");
309f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(42, mTestController.waitForIntValue());
310f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
311f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
312f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testReturnedObjectInjectedElsewhere() throws Throwable {
313f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class InnerObject {
314f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private int mNumMethodInvocations;
315f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setIntValue(++mNumMethodInvocations); }
316f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
317f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        final InnerObject innerObject = new InnerObject();
318f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        final Object object = new Object() {
319f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public InnerObject getInnerObject() {
320f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                return innerObject;
321f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
322f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        };
323f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
324f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
325f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
326f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(object, "testObject");
327f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().addJavascriptInterface(innerObject, "innerObject");
328f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                getWebView().reload();
329f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
330f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
331f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        mWebViewClient.waitForOnPageFinished();
332f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.getInnerObject().method()");
333f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(1, mTestController.waitForIntValue());
334f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("innerObject.method()");
335f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(2, mTestController.waitForIntValue());
336f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
337f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
338f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testMethodInvokedOnBackgroundThread() throws Throwable {
339f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
340f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void captureThreadId() {
341f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                mTestController.setLongValue(Thread.currentThread().getId());
342f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
343f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
344f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.captureThreadId()");
345f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        final long threadId = mTestController.waitForLongValue();
346f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertFalse(threadId == Thread.currentThread().getId());
347f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        runTestOnUiThread(new Runnable() {
348f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            @Override
349f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void run() {
350f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                assertFalse(threadId == Thread.currentThread().getId());
351f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            }
352f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        });
353f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
354f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
355f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testPublicInheritedMethod() throws Throwable {
356f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Base {
357f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method(int x) { mTestController.setIntValue(x); }
358f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
359f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Derived extends Base {
360f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
361f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Derived(), "testObject");
362f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("function", executeJavaScriptAndGetStringResult("typeof testObject.method"));
363f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method(42)");
364f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals(42, mTestController.waitForIntValue());
365f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
366f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
367f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testPrivateInheritedMethod() throws Throwable {
368f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Base {
369f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private void method() {}
370f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
371f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Derived extends Base {
372f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
373f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Derived(), "testObject");
374f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject.method"));
375f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
376f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
377f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testOverriddenMethod() throws Throwable {
378f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Base {
379f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setStringValue("base"); }
380f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
381f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        class Derived extends Base {
382f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() { mTestController.setStringValue("derived"); }
383f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }
384f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Derived(), "testObject");
385f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript("testObject.method()");
386f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("derived", mTestController.waitForStringValue());
387f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
388f7e26448c3591989840efa65f4f3f93a294b991eSteve Block
389f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    public void testEnumerateMembers() throws Throwable {
390f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        injectObjectAndReload(new Object() {
391f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public void method() {}
392f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private void privateMethod() {}
393f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            public int field;
394f7e26448c3591989840efa65f4f3f93a294b991eSteve Block            private int privateField;
395f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        }, "testObject");
396f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        executeJavaScript(
397f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                "var result = \"\"; " +
398f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                "for (x in testObject) { result += \" \" + x } " +
399f7e26448c3591989840efa65f4f3f93a294b991eSteve Block                "testController.setStringValue(result);");
400f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        // LIVECONNECT_COMPLIANCE: Should be able to enumerate members.
401f7e26448c3591989840efa65f4f3f93a294b991eSteve Block        assertEquals("", mTestController.waitForStringValue());
402f7e26448c3591989840efa65f4f3f93a294b991eSteve Block    }
4033aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block
4043aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block    public void testReflectPublicMethod() throws Throwable {
4053aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        injectObjectAndReload(new Object() {
4063aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block            public String method() { return "foo"; }
4073aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        }, "testObject");
4083aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        assertEquals("foo", executeJavaScriptAndGetStringResult(
4093aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block                "testObject.getClass().getMethod('method', null).invoke(testObject, null)" +
4103aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block                ".toString()"));
4113aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block    }
4123aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block
4133aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block    public void testReflectPublicField() throws Throwable {
4143aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        injectObjectAndReload(new Object() {
4153aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block            public String field = "foo";
4163aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        }, "testObject");
4173aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block        assertEquals("foo", executeJavaScriptAndGetStringResult(
4183aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block                "testObject.getClass().getField('field').get(testObject).toString()"));
4193aa800b9f93a99d6f25623ed24ab5f6fec213c15Steve Block    }
420d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block
421d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    public void testReflectPrivateMethodRaisesException() throws Throwable {
422d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        injectObjectAndReload(new Object() {
423d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block            private void method() {};
424d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        }, "testObject");
425d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        assertRaisesException("testObject.getClass().getMethod('method', null)");
426d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        // getDeclaredMethod() is able to access a private method, but invoke()
427d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        // throws a Java exception.
428d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        assertRaisesException(
429d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block                "testObject.getClass().getDeclaredMethod('method', null).invoke(testObject, null)");
430d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    }
431d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block
432d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    public void testReflectPrivateFieldRaisesException() throws Throwable {
433d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        injectObjectAndReload(new Object() {
434d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block            private int field;
435d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        }, "testObject");
436d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        assertRaisesException("testObject.getClass().getField('field')");
437d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        // getDeclaredField() is able to access a private field, but getInt()
438d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        // throws a Java exception.
439d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block        assertRaisesException(
440d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block                "testObject.getClass().getDeclaredField('field').getInt(testObject)");
441d890b0ddb607bbff5e809653f065b5e0cf480a6fSteve Block    }
442f7e26448c3591989840efa65f4f3f93a294b991eSteve Block}
443