summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgnacio Solla <igsolla@google.com>2014-10-29 12:46:49 +0000
committerIgnacio Solla <igsolla@google.com>2014-11-10 10:32:59 +0000
commit45702509d4752478188935eaf442c549c2c220be (patch)
tree8f7c3d40486f3fe67c11de8fda402e71a3abe054
parentedcfb0f0e74b0cbbd025397ecec6a80cb866854d (diff)
downloadwebview-45702509d4752478188935eaf442c549c2c220be.tar.gz
[WebView] Remove direct dependencies on hidden APIs.
BUG:18152150 Change-Id: If2b6c43f322b4223460b1be6c633858476244756
-rw-r--r--chromium/java/com/android/webview/chromium/DrawGLFunctor.java45
-rw-r--r--chromium/java/com/android/webview/chromium/ResourceRewriter.java35
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewChromium.java13
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java70
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java14
-rw-r--r--chromium/java/com/android/webview/chromium/WebViewDelegateFactory.java350
6 files changed, 444 insertions, 83 deletions
diff --git a/chromium/java/com/android/webview/chromium/DrawGLFunctor.java b/chromium/java/com/android/webview/chromium/DrawGLFunctor.java
index 7f7adeb..f955356 100644
--- a/chromium/java/com/android/webview/chromium/DrawGLFunctor.java
+++ b/chromium/java/com/android/webview/chromium/DrawGLFunctor.java
@@ -16,10 +16,12 @@
package com.android.webview.chromium;
-import android.view.HardwareCanvas;
-import android.view.ViewRootImpl;
+import android.view.View;
+import android.graphics.Canvas;
import android.util.Log;
+import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
+
import org.chromium.content.common.CleanupReference;
// Simple Java abstraction and wrapper for the native DrawGLFunctor flow.
@@ -34,10 +36,12 @@ class DrawGLFunctor {
// Pointer to native side instance
private CleanupReference mCleanupReference;
private DestroyRunnable mDestroyRunnable;
+ private WebViewDelegate mWebViewDelegate;
- public DrawGLFunctor(long viewContext) {
- mDestroyRunnable = new DestroyRunnable(nativeCreateGLFunctor(viewContext));
+ public DrawGLFunctor(long viewContext, WebViewDelegate webViewDelegate) {
+ mDestroyRunnable = new DestroyRunnable(nativeCreateGLFunctor(viewContext), webViewDelegate);
mCleanupReference = new CleanupReference(this, mDestroyRunnable);
+ mWebViewDelegate = webViewDelegate;
}
public void destroy() {
@@ -46,6 +50,7 @@ class DrawGLFunctor {
mCleanupReference.cleanupNow();
mCleanupReference = null;
mDestroyRunnable = null;
+ mWebViewDelegate = null;
}
}
@@ -53,26 +58,28 @@ class DrawGLFunctor {
mDestroyRunnable.detachNativeFunctor();
}
- public boolean requestDrawGL(HardwareCanvas canvas, ViewRootImpl viewRootImpl,
+ public boolean requestDrawGL(Canvas canvas, View containerView,
boolean waitForCompletion) {
if (mDestroyRunnable.mNativeDrawGLFunctor == 0) {
throw new RuntimeException("requested DrawGL on already destroyed DrawGLFunctor");
}
- if (viewRootImpl == null) {
- // Can happen during teardown when window is leaked.
+
+ if (!mWebViewDelegate.canInvokeDrawGlFunctor(containerView)) {
return false;
}
- mDestroyRunnable.mViewRootImpl = viewRootImpl;
+ mDestroyRunnable.mContainerView = containerView;
+
if (canvas == null) {
- viewRootImpl.invokeFunctor(mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);
+ mWebViewDelegate.invokeDrawGlFunctor(containerView,
+ mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);
return true;
}
- canvas.callDrawGLFunction(mDestroyRunnable.mNativeDrawGLFunctor);
+ mWebViewDelegate.callDrawGlFunction(canvas, mDestroyRunnable.mNativeDrawGLFunctor);
if (waitForCompletion) {
- viewRootImpl.invokeFunctor(mDestroyRunnable.mNativeDrawGLFunctor,
- waitForCompletion);
+ mWebViewDelegate.invokeDrawGlFunctor(containerView,
+ mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);
}
return true;
}
@@ -85,10 +92,12 @@ class DrawGLFunctor {
// IMPORTANT: this class must not hold any reference back to the outer DrawGLFunctor
// instance, as that will defeat GC of that object.
private static final class DestroyRunnable implements Runnable {
- ViewRootImpl mViewRootImpl;
+ private WebViewDelegate mWebViewDelegate;
+ View mContainerView;
long mNativeDrawGLFunctor;
- DestroyRunnable(long nativeDrawGLFunctor) {
+ DestroyRunnable(long nativeDrawGLFunctor, WebViewDelegate webViewDelegate) {
mNativeDrawGLFunctor = nativeDrawGLFunctor;
+ mWebViewDelegate = webViewDelegate;
}
// Called when the outer DrawGLFunctor instance has been GC'ed, i.e this is its finalizer.
@@ -100,10 +109,12 @@ class DrawGLFunctor {
}
void detachNativeFunctor() {
- if (mNativeDrawGLFunctor != 0 && mViewRootImpl != null) {
- mViewRootImpl.detachFunctor(mNativeDrawGLFunctor);
+ if (mNativeDrawGLFunctor != 0 && mContainerView != null
+ && mWebViewDelegate != null) {
+ mWebViewDelegate.detachDrawGlFunctor(mContainerView, mNativeDrawGLFunctor);
}
- mViewRootImpl = null;
+ mContainerView = null;
+ mWebViewDelegate = null;
}
}
diff --git a/chromium/java/com/android/webview/chromium/ResourceRewriter.java b/chromium/java/com/android/webview/chromium/ResourceRewriter.java
index 683277a..7d035b7 100644
--- a/chromium/java/com/android/webview/chromium/ResourceRewriter.java
+++ b/chromium/java/com/android/webview/chromium/ResourceRewriter.java
@@ -17,7 +17,6 @@
package com.android.webview.chromium;
import android.content.Context;
-import android.util.SparseArray;
/**
* Helper class used to fix up resource ids.
@@ -27,29 +26,15 @@ import android.util.SparseArray;
*/
class ResourceRewriter {
- public static void rewriteRValues(Context ctx) {
- // Rewrite the R 'constants' for the WebView library apk.
- SparseArray<String> packageIdentifiers = ctx.getResources().getAssets()
- .getAssignedPackageIdentifiers();
-
- final int N = packageIdentifiers.size();
- for (int i = 0; i < N; i++) {
- final String name = packageIdentifiers.valueAt(i);
-
- // The resources are always called com.android.webview even if the manifest has had the
- // package renamed.
- if ("com.android.webview".equals(name)) {
- final int id = packageIdentifiers.keyAt(i);
-
- // TODO: We should use jarjar to remove the redundant R classes here, but due
- // to a bug in jarjar it's not possible to rename classes with '$' in their name.
- // See b/15684775.
- com.android.webview.chromium.R.onResourcesLoaded(id);
- org.chromium.ui.R.onResourcesLoaded(id);
- org.chromium.content.R.onResourcesLoaded(id);
-
- break;
- }
- }
+ /**
+ * Rewrite the R 'constants' for the WebView library apk.
+ */
+ public static void rewriteRValues(final int packageId) {
+ // TODO: We should use jarjar to remove the redundant R classes here, but due
+ // to a bug in jarjar it's not possible to rename classes with '$' in their name.
+ // See b/15684775.
+ com.android.webview.chromium.R.onResourcesLoaded(packageId);
+ org.chromium.ui.R.onResourcesLoaded(packageId);
+ org.chromium.content.R.onResourcesLoaded(packageId);
}
}
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromium.java b/chromium/java/com/android/webview/chromium/WebViewChromium.java
index c08eb41..fb31b2a 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromium.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromium.java
@@ -37,7 +37,6 @@ import android.print.PrintDocumentAdapter;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
-import android.view.HardwareCanvas;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -166,8 +165,7 @@ class WebViewChromium implements WebViewProvider,
mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion;
mFactory = factory;
mRunQueue = new WebViewChromiumRunQueue();
- String webViewAssetPath = WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir;
- mWebView.getContext().getAssets().addAssetPath(webViewAssetPath);
+ factory.getWebViewDelegate().addWebViewAssetPath(mWebView.getContext());
}
static void completeWindowCreation(WebView parent, WebView child) {
@@ -244,7 +242,8 @@ class WebViewChromium implements WebViewProvider,
final boolean areLegacyQuirksEnabled =
mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT;
- mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView);
+ mContentsClientAdapter = new WebViewContentsClientAdapter(
+ mWebView, mFactory.getWebViewDelegate());
mWebSettings = new ContentSettingsAdapter(new AwSettings(
mWebView.getContext(), isAccessFromFileURLsGrantedByDefault,
areLegacyQuirksEnabled));
@@ -2154,10 +2153,10 @@ class WebViewChromium implements WebViewProvider,
public boolean requestDrawGL(Canvas canvas, boolean waitForCompletion,
View containerView) {
if (mGLfunctor == null) {
- mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext());
+ mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext(),
+ mFactory.getWebViewDelegate());
}
- return mGLfunctor.requestDrawGL(
- (HardwareCanvas) canvas, containerView.getViewRootImpl(), waitForCompletion);
+ return mGLfunctor.requestDrawGL(canvas, containerView, waitForCompletion);
}
@Override
diff --git a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 8043ad8..af78843 100644
--- a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -19,7 +19,6 @@ package com.android.webview.chromium;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.app.ActivityManager;
-import android.app.ActivityThread;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
@@ -28,8 +27,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.os.StrictMode;
-import android.os.SystemProperties;
-import android.os.Trace;
import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
@@ -41,6 +38,8 @@ import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
import android.webkit.WebViewProvider;
+import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
+
import org.chromium.android_webview.AwBrowserContext;
import org.chromium.android_webview.AwBrowserProcess;
import org.chromium.android_webview.AwContents;
@@ -97,8 +96,24 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
private boolean mStarted;
private SharedPreferences mWebViewPrefs;
+ private WebViewDelegate mWebViewDelegate;
+ /**
+ * Constructor called by the API 21 version of {@link WebViewFactory} and earlier.
+ */
public WebViewChromiumFactoryProvider() {
+ initialize(WebViewDelegateFactory.createApi21CompatibilityDelegate());
+ }
+
+ /**
+ * Constructor called by the API 22 version of {@link WebViewFactory} and later.
+ */
+ public WebViewChromiumFactoryProvider(android.webkit.WebViewDelegate delegate) {
+ initialize(WebViewDelegateFactory.createProxyDelegate(delegate));
+ }
+
+ private void initialize(WebViewDelegate webViewDelegate) {
+ mWebViewDelegate = webViewDelegate;
if (isBuildDebuggable()) {
// Suppress the StrictMode violation as this codepath is only hit on debugglable builds.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
@@ -117,21 +132,19 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
ThreadUtils.setWillOverrideUiThread();
// Load chromium library.
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "AwBrowserProcess.loadLibrary()");
AwBrowserProcess.loadLibrary();
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
// Load glue-layer support library.
System.loadLibrary("webviewchromium_plat_support");
// Use shared preference to check for package downgrade.
- mWebViewPrefs = ActivityThread.currentApplication().getSharedPreferences(
+ mWebViewPrefs = mWebViewDelegate.getApplication().getSharedPreferences(
CHROMIUM_PREFS_NAME, Context.MODE_PRIVATE);
int lastVersion = mWebViewPrefs.getInt(VERSION_CODE_PREF, 0);
int currentVersion = WebViewFactory.getLoadedPackageInfo().versionCode;
if (lastVersion > currentVersion) {
// The WebView package has been downgraded since we last ran in this application.
// Delete the WebView data directory's contents.
- String dataDir = PathUtils.getDataDirectory(ActivityThread.currentApplication());
+ String dataDir = PathUtils.getDataDirectory(mWebViewDelegate.getApplication());
Log.i(TAG, "WebView package downgraded from " + lastVersion + " to " + currentVersion +
"; deleting contents of " + dataDir);
deleteContents(new File(dataDir));
@@ -166,21 +179,6 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
AwContents.setAwDrawGLFunctionTable(GraphicsUtils.getDrawGLFunctionTable());
}
- private static void initTraceEvent() {
- syncATraceState();
- SystemProperties.addChangeCallback(new Runnable() {
- @Override
- public void run() {
- syncATraceState();
- }
- });
- }
-
- private static void syncATraceState() {
- long enabledFlags = SystemProperties.getLong("debug.atrace.tags.enableflags", 0);
- TraceEvent.setATraceEnabled((enabledFlags & Trace.TRACE_TAG_WEBVIEW) != 0);
- }
-
private void ensureChromiumStartedLocked(boolean onMainThread) {
assert Thread.holdsLock(mLock);
@@ -250,15 +248,22 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
"/system/framework/webview/paks");
// Make sure that ResourceProvider is initialized before starting the browser process.
- setUpResources(ActivityThread.currentApplication());
+ setUpResources(mWebViewDelegate.getApplication());
initPlatSupportLibrary();
- AwBrowserProcess.start(ActivityThread.currentApplication());
+ AwBrowserProcess.start(mWebViewDelegate.getApplication());
if (Build.IS_DEBUGGABLE) {
setWebContentsDebuggingEnabled(true);
}
- initTraceEvent();
+ TraceEvent.setATraceEnabled(mWebViewDelegate.isTraceTagEnabled());
+ mWebViewDelegate.setOnTraceEnabledChangeListener(
+ new WebViewDelegate.OnTraceEnabledChangeListener() {
+ @Override
+ public void onTraceEnabledChange(boolean enabled) {
+ TraceEvent.setATraceEnabled(enabled);
+ }
+ });
mStarted = true;
for (WeakReference<WebViewChromium> wvc : mWebViewsToStart) {
@@ -309,10 +314,13 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
mDevToolsServer.setRemoteDebuggingEnabled(enable);
}
- private void setUpResources(Context ctx) {
- ResourceRewriter.rewriteRValues(ctx);
+ private void setUpResources(Context context) {
+ // The resources are always called com.android.webview even if the manifest has had the
+ // package renamed.
+ ResourceRewriter.rewriteRValues(
+ mWebViewDelegate.getPackageId(context.getResources(), "com.android.webview"));
- AwResource.setResources(ctx.getResources());
+ AwResource.setResources(context.getResources());
AwResource.setErrorPageResources(android.R.raw.loaderror,
android.R.raw.nodomain);
AwResource.setConfigKeySystemUuidMapping(
@@ -410,7 +418,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(ActivityThread.currentApplication());
+ ContentMain.initApplicationContext(mWebViewDelegate.getApplication());
}
mCookieManager = new CookieManagerAdapter(new AwCookieManager());
}
@@ -453,4 +461,8 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
}
return mWebViewDatabase;
}
+
+ WebViewDelegate getWebViewDelegate() {
+ return mWebViewDelegate;
+ }
}
diff --git a/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java b/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
index 24c0ebc..6b4b894 100644
--- a/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
+++ b/chromium/java/com/android/webview/chromium/WebViewContentsClientAdapter.java
@@ -24,7 +24,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Picture;
-import android.net.http.ErrorStrings;
import android.net.http.SslError;
import android.net.Uri;
import android.os.Build;
@@ -52,6 +51,8 @@ import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import com.android.webview.chromium.WebViewDelegateFactory.WebViewDelegate;
+
import org.chromium.android_webview.AwContentsClient;
import org.chromium.android_webview.AwContentsClientBridge;
import org.chromium.android_webview.AwHttpAuthHandler;
@@ -107,6 +108,8 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
// The listener receiving notifications of screen updates.
private WebView.PictureListener mPictureListener;
+ private WebViewDelegate mWebViewDelegate;
+
private DownloadListener mDownloadListener;
private Handler mUiThreadHandler;
@@ -120,12 +123,13 @@ public class WebViewContentsClientAdapter extends AwContentsClient {
*
* @param webView the {@link WebView} instance that this adapter is serving.
*/
- WebViewContentsClientAdapter(WebView webView) {
- if (webView == null) {
- throw new IllegalArgumentException("webView can't be null");
+ WebViewContentsClientAdapter(WebView webView, WebViewDelegate webViewDelegate) {
+ if (webView == null || webViewDelegate == null) {
+ throw new IllegalArgumentException("webView or delegate can't be null");
}
mWebView = webView;
+ mWebViewDelegate = webViewDelegate;
setWebViewClient(null);
mUiThreadHandler = new Handler() {
@@ -531,7 +535,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 = ErrorStrings.getString(errorCode, mWebView.getContext());
+ description = mWebViewDelegate.getErrorString(mWebView.getContext(), errorCode);
}
TraceEvent.begin();
if (TRACE) Log.d(TAG, "onReceivedError=" + failingUrl);
diff --git a/chromium/java/com/android/webview/chromium/WebViewDelegateFactory.java b/chromium/java/com/android/webview/chromium/WebViewDelegateFactory.java
new file mode 100644
index 0000000..f5d1518
--- /dev/null
+++ b/chromium/java/com/android/webview/chromium/WebViewDelegateFactory.java
@@ -0,0 +1,350 @@
+package com.android.webview.chromium;
+
+import android.app.ActivityThread;
+import android.app.Application;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.net.http.ErrorStrings;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.HardwareCanvas;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.webkit.WebViewFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Factory class for {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate}s.
+ *
+ * <p>{@link WebViewDelegate com.android.webview.chromium.WebViewDelegate}s provide the same
+ * interface as {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} but without
+ * a dependency on the webkit class. Defining our own
+ * {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} in frameworks/webview
+ * allows the WebView apk to be binary compatible with the API 21 version of the framework, in
+ * which {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
+ * introduced.
+ *
+ * <p>The {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} interface and this
+ * factory class can be removed once we don't longer need to support WebView apk updates to devices
+ * running the API 21 version of the framework. At that point, we should use
+ * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} directly instead.
+ */
+class WebViewDelegateFactory {
+
+ /**
+ * Copy of {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}'s interface.
+ * See {@link WebViewDelegateFactory} for the reasons why this copy is needed.
+ */
+ interface WebViewDelegate {
+ /** @see android.webkit.WebViewDelegate.OnTraceEnabledChangeListener */
+ interface OnTraceEnabledChangeListener {
+ void onTraceEnabledChange(boolean enabled);
+ }
+
+ /** @see android.webkit.WebViewDelegate#setOnTraceEnabledChangeListener */
+ void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener);
+
+ /** @see android.webkit.WebViewDelegate#isTraceTagEnabled */
+ boolean isTraceTagEnabled();
+
+ /** @see android.webkit.WebViewDelegate#canInvokeDrawGlFunctor */
+ boolean canInvokeDrawGlFunctor(View containerView);
+
+ /** @see android.webkit.WebViewDelegate#invokeDrawGlFunctor */
+ void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
+ boolean waitForCompletion);
+
+ /** @see android.webkit.WebViewDelegate#callDrawGlFunction */
+ void callDrawGlFunction(Canvas canvas, long nativeDrawGLFunctor);
+
+ /** @see android.webkit.WebViewDelegate#detachDrawGlFunctor */
+ void detachDrawGlFunctor(View containerView, long nativeDrawGLFunctor);
+
+ /** @see android.webkit.WebViewDelegate#getPackageId */
+ int getPackageId(Resources resources, String packageName);
+
+ /** @see android.webkit.WebViewDelegate#getApplication */
+ Application getApplication();
+
+ /** @see android.webkit.WebViewDelegate#getErrorString */
+ String getErrorString(Context context, int errorCode);
+
+ /** @see android.webkit.WebViewDelegate#addWebViewAssetPath */
+ void addWebViewAssetPath(Context context);
+ }
+
+ /**
+ * Creates a {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} that proxies
+ * requests to the given {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}.
+ *
+ * @return the created delegate
+ */
+ static WebViewDelegate createProxyDelegate(android.webkit.WebViewDelegate delegate) {
+ return new ProxyDelegate(delegate);
+ }
+
+ /**
+ * Creates a {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} compatible
+ * with the API 21 version of the framework in which
+ * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
+ * introduced.
+ *
+ * @return the created delegate
+ */
+ static WebViewDelegate createApi21CompatibilityDelegate() {
+ return new Api21CompatibilityDelegate();
+ }
+
+ /**
+ * A {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} that proxies requests
+ * to a {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}.
+ */
+ private static class ProxyDelegate implements WebViewDelegate {
+
+ android.webkit.WebViewDelegate delegate;
+
+ ProxyDelegate(android.webkit.WebViewDelegate delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener) {
+ delegate.setOnTraceEnabledChangeListener(
+ new android.webkit.WebViewDelegate.OnTraceEnabledChangeListener() {
+ @Override
+ public void onTraceEnabledChange(boolean enabled) {
+ listener.onTraceEnabledChange(enabled);
+ ;
+ }
+ });
+ }
+
+ @Override
+ public boolean isTraceTagEnabled() {
+ return delegate.isTraceTagEnabled();
+ }
+
+ @Override
+ public boolean canInvokeDrawGlFunctor(View containerView) {
+ return delegate.canInvokeDrawGlFunctor(containerView);
+ }
+
+ @Override
+ public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
+ boolean waitForCompletion) {
+ delegate.invokeDrawGlFunctor(containerView, nativeDrawGLFunctor, waitForCompletion);
+ }
+
+ @Override
+ public void callDrawGlFunction(Canvas canvas, long nativeDrawGLFunctor) {
+ delegate.callDrawGlFunction(canvas, nativeDrawGLFunctor);
+ }
+
+ @Override
+ public void detachDrawGlFunctor(View containerView, long nativeDrawGLFunctor) {
+ delegate.detachDrawGlFunctor(containerView, nativeDrawGLFunctor);
+ }
+
+ @Override
+ public int getPackageId(Resources resources, String packageName) {
+ return delegate.getPackageId(resources, packageName);
+ }
+
+ @Override
+ public Application getApplication() {
+ return delegate.getApplication();
+ }
+
+ @Override
+ public String getErrorString(Context context, int errorCode) {
+ return delegate.getErrorString(context, errorCode);
+ }
+
+ @Override
+ public void addWebViewAssetPath(Context context) {
+ delegate.addWebViewAssetPath(context);
+ }
+ }
+
+ /**
+ * A {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} compatible with the
+ * API 21 version of the framework in which
+ * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
+ * introduced.
+ *
+ * <p>This class implements the
+ * {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} functionality by using
+ * reflection to call into hidden frameworks APIs released in the API-21 version of the
+ * framework.
+ */
+ private static class Api21CompatibilityDelegate implements WebViewDelegate {
+ /** Copy of Trace.TRACE_TAG_WEBVIEW */
+ private final static long TRACE_TAG_WEBVIEW = 1L << 4;
+
+ /** Hidden APIs released in the API 21 version of the framework */
+ private final Method mIsTagEnabledMethod;
+ private final Method mAddChangeCallbackMethod;
+ private final Method mGetViewRootImplMethod;
+ private final Method mInvokeFunctorMethod;
+ private final Method mCallDrawGLFunctionMethod;
+ private final Method mDetachFunctorMethod;
+ private final Method mGetAssignedPackageIdentifiersMethod;
+ private final Method mAddAssetPathMethod;
+ private final Method mCurrentApplicationMethod;
+ private final Method mGetStringMethod;
+ private final Method mGetLoadedPackageInfoMethod;
+
+ Api21CompatibilityDelegate() {
+ try {
+ // Important: This reflection essentially defines a snapshot of some hidden APIs
+ // at version 21 of the framework for compatibility reasons, and the reflection
+ // should not be changed even if those hidden APIs change in future releases.
+ mIsTagEnabledMethod = Trace.class.getMethod("isTagEnabled", long.class);
+ mAddChangeCallbackMethod = Class.forName("android.os.SystemProperties")
+ .getMethod("addChangeCallback", Runnable.class);
+ mGetViewRootImplMethod = View.class.getMethod("getViewRootImpl");
+ mInvokeFunctorMethod = Class.forName("android.view.ViewRootImpl")
+ .getMethod("invokeFunctor", long.class, boolean.class);
+ mDetachFunctorMethod = Class.forName("android.view.ViewRootImpl")
+ .getMethod("detachFunctor", long.class);
+ mCallDrawGLFunctionMethod = Class.forName("android.view.HardwareCanvas")
+ .getMethod("callDrawGLFunction", long.class);
+ mGetAssignedPackageIdentifiersMethod = AssetManager.class.getMethod(
+ "getAssignedPackageIdentifiers");
+ mAddAssetPathMethod = AssetManager.class.getMethod(
+ "addAssetPath", String.class);
+ mCurrentApplicationMethod = Class.forName("android.app.ActivityThread")
+ .getMethod("currentApplication");
+ mGetStringMethod = Class.forName("android.net.http.ErrorStrings")
+ .getMethod("getString", int.class, Context.class);
+ mGetLoadedPackageInfoMethod = Class.forName("android.webkit.WebViewFactory")
+ .getMethod("getLoadedPackageInfo");
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener) {
+ try {
+ mAddChangeCallbackMethod.invoke(null, new Runnable() {
+ @Override
+ public void run() {
+ listener.onTraceEnabledChange(isTraceTagEnabled());
+ }
+ });
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public boolean isTraceTagEnabled() {
+ try {
+ return ((Boolean) mIsTagEnabledMethod.invoke(null, TRACE_TAG_WEBVIEW));
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public boolean canInvokeDrawGlFunctor(View containerView) {
+ try {
+ Object viewRootImpl = mGetViewRootImplMethod.invoke(containerView);
+ // viewRootImpl can be null during teardown when window is leaked.
+ return viewRootImpl != null;
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public void invokeDrawGlFunctor(View containerView, long nativeDrawGLFunctor,
+ boolean waitForCompletion) {
+ try {
+ Object viewRootImpl = mGetViewRootImplMethod.invoke(containerView);
+ if (viewRootImpl != null) {
+ mInvokeFunctorMethod.invoke(viewRootImpl, nativeDrawGLFunctor, waitForCompletion);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public void callDrawGlFunction(Canvas canvas, long nativeDrawGLFunctor) {
+ try {
+ mCallDrawGLFunctionMethod.invoke(canvas, nativeDrawGLFunctor);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public void detachDrawGlFunctor(View containerView, long nativeDrawGLFunctor) {
+ try {
+ Object viewRootImpl = mGetViewRootImplMethod.invoke(containerView);
+ if (viewRootImpl != null) {
+ mDetachFunctorMethod.invoke(viewRootImpl, nativeDrawGLFunctor);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public int getPackageId(Resources resources, String packageName) {
+ try {
+ SparseArray packageIdentifiers =
+ (SparseArray) mGetAssignedPackageIdentifiersMethod.invoke(
+ resources.getAssets());
+ for (int i = 0; i < packageIdentifiers.size(); i++) {
+ final String name = (String) packageIdentifiers.valueAt(i);
+
+ if (packageName.equals(name)) {
+ return packageIdentifiers.keyAt(i);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ throw new RuntimeException("Package not found: " + packageName);
+ }
+
+ @Override
+ public Application getApplication() {
+ try {
+ return (Application) mCurrentApplicationMethod.invoke(null);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public String getErrorString(Context context, int errorCode) {
+ try {
+ return (String) mGetStringMethod.invoke(null, errorCode, context);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+
+ @Override
+ public void addWebViewAssetPath(Context context) {
+ try {
+ PackageInfo info = (PackageInfo) mGetLoadedPackageInfoMethod.invoke(null);
+ mAddAssetPathMethod.invoke(context.getAssets(), info.applicationInfo.sourceDir);
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid reflection", e);
+ }
+ }
+ }
+}
+