From 4950b2b6951bbdc2b0023130bfbaca2a4044044f Mon Sep 17 00:00:00 2001 From: Andrei Popescu Date: Thu, 3 Sep 2009 13:56:07 +0100 Subject: [PATCH] Fix appcache layout test that was timing out due to race condition in WebView::addJavascriptInterface. --- core/java/android/webkit/BrowserFrame.java | 8 ++++++-- core/java/android/webkit/WebView.java | 20 ++++++++++++++++++- core/java/android/webkit/WebViewCore.java | 12 ++++++++--- .../dumprendertree/TestShellActivity.java | 19 ++++++++++++++---- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index 599c6b06ed5c0..e96ba119e6db9 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -31,6 +31,7 @@ import junit.framework.Assert; import java.net.URLEncoder; import java.util.HashMap; +import java.util.Map; import java.util.Iterator; class BrowserFrame extends Handler { @@ -59,7 +60,7 @@ class BrowserFrame extends Handler { private boolean mIsMainFrame; // Attached Javascript interfaces - private HashMap mJSInterfaceMap; + private Map mJSInterfaceMap; // message ids // a message posted when a frame loading is completed @@ -98,7 +99,7 @@ class BrowserFrame extends Handler { * XXX: Called by WebCore thread. */ public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy, - WebSettings settings) { + WebSettings settings, Map javascriptInterfaces) { // Create a global JWebCoreJavaBridge to handle timers and // cookies in the WebCore thread. if (sJavaBridge == null) { @@ -112,6 +113,7 @@ class BrowserFrame extends Handler { // create PluginManager with current Context PluginManager.getInstance(context); } + mJSInterfaceMap = javascriptInterfaces; mSettings = settings; mContext = context; @@ -453,6 +455,8 @@ class BrowserFrame extends Handler { mJSInterfaceMap.remove(interfaceName); } mJSInterfaceMap.put(interfaceName, obj); + nativeAddJavascriptInterface(0, mJSInterfaceMap.get(interfaceName), + interfaceName); } /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 611681fc04b59..cbf9fd5ecbfd1 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -81,6 +81,7 @@ import java.io.IOException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** *

A View that displays web pages. This class is the basis upon which you @@ -721,11 +722,28 @@ public class WebView extends AbsoluteLayout * @param defStyle The default style resource ID. */ public WebView(Context context, AttributeSet attrs, int defStyle) { + this(context, attrs, defStyle, null); + } + + /** + * Construct a new WebView with layout parameters, a default style and a set + * of custom Javscript interfaces to be added to the WebView at initialization + * time. This guraratees that these interfaces will be available when the JS + * context is initialized. + * @param context A Context object used to access application assets. + * @param attrs An AttributeSet passed to our parent. + * @param defStyle The default style resource ID. + * @param javascriptInterfaces is a Map of intareface names, as keys, and + * object implementing those interfaces, as values. + * @hide pending API council approval. + */ + protected WebView(Context context, AttributeSet attrs, int defStyle, + Map javascriptInterfaces) { super(context, attrs, defStyle); init(); mCallbackProxy = new CallbackProxy(context, this); - mWebViewCore = new WebViewCore(context, this, mCallbackProxy); + mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javascriptInterfaces); mDatabase = WebViewDatabase.getInstance(context); mScroller = new Scroller(context); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 081250b1cd67c..2ff28242798b5 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -36,6 +36,8 @@ import android.view.SurfaceHolder; import android.view.SurfaceView; import java.util.ArrayList; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import junit.framework.Assert; @@ -67,7 +69,8 @@ final class WebViewCore { private int mNativeClass; // The BrowserFrame is an interface to the native Frame component. private BrowserFrame mBrowserFrame; - + // Custom JS interfaces to add during the initialization. + private Map mJavascriptInterfaces; /* * range is from 200 to 10,000. 0 is a special value means device-width. -1 * means undefined. @@ -113,10 +116,12 @@ final class WebViewCore { // debugging other classes that require operation within the WebCore thread. /* package */ static final String THREAD_NAME = "WebViewCoreThread"; - public WebViewCore(Context context, WebView w, CallbackProxy proxy) { + public WebViewCore(Context context, WebView w, CallbackProxy proxy, + Map javascriptInterfaces) { // No need to assign this in the WebCore thread. mCallbackProxy = proxy; mWebView = w; + mJavascriptInterfaces = javascriptInterfaces; // This context object is used to initialize the WebViewCore during // subwindow creation. mContext = context; @@ -164,7 +169,8 @@ final class WebViewCore { * in turn creates a C level FrameView and attaches it to the frame. */ mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy, - mSettings); + mSettings, mJavascriptInterfaces); + mJavascriptInterfaces = null; // Sync the native settings and also create the WebCore thread handler. mSettings.syncSettingsAndCreateHandler(mBrowserFrame); // Create the handler and transfer messages for the IconDatabase diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index e342efb4a37df..663df83a5eb74 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -18,6 +18,7 @@ package com.android.dumprendertree; import android.app.Activity; import android.app.AlertDialog; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnClickListener; @@ -47,6 +48,8 @@ import java.io.FileReader; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.HashMap; +import java.util.Map; import java.util.Vector; public class TestShellActivity extends Activity implements LayoutTestController { @@ -107,6 +110,8 @@ public class TestShellActivity extends Activity implements LayoutTestController mEventSender = new WebViewEventSender(mWebView); mCallbackProxy = new CallbackProxy(mEventSender, this); + mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController"); + mWebView.addJavascriptInterface(mCallbackProxy, "eventSender"); setupWebViewForLayoutTests(mWebView, mCallbackProxy); contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f)); @@ -620,7 +625,10 @@ public class TestShellActivity extends Activity implements LayoutTestController // allow it's content to execute and be recorded by the test // runner. - WebView newWindowView = new WebView(TestShellActivity.this); + HashMap jsIfaces = new HashMap(); + jsIfaces.put("layoutTestController", mCallbackProxy); + jsIfaces.put("eventSender", mCallbackProxy); + WebView newWindowView = new NewWindowWebView(TestShellActivity.this, jsIfaces); setupWebViewForLayoutTests(newWindowView, mCallbackProxy); WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; @@ -630,6 +638,12 @@ public class TestShellActivity extends Activity implements LayoutTestController } }; + private static class NewWindowWebView extends WebView { + public NewWindowWebView(Context context, Map jsIfaces) { + super(context, null, 0, jsIfaces); + } + } + private void resetTestStatus() { mWaitUntilDone = false; mDumpDataType = mDefaultDumpDataType; @@ -659,9 +673,6 @@ public class TestShellActivity extends Activity implements LayoutTestController settings.setDomStorageEnabled(true); settings.setWorkersEnabled(false); - webview.addJavascriptInterface(callbackProxy, "layoutTestController"); - webview.addJavascriptInterface(callbackProxy, "eventSender"); - webview.setWebChromeClient(mChromeClient); webview.setWebViewClient(mViewClient); }