OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 org.chromium.base; | 5 package org.chromium.base; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.app.Application; | 8 import android.app.Application; |
9 import android.content.Context; | 9 import android.content.Context; |
10 import android.os.Bundle; | 10 import android.os.Bundle; |
11 import android.view.KeyEvent; | |
12 import android.view.Window; | 11 import android.view.Window; |
13 | 12 |
14 import java.lang.reflect.InvocationHandler; | |
15 import java.lang.reflect.InvocationTargetException; | |
16 import java.lang.reflect.Method; | |
17 import java.lang.reflect.Proxy; | |
18 | |
19 /** | 13 /** |
20 * Basic application functionality that should be shared among all browser appli
cations. | 14 * Basic application functionality that should be shared among all browser appli
cations. |
21 */ | 15 */ |
22 public class BaseChromiumApplication extends Application { | 16 public class BaseChromiumApplication extends Application { |
| 17 private static final String TAG = "cr.base"; |
| 18 |
| 19 @Override |
| 20 protected void attachBaseContext(Context base) { |
| 21 super.attachBaseContext(base); |
| 22 } |
| 23 |
23 /** | 24 /** |
24 * Interface to be implemented by listeners for window focus events. | 25 * Interface to be implemented by listeners for window focus events. |
25 */ | 26 */ |
26 public interface WindowFocusChangedListener { | 27 public interface WindowFocusChangedListener { |
27 /** | 28 /** |
28 * Called when the window focus changes for {@code activity}. | 29 * Called when the window focus changes for {@code activity}. |
29 * @param activity The {@link Activity} that has a window focus changed
event. | 30 * @param activity The {@link Activity} that has a window focus changed
event. |
30 * @param hasFocus Whether or not {@code activity} gained or lost focus. | 31 * @param hasFocus Whether or not {@code activity} gained or lost focus. |
31 */ | 32 */ |
32 public void onWindowFocusChanged(Activity activity, boolean hasFocus); | 33 public void onWindowFocusChanged(Activity activity, boolean hasFocus); |
33 } | 34 } |
34 | 35 |
35 private ObserverList<WindowFocusChangedListener> mWindowFocusListeners = | 36 private ObserverList<WindowFocusChangedListener> mWindowFocusListeners = |
36 new ObserverList<WindowFocusChangedListener>(); | 37 new ObserverList<WindowFocusChangedListener>(); |
37 | 38 |
38 /** | |
39 * Intercepts calls to an existing Window.Callback. Most invocations are pas
sed on directly | |
40 * to the composed Window.Callback but enables intercepting/manipulating oth
ers. | |
41 * | |
42 * This is used to relay window focus changes throughout the app and remedy
a bug in the | |
43 * appcompat library. | |
44 */ | |
45 private class WindowCallbackProxy implements InvocationHandler { | |
46 private final Window.Callback mCallback; | |
47 private final Activity mActivity; | |
48 | |
49 public WindowCallbackProxy(Activity activity, Window.Callback callback)
{ | |
50 mCallback = callback; | |
51 mActivity = activity; | |
52 } | |
53 | |
54 @Override | |
55 public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable { | |
56 if (method.getName().equals("onWindowFocusChanged") && args.length =
= 1 | |
57 && args[0] instanceof Boolean) { | |
58 onWindowFocusChanged((boolean) args[0]); | |
59 return null; | |
60 } else if (method.getName().equals("dispatchKeyEvent") && args.lengt
h == 1 | |
61 && args[0] instanceof KeyEvent) { | |
62 return dispatchKeyEvent((KeyEvent) args[0]); | |
63 } else { | |
64 try { | |
65 return method.invoke(mCallback, args); | |
66 } catch (InvocationTargetException e) { | |
67 // Special-case for when a method is not defined on the unde
rlying | |
68 // Window.Callback object. Because we're using a Proxy to fo
rward all method | |
69 // calls, this breaks the Android framework's handling for a
pps built against | |
70 // an older SDK. The framework expects an AbstractMethodErro
r but due to | |
71 // reflection it becomes wrapped inside an InvocationTargetE
xception. Undo the | |
72 // wrapping to signal the framework accordingly. | |
73 if (e.getCause() instanceof AbstractMethodError) { | |
74 throw e.getCause(); | |
75 } | |
76 throw e; | |
77 } | |
78 } | |
79 } | |
80 | |
81 public void onWindowFocusChanged(boolean hasFocus) { | |
82 mCallback.onWindowFocusChanged(hasFocus); | |
83 | |
84 for (WindowFocusChangedListener listener : mWindowFocusListeners) { | |
85 listener.onWindowFocusChanged(mActivity, hasFocus); | |
86 } | |
87 } | |
88 | |
89 public boolean dispatchKeyEvent(KeyEvent event) { | |
90 // TODO(aurimas): remove this once AppCompatDelegateImpl no longer s
teals | |
91 // KEYCODE_MENU. (see b/20529185) | |
92 if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatc
hKeyEvent(event)) { | |
93 return true; | |
94 } | |
95 return mCallback.dispatchKeyEvent(event); | |
96 } | |
97 } | |
98 @Override | 39 @Override |
99 public void onCreate() { | 40 public void onCreate() { |
100 super.onCreate(); | 41 super.onCreate(); |
101 ApplicationStatus.initialize(this); | 42 ApplicationStatus.initialize(this); |
102 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { | 43 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { |
103 @Override | 44 @Override |
104 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { | 45 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { |
105 Window.Callback callback = activity.getWindow().getCallback(); | 46 Window.Callback callback = activity.getWindow().getCallback(); |
106 activity.getWindow().setCallback((Window.Callback) Proxy.newProx
yInstance( | 47 activity.getWindow().setCallback(new WindowCallbackWrapper(callb
ack) { |
107 Window.Callback.class.getClassLoader(), new Class[] {Win
dow.Callback.class}, | 48 @Override |
108 new WindowCallbackProxy(activity, callback))); | 49 public void onWindowFocusChanged(boolean hasFocus) { |
| 50 super.onWindowFocusChanged(hasFocus); |
| 51 for (WindowFocusChangedListener listener : mWindowFocusL
isteners) { |
| 52 listener.onWindowFocusChanged(activity, hasFocus); |
| 53 } |
| 54 } |
| 55 }); |
109 } | 56 } |
110 | 57 |
111 @Override | 58 @Override |
112 public void onActivityDestroyed(Activity activity) { | 59 public void onActivityDestroyed(Activity activity) { |
113 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 60 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
114 } | 61 } |
115 | 62 |
116 @Override | 63 @Override |
117 public void onActivityPaused(Activity activity) { | 64 public void onActivityPaused(Activity activity) { |
118 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 65 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
119 } | 66 } |
120 | 67 |
121 @Override | 68 @Override |
122 public void onActivityResumed(Activity activity) { | 69 public void onActivityResumed(Activity activity) { |
123 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 70 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
124 } | 71 } |
125 | 72 |
126 @Override | 73 @Override |
127 public void onActivitySaveInstanceState(Activity activity, Bundle ou
tState) { | 74 public void onActivitySaveInstanceState(Activity activity, Bundle ou
tState) { |
128 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 75 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
129 } | 76 } |
130 | 77 |
131 @Override | 78 @Override |
132 public void onActivityStarted(Activity activity) { | 79 public void onActivityStarted(Activity activity) { |
133 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 80 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
134 } | 81 } |
135 | 82 |
136 @Override | 83 @Override |
137 public void onActivityStopped(Activity activity) { | 84 public void onActivityStopped(Activity activity) { |
138 assert Proxy.isProxyClass(activity.getWindow().getCallback().get
Class()); | 85 assert activity.getWindow().getCallback() instanceof WindowCallb
ackWrapper; |
139 } | 86 } |
140 }); | 87 }); |
141 } | 88 } |
142 | 89 |
143 /** | 90 /** |
144 * Registers a listener to receive window focus updates on activities in thi
s application. | 91 * Registers a listener to receive window focus updates on activities in thi
s application. |
145 * @param listener Listener to receive window focus events. | 92 * @param listener Listener to receive window focus events. |
146 */ | 93 */ |
147 public void registerWindowFocusChangedListener(WindowFocusChangedListener li
stener) { | 94 public void registerWindowFocusChangedListener(WindowFocusChangedListener li
stener) { |
148 mWindowFocusListeners.addObserver(listener); | 95 mWindowFocusListeners.addObserver(listener); |
(...skipping 10 matching lines...) Expand all Loading... |
159 /** Initializes the {@link CommandLine}. */ | 106 /** Initializes the {@link CommandLine}. */ |
160 public void initCommandLine() {} | 107 public void initCommandLine() {} |
161 | 108 |
162 /** | 109 /** |
163 * This must only be called for contexts whose application is a subclass of | 110 * This must only be called for contexts whose application is a subclass of |
164 * {@link BaseChromiumApplication}. | 111 * {@link BaseChromiumApplication}. |
165 */ | 112 */ |
166 @VisibleForTesting | 113 @VisibleForTesting |
167 public static void initCommandLine(Context context) { | 114 public static void initCommandLine(Context context) { |
168 ((BaseChromiumApplication) context.getApplicationContext()).initCommandL
ine(); | 115 ((BaseChromiumApplication) context.getApplicationContext()).initCommandL
ine(); |
169 }; | 116 } |
170 } | 117 } |
OLD | NEW |