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: Ic5a928f34c16cc86de331d39ce5eb534b2602907
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..667259e
--- /dev/null
+++ b/chromium/java/com/android/webview/chromium/ResourcesContextWrapperFactory.java
@@ -0,0 +1,121 @@
+/*
+ * 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 we can use resources from the WebView
+ * apk. 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 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;
+ }
+
+ // Wrap Context so that we can use resources from the webview resource apk.
+ private static ContextWrapper createWrapper(final Context ctx) {
+ final Resources resources = WebViewChromiumFactoryProvider.getWebViewPackageResources(ctx);
+ final Resources.Theme theme = resources.newTheme();
+
+ 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 Context getApplicationContext() {
+ return get(ctx.getApplicationContext());
+ }
+
+ @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);
+ }
+
+ @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);
+ }
+ }
+
+ @Override
+ public AssetManager getAssets() {
+ return resources.getAssets();
+ }
+
+ @Override
+ public Resources getResources() {
+ return resources;
+ }
+
+ @Override
+ public Resources.Theme getTheme() {
+ return theme;
+ }
+ };
+ }
+}
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromium.java b/chromium/java/com/android/webview/chromium/WebViewChromium.java
index 763502a..23d34d7 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;
@@ -38,7 +36,6 @@
import android.util.Log;
import android.view.HardwareCanvas;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
@@ -253,54 +250,8 @@
});
}
- // Wrap Context so that we can use resources from the webview resource apk.
- private static Context resourcesContextWrapper(final Context ctx) {
- final Resources resources = WebViewChromiumFactoryProvider.getWebViewPackageResources(ctx);
- final Resources.Theme theme = resources.newTheme();
-
- 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);
- }
- }
-
- @Override
- public Resources getResources() {
- return resources;
- }
-
- @Override
- public Resources.Theme getTheme() {
- return theme;
- }
- };
- }
-
private void initForReal() {
- Context ctx = resourcesContextWrapper(mWebView.getContext());
+ Context ctx = ResourcesContextWrapperFactory.get(mWebView.getContext());
mAwContents = new AwContents(mFactory.getBrowserContext(), mWebView, ctx,
new InternalAccessAdapter(), new WebViewNativeGLDelegate(),
mContentsClientAdapter, mWebSettings.getAwSettings());
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index e3e34bb..8bde8d6 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -191,7 +191,7 @@
// Make sure that ResourceProvider is initialized before starting the browser process.
setUpResources(ActivityThread.currentApplication());
- AwBrowserProcess.start(ActivityThread.currentApplication());
+ AwBrowserProcess.start(getWrappedCurrentApplicationContext());
initPlatSupportLibrary();
if (Build.IS_DEBUGGABLE) {
@@ -220,6 +220,10 @@
}
}
+ private Context getWrappedCurrentApplicationContext() {
+ return ResourcesContextWrapperFactory.get(ActivityThread.currentApplication());
+ }
+
AwBrowserContext getBrowserContext() {
synchronized (mLock) {
return getBrowserContextLocked();
@@ -346,7 +350,7 @@
// 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(ActivityThread.currentApplication());
+ ContentMain.initApplicationContext(getWrappedCurrentApplicationContext());
}
mCookieManager = new CookieManagerAdapter(new AwCookieManager());
}