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 17 package com.android.browser; 18 19 import android.app.Instrumentation; 20 import android.net.http.SslError; 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.test.ActivityInstrumentationTestCase2; 25 import android.util.Log; 26 import android.webkit.ClientCertRequestHandler; 27 import android.webkit.JsPromptResult; 28 import android.webkit.JsResult; 29 import android.webkit.SslErrorHandler; 30 import android.webkit.WebView; 31 32 import java.io.File; 33 import java.io.FileOutputStream; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.OutputStream; 37 38 /** 39 * Adds a JavaScript interface to the webview and calls functions on it to verify variables 40 * are passed from JS to Java correctly. 41 * To run this test, execute: 42 * adb shell am instrument -w -e class com.android.browser.JNIBindingsTestApp#testJNIBindings \ 43 * com.android.browser.tests/android.test.InstrumentationTestRunner 44 */ 45 public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<BrowserActivity> { 46 47 private final static String TAG = "JNIBindingsTest"; 48 49 private static final String SDCARD_BINDINGS_TEST_HTML = "/sdcard/bindings_test.html"; 50 51 private static final int MSG_WEBKIT_DATA_READY = 101; 52 53 private BrowserActivity mActivity = null; 54 private Controller mController = null; 55 private Instrumentation mInst = null; 56 57 private boolean mTestDone = false; 58 private String mWebKitResult; 59 60 private String mExpectedWebKitResult = "Running JNI Bindings test...\n" + 61 "testPrimitiveTypes passed!\n" + 62 "testObjectTypes passed!\n" + 63 "testArray passed!\n" + 64 "testObjectArray passed!\n" + 65 "testObjectMembers passed!\n" + 66 "testJSPrimitivesToStringsInJava passed!\n" + 67 "testJavaReturnTypes passed!\n" + 68 "getIfaceProperties passed!\n" + 69 "testParameterTypeMismatch passed!\n"; 70 71 72 private class GetWebKitDataThread extends Thread { 73 private JNIBindingsTestApp mTestApp; 74 private WebView mWebView; 75 private Handler mHandler; 76 77 GetWebKitDataThread(JNIBindingsTestApp testApp, WebView webView) { 78 mTestApp = testApp; 79 mWebView = webView; 80 } 81 82 @Override 83 public void run() { 84 Looper.prepare(); 85 mHandler = new Handler() { 86 @Override 87 public void handleMessage(Message msg) { 88 switch (msg.what) { 89 case MSG_WEBKIT_DATA_READY: { 90 mTestApp.setWebKitResult((String)msg.obj); 91 Looper.myLooper().quit(); 92 } 93 default: super.handleMessage(msg); break; 94 } 95 } 96 }; 97 mWebView.documentAsText(mHandler.obtainMessage(MSG_WEBKIT_DATA_READY, 1, 0)); 98 Looper.loop(); 99 } 100 } 101 102 public synchronized void setWebKitResult(String result) { 103 mWebKitResult = result; 104 notify(); 105 } 106 107 public JNIBindingsTestApp() { 108 super(BrowserActivity.class); 109 } 110 111 @Override 112 protected void setUp() throws Exception { 113 super.setUp(); 114 115 mActivity = getActivity(); 116 mController = mActivity.getController(); 117 mInst = getInstrumentation(); 118 mInst.waitForIdleSync(); 119 120 extractAsset(); 121 } 122 123 @Override 124 protected void tearDown() throws Exception { 125 removeAsset(); 126 super.tearDown(); 127 } 128 129 protected void extractAsset() throws IOException { 130 InputStream in = getInstrumentation().getContext().getAssets().open("bindings_test.html"); 131 OutputStream out = new FileOutputStream(SDCARD_BINDINGS_TEST_HTML); 132 133 byte[] buf = new byte[2048]; 134 int len; 135 136 while ((len = in.read(buf)) >= 0 ) { 137 out.write(buf, 0, len); 138 } 139 out.close(); 140 in.close(); 141 } 142 143 protected void removeAsset(){ 144 File fileToDelete = new File(SDCARD_BINDINGS_TEST_HTML); 145 fileToDelete.delete(); 146 } 147 148 /** 149 * Gets the browser ready for testing by starting the application 150 * and wrapping the WebView's helper clients. 151 */ 152 void setUpBrowser() { 153 Tab tab = mController.getTabControl().getCurrentTab(); 154 WebView webView = tab.getWebView(); 155 webView.addJavascriptInterface(new JNIBindingsTest(this), "JNIBindingsTest"); 156 157 webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) { 158 159 /** 160 * Dismisses and logs Javascript alerts. 161 */ 162 @Override 163 public boolean onJsAlert(WebView view, String url, String message, 164 JsResult result) { 165 String logMsg = String.format("JS Alert '%s' received from %s", message, url); 166 Log.w(TAG, logMsg); 167 result.confirm(); 168 169 return true; 170 } 171 172 /** 173 * Confirms and logs Javascript alerts. 174 */ 175 @Override 176 public boolean onJsConfirm(WebView view, String url, String message, 177 JsResult result) { 178 String logMsg = String.format("JS Confirmation '%s' received from %s", 179 message, url); 180 Log.w(TAG, logMsg); 181 result.confirm(); 182 183 return true; 184 } 185 186 /** 187 * Confirms and logs Javascript alerts, providing the default value. 188 */ 189 @Override 190 public boolean onJsPrompt(WebView view, String url, String message, 191 String defaultValue, JsPromptResult result) { 192 String logMsg = String.format("JS Prompt '%s' received from %s; " + 193 "Giving default value '%s'", message, url, defaultValue); 194 Log.w(TAG, logMsg); 195 result.confirm(defaultValue); 196 197 return true; 198 } 199 }); 200 201 webView.setWebViewClient(new TestWebViewClient(webView.getWebViewClient()) { 202 203 /** 204 * Bypasses and logs errors. 205 */ 206 @Override 207 public void onReceivedError(WebView view, int errorCode, 208 String description, String failingUrl) { 209 String message = String.format("Error '%s' (%d) loading url: %s", 210 description, errorCode, failingUrl); 211 Log.w(TAG, message); 212 } 213 214 /** 215 * Ignores and logs SSL errors. 216 */ 217 @Override 218 public void onReceivedSslError(WebView view, SslErrorHandler handler, 219 SslError error) { 220 Log.w(TAG, "SSL error: " + error); 221 handler.proceed(); 222 } 223 224 /** 225 * Ignores and logs SSL client certificate requests. 226 */ 227 @Override 228 public void onReceivedClientCertRequest(WebView view, ClientCertRequestHandler handler, 229 String host_and_port) { 230 Log.w(TAG, "SSL client certificate request: " + host_and_port); 231 handler.cancel(); 232 } 233 234 }); 235 } 236 237 public synchronized void notifyComplete() { 238 mTestDone = true; 239 notify(); 240 } 241 242 public void testJNIBindings() { 243 setUpBrowser(); 244 245 Tab tab = mController.getTabControl().getCurrentTab(); 246 WebView webView = tab.getWebView(); 247 webView.loadUrl("file://" + SDCARD_BINDINGS_TEST_HTML); 248 synchronized(this) { 249 while(!mTestDone) { 250 try { 251 wait(); 252 } catch (InterruptedException e) {} 253 } 254 } 255 256 // Now the tests are complete grab the DOM content and compare to the reference. 257 GetWebKitDataThread getWKData = new GetWebKitDataThread(this, webView); 258 mWebKitResult = null; 259 getWKData.start(); 260 261 synchronized(this) { 262 while(mWebKitResult == null) { 263 try { 264 wait(); 265 } catch (InterruptedException e) {} 266 } 267 } 268 269 Log.v(TAG, "WebKit result:"); 270 Log.v(TAG, mWebKitResult); 271 assertEquals("Bindings test failed! See logcat for more details!", mExpectedWebKitResult, 272 mWebKitResult); 273 } 274 } 275