OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package com.android.webview.chromium; | 5 package com.android.webview.chromium; |
6 | 6 |
7 import android.content.ComponentCallbacks; | 7 import android.content.ComponentCallbacks; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.ContextWrapper; | 9 import android.content.ContextWrapper; |
10 import android.view.LayoutInflater; | 10 import android.view.LayoutInflater; |
11 | 11 |
12 import org.chromium.base.annotations.SuppressFBWarnings; | 12 import org.chromium.base.annotations.SuppressFBWarnings; |
13 | 13 |
14 import java.util.WeakHashMap; | |
15 | |
16 /** | 14 /** |
17 * This class allows us to wrap the application context so that the WebView impl
ementation can | 15 * This class allows us to wrap the application context so that the WebView impl
ementation can |
18 * correctly reference both org.chromium.* and application classes which is nece
ssary to properly | 16 * correctly reference both org.chromium.* and application classes which is nece
ssary to properly |
19 * inflate UI. We keep a weak map from contexts to wrapped contexts to avoid co
nstantly re-wrapping | 17 * inflate UI. |
20 * or doubly wrapping contexts. | |
21 */ | 18 */ |
22 public class ResourcesContextWrapperFactory { | 19 public class ResourcesContextWrapperFactory { |
23 private static WeakHashMap<Context, ContextWrapper> sCtxToWrapper = | |
24 new WeakHashMap<Context, ContextWrapper>(); | |
25 private static final Object sLock = new Object(); | |
26 | |
27 private ResourcesContextWrapperFactory() {} | 20 private ResourcesContextWrapperFactory() {} |
28 | 21 |
29 public static Context get(Context ctx) { | 22 public static Context get(Context ctx) { |
30 ContextWrapper wrappedCtx; | 23 // Avoid double-wrapping a context. |
31 synchronized (sLock) { | 24 if (ctx instanceof WebViewContextWrapper) { |
32 wrappedCtx = sCtxToWrapper.get(ctx); | 25 return ctx; |
33 if (wrappedCtx == null) { | 26 } |
34 wrappedCtx = createWrapper(ctx); | 27 return new WebViewContextWrapper(ctx); |
35 sCtxToWrapper.put(ctx, wrappedCtx); | 28 } |
| 29 |
| 30 private static class WebViewContextWrapper extends ContextWrapper { |
| 31 private Context mApplicationContext; |
| 32 |
| 33 public WebViewContextWrapper(Context base) { |
| 34 super(base); |
| 35 } |
| 36 |
| 37 @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") |
| 38 @Override |
| 39 public ClassLoader getClassLoader() { |
| 40 final ClassLoader appCl = getBaseContext().getClassLoader(); |
| 41 final ClassLoader webViewCl = this.getClass().getClassLoader(); |
| 42 return new ClassLoader() { |
| 43 @Override |
| 44 protected Class<?> findClass(String name) throws ClassNotFoundEx
ception { |
| 45 // First look in the WebViewProvider class loader. |
| 46 try { |
| 47 return webViewCl.loadClass(name); |
| 48 } catch (ClassNotFoundException e) { |
| 49 // Look in the app class loader; allowing it to throw |
| 50 // ClassNotFoundException. |
| 51 return appCl.loadClass(name); |
| 52 } |
| 53 } |
| 54 }; |
| 55 } |
| 56 |
| 57 @Override |
| 58 public Object getSystemService(String name) { |
| 59 if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) { |
| 60 LayoutInflater i = (LayoutInflater) getBaseContext().getSystemSe
rvice(name); |
| 61 return i.cloneInContext(this); |
| 62 } else { |
| 63 return getBaseContext().getSystemService(name); |
36 } | 64 } |
37 } | 65 } |
38 return wrappedCtx; | |
39 } | |
40 | 66 |
41 private static ContextWrapper createWrapper(final Context ctx) { | 67 @Override |
42 return new ContextWrapper(ctx) { | 68 public Context getApplicationContext() { |
43 private Context mApplicationContext; | 69 if (mApplicationContext == null) { |
44 | 70 Context appCtx = getBaseContext().getApplicationContext(); |
45 @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") | 71 if (appCtx == getBaseContext()) { |
46 @Override | 72 mApplicationContext = this; |
47 public ClassLoader getClassLoader() { | |
48 final ClassLoader appCl = getBaseContext().getClassLoader(); | |
49 final ClassLoader webViewCl = this.getClass().getClassLoader(); | |
50 return new ClassLoader() { | |
51 @Override | |
52 protected Class<?> findClass(String name) throws ClassNotFou
ndException { | |
53 // First look in the WebViewProvider class loader. | |
54 try { | |
55 return webViewCl.loadClass(name); | |
56 } catch (ClassNotFoundException e) { | |
57 // Look in the app class loader; allowing it to thro
w | |
58 // ClassNotFoundException. | |
59 return appCl.loadClass(name); | |
60 } | |
61 } | |
62 }; | |
63 } | |
64 | |
65 @Override | |
66 public Object getSystemService(String name) { | |
67 if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) { | |
68 LayoutInflater i = (LayoutInflater) getBaseContext().getSyst
emService(name); | |
69 return i.cloneInContext(this); | |
70 } else { | 73 } else { |
71 return getBaseContext().getSystemService(name); | 74 mApplicationContext = get(appCtx); |
72 } | 75 } |
73 } | 76 } |
| 77 return mApplicationContext; |
| 78 } |
74 | 79 |
75 @Override | 80 @Override |
76 public Context getApplicationContext() { | 81 public void registerComponentCallbacks(ComponentCallbacks callback) { |
77 if (mApplicationContext == null) { | 82 // We have to override registerComponentCallbacks and unregisterComp
onentCallbacks |
78 mApplicationContext = get(ctx.getApplicationContext()); | 83 // since they call getApplicationContext().[un]registerComponentCall
backs() |
79 } | 84 // which causes us to go into a loop. |
80 return mApplicationContext; | 85 getBaseContext().registerComponentCallbacks(callback); |
81 } | 86 } |
82 | 87 |
83 @Override | 88 @Override |
84 public void registerComponentCallbacks(ComponentCallbacks callback)
{ | 89 public void unregisterComponentCallbacks(ComponentCallbacks callback) { |
85 // We have to override registerComponentCallbacks and unregister
ComponentCallbacks | 90 getBaseContext().unregisterComponentCallbacks(callback); |
86 // since they call getApplicationContext().[un]registerComponent
Callbacks() | 91 } |
87 // which causes us to go into a loop. | |
88 ctx.registerComponentCallbacks(callback); | |
89 } | |
90 | |
91 @Override | |
92 public void unregisterComponentCallbacks(ComponentCallbacks callback
) { | |
93 ctx.unregisterComponentCallbacks(callback); | |
94 } | |
95 }; | |
96 } | 92 } |
97 } | 93 } |
OLD | NEW |