summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Kosiba <mkosiba@google.com>2014-10-07 13:11:51 +0100
committerMarcin Kosiba <mkosiba@google.com>2014-11-24 09:58:34 +0000
commita88fd788aa418e3f7ecf2b937517448f218a27de (patch)
treee559a2284d07123fa52f091f8336d85993d6e951
parentca22ae4017e46f1abee044d2657c1697f28e2b95 (diff)
downloadwebview-a88fd788aa418e3f7ecf2b937517448f218a27de.tar.gz
Wrap all of the WebView Contexts
We're missing a few places in WebViewChromium and WebViewChromium where we should be wrapping the application context. Particularly we need to override getApplicationContext on ContextWrapper to return a wrapped version. Change-Id: I5ce6db1ebea6c5fc545b159a49115dad7c88a624
-rw-r--r--chromium/java/com/android/webview/chromium/ResourcesContextWrapperFactory.java106
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewChromium.java57
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java11
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java28
4 files changed, 143 insertions, 59 deletions
diff --git a/chromium/java/com/android/webview/chromium/ResourcesContextWrapperFactory.java b/chromium/java/com/android/webview/chromium/ResourcesContextWrapperFactory.java
new file mode 100644
index 0000000..da4174f
--- /dev/null
+++ b/chromium/java/com/android/webview/chromium/ResourcesContextWrapperFactory.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2014 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.webview.chromium;
+
+import android.content.ComponentCallbacks;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+
+import java.util.WeakHashMap;
+
+/**
+ * This class allows us to wrap the application context so that the WebView implementation can
+ * correctly reference both org.chromium.* and application classes which is necessary to properly
+ * inflate UI. We keep a weak map from contexts to wrapped contexts to avoid constantly re-wrapping
+ * or doubly wrapping contexts.
+ */
+public class ResourcesContextWrapperFactory {
+ private static WeakHashMap<Context,ContextWrapper> sCtxToWrapper
+ = new WeakHashMap<Context,ContextWrapper>();
+ private static final Object sLock = new Object();
+
+ private ResourcesContextWrapperFactory() {
+ }
+
+ public static Context get(Context ctx) {
+ ContextWrapper wrappedCtx;
+ synchronized (sLock) {
+ wrappedCtx = sCtxToWrapper.get(ctx);
+ if (wrappedCtx == null) {
+ wrappedCtx = createWrapper(ctx);
+ sCtxToWrapper.put(ctx, wrappedCtx);
+ }
+ }
+ return wrappedCtx;
+ }
+
+ private static ContextWrapper createWrapper(final Context ctx) {
+ return new ContextWrapper(ctx) {
+ private Context applicationContext;
+
+ @Override
+ public ClassLoader getClassLoader() {
+ final ClassLoader appCl = getBaseContext().getClassLoader();
+ final ClassLoader webViewCl = this.getClass().getClassLoader();
+ return new ClassLoader() {
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ // First look in the WebViewProvider class loader.
+ try {
+ return webViewCl.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ // Look in the app class loader; allowing it to throw ClassNotFoundException.
+ return appCl.loadClass(name);
+ }
+ }
+ };
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
+ LayoutInflater i = (LayoutInflater) getBaseContext().getSystemService(name);
+ return i.cloneInContext(this);
+ } else {
+ return getBaseContext().getSystemService(name);
+ }
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ if (applicationContext == null)
+ applicationContext = get(ctx.getApplicationContext());
+ return applicationContext;
+ }
+
+ @Override
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ // We have to override registerComponentCallbacks and unregisterComponentCallbacks
+ // since they call getApplicationContext().[un]registerComponentCallbacks()
+ // which causes us to go into a loop.
+ ctx.registerComponentCallbacks(callback);
+ }
+
+ @Override
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ ctx.unregisterComponentCallbacks(callback);
+ }
+ };
+ }
+}
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromium.java b/chromium/java/com/android/webview/chromium/WebViewChromium.java
index 6e857db..ca82bb7 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromium.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromium.java
@@ -17,10 +17,8 @@
package com.android.webview.chromium;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -39,7 +37,6 @@ import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
@@ -138,6 +135,8 @@ class WebViewChromium implements WebViewProvider,
WebView.PrivateAccess mWebViewPrivate;
// The client adapter class.
private WebViewContentsClientAdapter mContentsClientAdapter;
+ // The wrapped Context.
+ private Context mContext;
// Variables for functionality provided by this adapter ---------------------------------------
private ContentSettingsAdapter mWebSettings;
@@ -164,7 +163,8 @@ class WebViewChromium implements WebViewProvider,
mWebView = webView;
mWebViewPrivate = webViewPrivate;
mHitTestResult = new WebView.HitTestResult();
- mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion;
+ mContext = ResourcesContextWrapperFactory.get(mWebView.getContext());
+ mAppTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
mFactory = factory;
mRunQueue = new WebViewChromiumRunQueue();
factory.getWebViewDelegate().addWebViewAssetPath(mWebView.getContext());
@@ -219,8 +219,8 @@ class WebViewChromium implements WebViewProvider,
throw new IllegalArgumentException(msg);
} else {
Log.w(TAG, msg);
- TextView warningLabel = new TextView(mWebView.getContext());
- warningLabel.setText(mWebView.getContext().getString(
+ TextView warningLabel = new TextView(mContext);
+ warningLabel.setText(mContext.getString(
R.string.webviewchromium_private_browsing_warning));
mWebView.addView(warningLabel);
}
@@ -245,9 +245,9 @@ class WebViewChromium implements WebViewProvider,
mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT;
mContentsClientAdapter = new WebViewContentsClientAdapter(
- mWebView, mFactory.getWebViewDelegate());
+ mWebView, mContext, mFactory.getWebViewDelegate());
mWebSettings = new ContentSettingsAdapter(new AwSettings(
- mWebView.getContext(), isAccessFromFileURLsGrantedByDefault,
+ mContext, isAccessFromFileURLsGrantedByDefault,
areLegacyQuirksEnabled));
if (mAppTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
@@ -272,43 +272,8 @@ class WebViewChromium implements WebViewProvider,
});
}
- // Wrap Context so that we can use resources from the webview resource apk.
- private static Context resourcesContextWrapper(final Context ctx) {
- return new ContextWrapper(ctx) {
- @Override
- public ClassLoader getClassLoader() {
- final ClassLoader appCl = getBaseContext().getClassLoader();
- final ClassLoader webViewCl = this.getClass().getClassLoader();
- return new ClassLoader() {
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- // First look in the WebViewProvider class loader.
- try {
- return webViewCl.loadClass(name);
- } catch (ClassNotFoundException e) {
- // Look in the app class loader; allowing it to throw ClassNotFoundException.
- return appCl.loadClass(name);
- }
- }
- };
- }
-
- @Override
- public Object getSystemService(String name) {
- if (name.equals(Context.LAYOUT_INFLATER_SERVICE)) {
- LayoutInflater i = (LayoutInflater) getBaseContext().getSystemService(name);
- return i.cloneInContext(this);
- } else {
- return getBaseContext().getSystemService(name);
- }
- }
-
- };
- }
-
private void initForReal() {
- Context ctx = resourcesContextWrapper(mWebView.getContext());
- mAwContents = new AwContents(mFactory.getBrowserContext(), mWebView, ctx,
+ mAwContents = new AwContents(mFactory.getBrowserContext(), mWebView, mContext,
new InternalAccessAdapter(), new WebViewNativeGLDelegate(),
mContentsClientAdapter, mWebSettings.getAwSettings());
@@ -1261,7 +1226,7 @@ class WebViewChromium implements WebViewProvider,
return false;
}
- FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext());
+ FindActionModeCallback findAction = new FindActionModeCallback(mContext);
if (findAction == null) {
return false;
}
@@ -1453,7 +1418,7 @@ class WebViewChromium implements WebViewProvider,
// This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed
// to stop very out-dated applications from crashing.
Log.w(TAG, "WebView doesn't support getZoomControls");
- return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null;
+ return mAwContents.getSettings().supportZoom() ? new View(mContext) : null;
}
@Override
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index dc48b6e..5111105 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -256,9 +256,10 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
"/system/framework/webview/paks");
// Make sure that ResourceProvider is initialized before starting the browser process.
- setUpResources(mWebViewDelegate.getApplication());
+ Context context = getWrappedCurrentApplicationContext();
+ setUpResources(context);
initPlatSupportLibrary();
- AwBrowserProcess.start(mWebViewDelegate.getApplication());
+ AwBrowserProcess.start(context);
if (isBuildDebuggable()) {
setWebContentsDebuggingEnabled(true);
@@ -295,6 +296,10 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
}
}
+ private Context getWrappedCurrentApplicationContext() {
+ return ResourcesContextWrapperFactory.get(mWebViewDelegate.getApplication());
+ }
+
AwBrowserContext getBrowserContext() {
synchronized (mLock) {
return getBrowserContextLocked();
@@ -426,7 +431,7 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
// will bring up just the parts it needs to make this work on a temporary
// basis until Chromium is started for real. The temporary cookie manager
// needs the application context to have been set.
- ContentMain.initApplicationContext(mWebViewDelegate.getApplication());
+ ContentMain.initApplicationContext(getWrappedCurrentApplicationContext());
}
mCookieManager = new CookieManagerAdapter(new AwCookieManager());
}
diff --git a/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java b/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
index f3351c5..a08c457 100644
--- a/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
+++ b/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
@@ -99,6 +99,8 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
private static final boolean TRACE = false;
// The WebView instance that this adapter is serving.
private final WebView mWebView;
+ // The Context to use. This is different from mWebView.getContext(), which should not be used.
+ private final Context mContext;
// The WebViewClient instance that was passed to WebView.setWebViewClient().
private WebViewClient mWebViewClient;
// The WebChromeClient instance that was passed to WebView.setContentViewClient().
@@ -123,11 +125,17 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
*
* @param webView the {@link WebView} instance that this adapter is serving.
*/
- WebViewContentsClientAdapter(WebView webView, WebViewDelegate webViewDelegate) {
+ WebViewContentsClientAdapter(WebView webView, Context context,
+ WebViewDelegate webViewDelegate) {
if (webView == null || webViewDelegate == null) {
- throw new IllegalArgumentException("webView or delegate can't be null");
+ throw new IllegalArgumentException("webView or delegate can't be null.");
}
+ if (context == null) {
+ throw new IllegalArgumentException("context can't be null.");
+ }
+
+ mContext = context;
mWebView = webView;
mWebViewDelegate = webViewDelegate;
setWebViewClient(null);
@@ -535,7 +543,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
// ErrorStrings is @hidden, so we can't do this in AwContents.
// Normally the net/ layer will set a valid description, but for synthesized callbacks
// (like in the case for intercepted requests) AwContents will pass in null.
- description = mWebViewDelegate.getErrorString(mWebView.getContext(), errorCode);
+ description = mWebViewDelegate.getErrorString(mContext, errorCode);
}
TraceEvent.begin();
if (TRACE) Log.d(TAG, "onReceivedError=" + failingUrl);
@@ -693,7 +701,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
if (TRACE) Log.d(TAG, "onJsAlert");
if (!mWebChromeClient.onJsAlert(mWebView, url, message, res)) {
new JsDialogHelper(res, JsDialogHelper.ALERT, null, message, url)
- .showDialog(mWebView.getContext());
+ .showDialog(mContext);
}
} else {
receiver.cancel();
@@ -710,7 +718,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
if (TRACE) Log.d(TAG, "onJsBeforeUnload");
if (!mWebChromeClient.onJsBeforeUnload(mWebView, url, message, res)) {
new JsDialogHelper(res, JsDialogHelper.UNLOAD, null, message, url)
- .showDialog(mWebView.getContext());
+ .showDialog(mContext);
}
} else {
receiver.cancel();
@@ -727,7 +735,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
if (TRACE) Log.d(TAG, "onJsConfirm");
if (!mWebChromeClient.onJsConfirm(mWebView, url, message, res)) {
new JsDialogHelper(res, JsDialogHelper.CONFIRM, null, message, url)
- .showDialog(mWebView.getContext());
+ .showDialog(mContext);
}
} else {
receiver.cancel();
@@ -745,7 +753,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
if (TRACE) Log.d(TAG, "onJsPrompt");
if (!mWebChromeClient.onJsPrompt(mWebView, url, message, defaultValue, res)) {
new JsDialogHelper(res, JsDialogHelper.PROMPT, defaultValue, message, url)
- .showDialog(mWebView.getContext());
+ .showDialog(mContext);
}
} else {
receiver.cancel();
@@ -891,7 +899,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
}
TraceEvent.begin();
FileChooserParamsAdapter adapter = new FileChooserParamsAdapter(
- fileChooserParams, mWebView.getContext());
+ fileChooserParams, mContext);
if (TRACE) Log.d(TAG, "showFileChooser");
ValueCallback<Uri[]> callbackAdapter = new ValueCallback<Uri[]>() {
private boolean mCompleted;
@@ -920,7 +928,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
// If the app did not handle it and we are running on Lollipop or newer, then
// abort.
- if (mWebView.getContext().getApplicationInfo().targetSdkVersion >=
+ if (mContext.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.LOLLIPOP) {
uploadFileCallback.onReceiveValue(null);
return;
@@ -1000,7 +1008,7 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
// The ic_media_video_poster icon is transparent so we need to draw it on a gray
// background.
Bitmap poster = BitmapFactory.decodeResource(
- mWebView.getContext().getResources(),
+ mContext.getResources(),
R.drawable.ic_media_video_poster);
result = Bitmap.createBitmap(poster.getWidth(), poster.getHeight(), poster.getConfig());
result.eraseColor(Color.GRAY);