1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package com
.android
.webview
.chromium
;
7 import android
.app
.Application
;
8 import android
.content
.Context
;
9 import android
.content
.pm
.PackageInfo
;
10 import android
.content
.res
.AssetManager
;
11 import android
.content
.res
.Resources
;
12 import android
.graphics
.Canvas
;
13 import android
.os
.Trace
;
14 import android
.util
.SparseArray
;
15 import android
.view
.View
;
17 import java
.lang
.reflect
.Method
;
20 * Factory class for {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate}s.
22 * <p>{@link WebViewDelegate com.android.webview.chromium.WebViewDelegate}s provide the same
23 * interface as {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} but without
24 * a dependency on the webkit class. Defining our own
25 * {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} in frameworks/webview
26 * allows the WebView apk to be binary compatible with the API 21 version of the framework, in
27 * which {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
30 * <p>The {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} interface and this
31 * factory class can be removed once we don't longer need to support WebView apk updates to devices
32 * running the API 21 version of the framework. At that point, we should use
33 * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} directly instead.
35 class WebViewDelegateFactory
{
37 * Copy of {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}'s interface.
38 * See {@link WebViewDelegateFactory} for the reasons why this copy is needed.
40 interface WebViewDelegate
{
41 /** @see android.webkit.WebViewDelegate.OnTraceEnabledChangeListener */
42 interface OnTraceEnabledChangeListener
{
43 void onTraceEnabledChange(boolean enabled
);
46 /** @see android.webkit.WebViewDelegate#setOnTraceEnabledChangeListener */
47 void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener
);
49 /** @see android.webkit.WebViewDelegate#isTraceTagEnabled */
50 boolean isTraceTagEnabled();
52 /** @see android.webkit.WebViewDelegate#canInvokeDrawGlFunctor */
53 boolean canInvokeDrawGlFunctor(View containerView
);
55 /** @see android.webkit.WebViewDelegate#invokeDrawGlFunctor */
56 void invokeDrawGlFunctor(
57 View containerView
, long nativeDrawGLFunctor
, boolean waitForCompletion
);
59 /** @see android.webkit.WebViewDelegate#callDrawGlFunction */
60 void callDrawGlFunction(Canvas canvas
, long nativeDrawGLFunctor
);
62 /** @see android.webkit.WebViewDelegate#detachDrawGlFunctor */
63 void detachDrawGlFunctor(View containerView
, long nativeDrawGLFunctor
);
65 /** @see android.webkit.WebViewDelegate#getPackageId */
66 int getPackageId(Resources resources
, String packageName
);
68 /** @see android.webkit.WebViewDelegate#getApplication */
69 Application
getApplication();
71 /** @see android.webkit.WebViewDelegate#getErrorString */
72 String
getErrorString(Context context
, int errorCode
);
74 /** @see android.webkit.WebViewDelegate#addWebViewAssetPath */
75 void addWebViewAssetPath(Context context
);
79 * Creates a {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} that proxies
80 * requests to the given {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}.
82 * @return the created delegate
84 static WebViewDelegate
createProxyDelegate(android
.webkit
.WebViewDelegate delegate
) {
85 return new ProxyDelegate(delegate
);
89 * Creates a {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} compatible
90 * with the API 21 version of the framework in which
91 * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
94 * @return the created delegate
96 static WebViewDelegate
createApi21CompatibilityDelegate() {
97 return new Api21CompatibilityDelegate();
101 * A {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} that proxies requests
102 * to a {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate}.
104 private static class ProxyDelegate
implements WebViewDelegate
{
105 android
.webkit
.WebViewDelegate mDelegate
;
107 ProxyDelegate(android
.webkit
.WebViewDelegate delegate
) {
108 mDelegate
= delegate
;
112 public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener
) {
113 mDelegate
.setOnTraceEnabledChangeListener(
114 new android
.webkit
.WebViewDelegate
.OnTraceEnabledChangeListener() {
116 public void onTraceEnabledChange(boolean enabled
) {
117 listener
.onTraceEnabledChange(enabled
);
123 public boolean isTraceTagEnabled() {
124 return mDelegate
.isTraceTagEnabled();
128 public boolean canInvokeDrawGlFunctor(View containerView
) {
129 return mDelegate
.canInvokeDrawGlFunctor(containerView
);
133 public void invokeDrawGlFunctor(
134 View containerView
, long nativeDrawGLFunctor
, boolean waitForCompletion
) {
135 mDelegate
.invokeDrawGlFunctor(containerView
, nativeDrawGLFunctor
, waitForCompletion
);
139 public void callDrawGlFunction(Canvas canvas
, long nativeDrawGLFunctor
) {
140 mDelegate
.callDrawGlFunction(canvas
, nativeDrawGLFunctor
);
144 public void detachDrawGlFunctor(View containerView
, long nativeDrawGLFunctor
) {
145 mDelegate
.detachDrawGlFunctor(containerView
, nativeDrawGLFunctor
);
149 public int getPackageId(Resources resources
, String packageName
) {
150 return mDelegate
.getPackageId(resources
, packageName
);
154 public Application
getApplication() {
155 return mDelegate
.getApplication();
159 public String
getErrorString(Context context
, int errorCode
) {
160 return mDelegate
.getErrorString(context
, errorCode
);
164 public void addWebViewAssetPath(Context context
) {
165 mDelegate
.addWebViewAssetPath(context
);
170 * A {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} compatible with the
171 * API 21 version of the framework in which
172 * {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
175 * <p>This class implements the
176 * {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} functionality by using
177 * reflection to call into hidden frameworks APIs released in the API-21 version of the
180 private static class Api21CompatibilityDelegate
implements WebViewDelegate
{
181 /** Copy of Trace.TRACE_TAG_WEBVIEW */
182 private static final long TRACE_TAG_WEBVIEW
= 1L << 4;
184 /** Hidden APIs released in the API 21 version of the framework */
185 private final Method mIsTagEnabledMethod
;
186 private final Method mAddChangeCallbackMethod
;
187 private final Method mGetViewRootImplMethod
;
188 private final Method mInvokeFunctorMethod
;
189 private final Method mCallDrawGLFunctionMethod
;
190 private final Method mDetachFunctorMethod
;
191 private final Method mGetAssignedPackageIdentifiersMethod
;
192 private final Method mAddAssetPathMethod
;
193 private final Method mCurrentApplicationMethod
;
194 private final Method mGetStringMethod
;
195 private final Method mGetLoadedPackageInfoMethod
;
197 Api21CompatibilityDelegate() {
199 // Important: This reflection essentially defines a snapshot of some hidden APIs
200 // at version 21 of the framework for compatibility reasons, and the reflection
201 // should not be changed even if those hidden APIs change in future releases.
202 mIsTagEnabledMethod
= Trace
.class.getMethod("isTagEnabled", long.class);
203 mAddChangeCallbackMethod
= Class
.forName("android.os.SystemProperties")
204 .getMethod("addChangeCallback", Runnable
.class);
205 mGetViewRootImplMethod
= View
.class.getMethod("getViewRootImpl");
206 mInvokeFunctorMethod
=
207 Class
.forName("android.view.ViewRootImpl")
208 .getMethod("invokeFunctor", long.class, boolean.class);
209 mDetachFunctorMethod
= Class
.forName("android.view.ViewRootImpl")
210 .getMethod("detachFunctor", long.class);
211 mCallDrawGLFunctionMethod
= Class
.forName("android.view.HardwareCanvas")
212 .getMethod("callDrawGLFunction", long.class);
213 mGetAssignedPackageIdentifiersMethod
=
214 AssetManager
.class.getMethod("getAssignedPackageIdentifiers");
215 mAddAssetPathMethod
= AssetManager
.class.getMethod("addAssetPath", String
.class);
216 mCurrentApplicationMethod
=
217 Class
.forName("android.app.ActivityThread").getMethod("currentApplication");
218 mGetStringMethod
= Class
.forName("android.net.http.ErrorStrings")
219 .getMethod("getString", int.class, Context
.class);
220 mGetLoadedPackageInfoMethod
= Class
.forName("android.webkit.WebViewFactory")
221 .getMethod("getLoadedPackageInfo");
222 } catch (Exception e
) {
223 throw new RuntimeException("Invalid reflection", e
);
228 public void setOnTraceEnabledChangeListener(final OnTraceEnabledChangeListener listener
) {
230 mAddChangeCallbackMethod
.invoke(null, new Runnable() {
233 listener
.onTraceEnabledChange(isTraceTagEnabled());
236 } catch (Exception e
) {
237 throw new RuntimeException("Invalid reflection", e
);
242 public boolean isTraceTagEnabled() {
244 return ((Boolean
) mIsTagEnabledMethod
.invoke(null, TRACE_TAG_WEBVIEW
));
245 } catch (Exception e
) {
246 throw new RuntimeException("Invalid reflection", e
);
251 public boolean canInvokeDrawGlFunctor(View containerView
) {
253 Object viewRootImpl
= mGetViewRootImplMethod
.invoke(containerView
);
254 // viewRootImpl can be null during teardown when window is leaked.
255 return viewRootImpl
!= null;
256 } catch (Exception e
) {
257 throw new RuntimeException("Invalid reflection", e
);
262 public void invokeDrawGlFunctor(
263 View containerView
, long nativeDrawGLFunctor
, boolean waitForCompletion
) {
265 Object viewRootImpl
= mGetViewRootImplMethod
.invoke(containerView
);
266 if (viewRootImpl
!= null) {
267 mInvokeFunctorMethod
.invoke(
268 viewRootImpl
, nativeDrawGLFunctor
, waitForCompletion
);
270 } catch (Exception e
) {
271 throw new RuntimeException("Invalid reflection", e
);
276 public void callDrawGlFunction(Canvas canvas
, long nativeDrawGLFunctor
) {
278 mCallDrawGLFunctionMethod
.invoke(canvas
, nativeDrawGLFunctor
);
279 } catch (Exception e
) {
280 throw new RuntimeException("Invalid reflection", e
);
285 public void detachDrawGlFunctor(View containerView
, long nativeDrawGLFunctor
) {
287 Object viewRootImpl
= mGetViewRootImplMethod
.invoke(containerView
);
288 if (viewRootImpl
!= null) {
289 mDetachFunctorMethod
.invoke(viewRootImpl
, nativeDrawGLFunctor
);
291 } catch (Exception e
) {
292 throw new RuntimeException("Invalid reflection", e
);
297 public int getPackageId(Resources resources
, String packageName
) {
299 SparseArray packageIdentifiers
=
300 (SparseArray
) mGetAssignedPackageIdentifiersMethod
.invoke(
301 resources
.getAssets());
302 for (int i
= 0; i
< packageIdentifiers
.size(); i
++) {
303 final String name
= (String
) packageIdentifiers
.valueAt(i
);
305 if (packageName
.equals(name
)) {
306 return packageIdentifiers
.keyAt(i
);
309 } catch (Exception e
) {
310 throw new RuntimeException("Invalid reflection", e
);
312 throw new RuntimeException("Package not found: " + packageName
);
316 public Application
getApplication() {
318 return (Application
) mCurrentApplicationMethod
.invoke(null);
319 } catch (Exception e
) {
320 throw new RuntimeException("Invalid reflection", e
);
325 public String
getErrorString(Context context
, int errorCode
) {
327 return (String
) mGetStringMethod
.invoke(null, errorCode
, context
);
328 } catch (Exception e
) {
329 throw new RuntimeException("Invalid reflection", e
);
334 public void addWebViewAssetPath(Context context
) {
336 PackageInfo info
= (PackageInfo
) mGetLoadedPackageInfoMethod
.invoke(null);
337 mAddAssetPathMethod
.invoke(context
.getAssets(), info
.applicationInfo
.sourceDir
);
338 } catch (Exception e
) {
339 throw new RuntimeException("Invalid reflection", e
);