diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-11-18 00:26:35 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-11-18 00:26:35 +0000 |
commit | c28cfda48ebe288274a9e58f7605e08658f7ed87 (patch) | |
tree | 3d8c1a0f35801b6526196c9a043a2ed7677e16e1 /chromium | |
parent | d04ef93249f34306cd5cfce2c4ae7df3b0d850cd (diff) | |
parent | ee0f312eaa0858d2608d88011527f9458bfeb8bf (diff) | |
download | webview-c28cfda48ebe288274a9e58f7605e08658f7ed87.tar.gz |
Merge up to ee0f312 from master-chromium.
Bring in changes that remove most of the direct dependencies on hidden
APIs.
Diffstat (limited to 'chromium')
7 files changed, 467 insertions, 88 deletions
diff --git a/chromium/java/com/android/webview/chromium/CookieManagerAdapter.java b/chromium/java/com/android/webview/chromium/CookieManagerAdapter.java index 44c2258..2dd34a3 100644 --- a/chromium/java/com/android/webview/chromium/CookieManagerAdapter.java +++ b/chromium/java/com/android/webview/chromium/CookieManagerAdapter.java @@ -88,6 +88,12 @@ public class CookieManagerAdapter extends CookieManager { return getCookie(url); } + // TODO(igsolla): remove this override once the WebView apk does not longer need + // to be binary compatibility with the API 21 version of the framework + /** + * IMPORTANT: This override is required for compatibility with the API 21 version of + * {@link CookieManager}. + */ @Override public synchronized String getCookie(WebAddress uri) { return mChromeCookieManager.getCookie(uri.toString()); @@ -133,10 +139,6 @@ public class CookieManagerAdapter extends CookieManager { mChromeCookieManager.flushCookieStore(); } - protected void flushCookieStore() { - flush(); - } - @Override protected boolean allowFileSchemeCookiesImpl() { return mChromeCookieManager.allowFileSchemeCookies(); diff --git a/chromium/java/com/android/webview/chromium/DrawGLFunctor.java b/chromium/java/com/android/webview/chromium/DrawGLFunctor.java index 265bfd0..7805077 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,7 +58,7 @@ 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"); @@ -63,18 +68,19 @@ class DrawGLFunctor { throw new IllegalArgumentException("requested a blocking DrawGL with a not null canvas."); } - 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); return true; } @@ -86,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. @@ -101,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 8706e4a..c065988 100644 --- a/chromium/java/com/android/webview/chromium/WebViewChromium.java +++ b/chromium/java/com/android/webview/chromium/WebViewChromium.java @@ -38,7 +38,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; @@ -168,8 +167,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) { @@ -246,7 +244,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)); @@ -2158,10 +2157,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 9f9c3aa..79751d8 100644 --- a/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java +++ b/chromium/java/com/android/webview/chromium/WebViewChromiumFactoryProvider.java @@ -20,18 +20,14 @@ import android.content.pm.PackageInfo; 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; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; -import android.os.FileUtils; 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; @@ -43,6 +39,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; @@ -100,9 +98,25 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider { private DataReductionProxyManager mProxyManager; private SharedPreferences mWebViewPrefs; + private WebViewDelegate mWebViewDelegate; + /** + * Constructor called by the API 21 version of {@link WebViewFactory} and earlier. + */ public WebViewChromiumFactoryProvider() { - if (Build.IS_DEBUGGABLE) { + 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(); CommandLine.initFromFile(COMMAND_LINE_FILE); @@ -120,9 +134,7 @@ 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); final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo(); @@ -134,17 +146,17 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider { 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 = packageInfo.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); - FileUtils.deleteContents(new File(dataDir)); + deleteContents(new File(dataDir)); } if (lastVersion != currentVersion) { mWebViewPrefs.edit().putInt(VERSION_CODE_PREF, currentVersion).apply(); @@ -152,25 +164,28 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider { // Now safe to use WebView data directory. } - private void initPlatSupportLibrary() { - DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction()); - AwContents.setAwDrawSWFunctionTable(GraphicsUtils.getDrawSWFunctionTable()); - AwContents.setAwDrawGLFunctionTable(GraphicsUtils.getDrawGLFunctionTable()); + private static boolean isBuildDebuggable() { + return !Build.TYPE.equals("user"); } - private static void initTraceEvent() { - syncATraceState(); - SystemProperties.addChangeCallback(new Runnable() { - @Override - public void run() { - syncATraceState(); + private static void deleteContents(File dir) { + File[] files = dir.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + Log.w(TAG, "Failed to delete " + file); + } } - }); + } } - private static void syncATraceState() { - long enabledFlags = SystemProperties.getLong("debug.atrace.tags.enableflags", 0); - TraceEvent.setATraceEnabled((enabledFlags & Trace.TRACE_TAG_WEBVIEW) != 0); + private void initPlatSupportLibrary() { + DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction()); + AwContents.setAwDrawSWFunctionTable(GraphicsUtils.getDrawSWFunctionTable()); + AwContents.setAwDrawGLFunctionTable(GraphicsUtils.getDrawGLFunctionTable()); } private void ensureChromiumStartedLocked(boolean onMainThread) { @@ -242,15 +257,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) { @@ -264,7 +286,7 @@ public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider { // Start listening for data reduction proxy setting changes. mProxyManager = new DataReductionProxyManager(); - mProxyManager.start(ActivityThread.currentApplication()); + mProxyManager.start(mWebViewDelegate.getApplication()); } boolean hasStarted() { @@ -305,10 +327,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( @@ -406,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(ActivityThread.currentApplication()); + ContentMain.initApplicationContext(mWebViewDelegate.getApplication()); } mCookieManager = new CookieManagerAdapter(new AwCookieManager()); } @@ -449,4 +474,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); + } + } + } +} + |