1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
19import android.app.Instrumentation;
20import android.net.http.SslError;
21import android.os.Environment;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.test.ActivityInstrumentationTestCase2;
26import android.util.Log;
27import android.webkit.JsPromptResult;
28import android.webkit.JsResult;
29import android.webkit.SslErrorHandler;
30import android.webkit.WebView;
31
32/**
33 * Adds a JavaScript interface to the webview and calls functions on it to verify variables
34 * are passed from JS to Java correctly.
35 */
36public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<BrowserActivity> {
37
38    private final static String TAG = "JNIBindingsTest";
39
40    private static final int MSG_WEBKIT_DATA_READY = 101;
41
42    private BrowserActivity mActivity = null;
43    private Instrumentation mInst = null;
44
45    private boolean mTestDone = false;
46    private String mWebKitResult;
47
48    private String mExpectedWebKitResult = "Running JNI Bindings test...\n" +
49            "testPrimitiveTypes passed!\n" +
50            "testObjectTypes passed!\n" +
51            "testArray passed!\n" +
52            "testObjectArray passed!\n" +
53            "testObjectMembers passed!\n" +
54            "testJSPrimitivesToStringsInJava passed!\n" +
55            "testJavaReturnTypes passed!\n" +
56            "getIfaceProperties passed!\n" +
57            "testParameterTypeMismatch passed!\n";
58
59
60    private class GetWebKitDataThread extends Thread {
61        private JNIBindingsTestApp mTestApp;
62        private WebView mWebView;
63        private Handler mHandler;
64
65        GetWebKitDataThread(JNIBindingsTestApp testApp, WebView webView) {
66            mTestApp = testApp;
67            mWebView = webView;
68        }
69
70        public void run() {
71            Looper.prepare();
72            mHandler = new Handler() {
73                public void handleMessage(Message msg) {
74                    switch (msg.what) {
75                        case MSG_WEBKIT_DATA_READY: {
76                            mTestApp.setWebKitResult((String)msg.obj);
77                            Looper.myLooper().quit();
78                        }
79                        default: super.handleMessage(msg); break;
80                    }
81                }
82            };
83            mWebView.documentAsText(mHandler.obtainMessage(MSG_WEBKIT_DATA_READY));
84            Looper.loop();
85        }
86    }
87
88    public synchronized void setWebKitResult(String result) {
89       mWebKitResult = result;
90       notify();
91    }
92
93    public JNIBindingsTestApp() {
94        super(BrowserActivity.class);
95    }
96
97    @Override
98    protected void setUp() throws Exception {
99        super.setUp();
100
101        mActivity = getActivity();
102        mInst = getInstrumentation();
103        mInst.waitForIdleSync();
104
105    }
106
107    /**
108     * Gets the browser ready for testing by starting the application
109     * and wrapping the WebView's helper clients.
110     */
111    void setUpBrowser() {
112        Tab tab = mActivity.getTabControl().getCurrentTab();
113        WebView webView = tab.getWebView();
114        webView.addJavascriptInterface(new JNIBindingsTest(this), "JNIBindingsTest");
115
116        webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) {
117
118            /**
119             * Dismisses and logs Javascript alerts.
120             */
121            @Override
122            public boolean onJsAlert(WebView view, String url, String message,
123                    JsResult result) {
124                String logMsg = String.format("JS Alert '%s' received from %s", message, url);
125                Log.w(TAG, logMsg);
126                result.confirm();
127
128                return true;
129            }
130
131            /**
132             * Confirms and logs Javascript alerts.
133             */
134            @Override
135            public boolean onJsConfirm(WebView view, String url, String message,
136                    JsResult result) {
137                String logMsg = String.format("JS Confirmation '%s' received from %s",
138                        message, url);
139                Log.w(TAG, logMsg);
140                result.confirm();
141
142                return true;
143            }
144
145            /**
146             * Confirms and logs Javascript alerts, providing the default value.
147             */
148            @Override
149            public boolean onJsPrompt(WebView view, String url, String message,
150                    String defaultValue, JsPromptResult result) {
151                String logMsg = String.format("JS Prompt '%s' received from %s; " +
152                        "Giving default value '%s'", message, url, defaultValue);
153                Log.w(TAG, logMsg);
154                result.confirm(defaultValue);
155
156                return true;
157            }
158        });
159
160        webView.setWebViewClient(new TestWebViewClient(webView.getWebViewClient()) {
161
162            /**
163             * Bypasses and logs errors.
164             */
165            @Override
166            public void onReceivedError(WebView view, int errorCode,
167                    String description, String failingUrl) {
168                String message = String.format("Error '%s' (%d) loading url: %s",
169                        description, errorCode, failingUrl);
170                Log.w(TAG, message);
171            }
172
173            /**
174             * Ignores and logs SSL errors.
175             */
176            @Override
177            public void onReceivedSslError(WebView view, SslErrorHandler handler,
178                    SslError error) {
179                Log.w(TAG, "SSL error: " + error);
180                handler.proceed();
181            }
182
183        });
184    }
185
186    public synchronized void testComplete() {
187        mTestDone = true;
188        notify();
189    }
190
191    public void testJNIBindings() {
192        setUpBrowser();
193
194        Tab tab = mActivity.getTabControl().getCurrentTab();
195        WebView webView = tab.getWebView();
196        webView.loadUrl("file:///sdcard/bindings_test.html");
197        synchronized(this) {
198            while(!mTestDone) {
199                try {
200                    wait();
201                } catch (InterruptedException e) {}
202            }
203        }
204
205        // Now the tests are complete grab the DOM content and compare to the reference.
206        GetWebKitDataThread getWKData = new GetWebKitDataThread(this, webView);
207        mWebKitResult = null;
208        getWKData.start();
209
210        synchronized(this) {
211            while(mWebKitResult == null) {
212                try {
213                    wait();
214                } catch (InterruptedException e) {}
215            }
216        }
217
218        Log.v(TAG, "WebKit result:");
219        Log.v(TAG, mWebKitResult);
220        assertEquals("Bindings test failed! See logcat for more details!", mExpectedWebKitResult,
221                mWebKitResult);
222    }
223}
224