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; | 13 import java.lang.reflect.InvocationHandler; |
15 import java.lang.reflect.InvocationTargetException; | 14 import java.lang.reflect.InvocationTargetException; |
16 import java.lang.reflect.Method; | 15 import java.lang.reflect.Method; |
17 import java.lang.reflect.Proxy; | 16 import java.lang.reflect.Proxy; |
18 | 17 |
19 /** | 18 /** |
20 * Basic application functionality that should be shared among all browser appli
cations. | 19 * Basic application functionality that should be shared among all browser appli
cations. |
21 */ | 20 */ |
22 public class BaseChromiumApplication extends Application { | 21 public class BaseChromiumApplication extends Application { |
23 /** | 22 /** |
24 * Interface to be implemented by listeners for window focus events. | 23 * Interface to be implemented by listeners for window focus events. |
25 */ | 24 */ |
26 public interface WindowFocusChangedListener { | 25 public interface WindowFocusChangedListener { |
27 /** | 26 /** |
28 * Called when the window focus changes for {@code activity}. | 27 * Called when the window focus changes for {@code activity}. |
29 * @param activity The {@link Activity} that has a window focus changed
event. | 28 * @param activity The {@link Activity} that has a window focus changed
event. |
30 * @param hasFocus Whether or not {@code activity} gained or lost focus. | 29 * @param hasFocus Whether or not {@code activity} gained or lost focus. |
31 */ | 30 */ |
32 public void onWindowFocusChanged(Activity activity, boolean hasFocus); | 31 public void onWindowFocusChanged(Activity activity, boolean hasFocus); |
33 } | 32 } |
34 | 33 |
35 private ObserverList<WindowFocusChangedListener> mWindowFocusListeners = | 34 private ObserverList<WindowFocusChangedListener> mWindowFocusListeners = |
36 new ObserverList<WindowFocusChangedListener>(); | 35 new ObserverList<WindowFocusChangedListener>(); |
37 | 36 |
38 /** | 37 /** |
39 * Intercepts calls to an existing Window.Callback. Most invocations are pas
sed on directly | 38 * 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. | 39 * 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 */ | 40 */ |
45 private class WindowCallbackProxy implements InvocationHandler { | 41 private class WindowCallbackProxy implements InvocationHandler { |
46 private final Window.Callback mCallback; | 42 private final Window.Callback mCallback; |
47 private final Activity mActivity; | 43 private final Activity mActivity; |
48 | 44 |
49 public WindowCallbackProxy(Activity activity, Window.Callback callback)
{ | 45 public WindowCallbackProxy(Activity activity, Window.Callback callback)
{ |
50 mCallback = callback; | 46 mCallback = callback; |
51 mActivity = activity; | 47 mActivity = activity; |
52 } | 48 } |
53 | 49 |
54 @Override | 50 @Override |
55 public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable { | 51 public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable { |
56 if (method.getName().equals("onWindowFocusChanged") && args.length =
= 1 | 52 if (method.getName().equals("onWindowFocusChanged") && args.length =
= 1 |
57 && args[0] instanceof Boolean) { | 53 && args[0] instanceof Boolean) { |
58 onWindowFocusChanged((boolean) args[0]); | 54 onWindowFocusChanged((boolean) args[0]); |
59 return null; | 55 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 { | 56 } else { |
64 try { | 57 try { |
65 return method.invoke(mCallback, args); | 58 return method.invoke(mCallback, args); |
66 } catch (InvocationTargetException e) { | 59 } catch (InvocationTargetException e) { |
67 // Special-case for when a method is not defined on the unde
rlying | 60 // 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 | 61 // 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 | 62 // 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 | 63 // an older SDK. The framework expects an AbstractMethodErro
r but due to |
71 // reflection it becomes wrapped inside an InvocationTargetE
xception. Undo the | 64 // reflection it becomes wrapped inside an InvocationTargetE
xception. Undo the |
72 // wrapping to signal the framework accordingly. | 65 // wrapping to signal the framework accordingly. |
73 if (e.getCause() instanceof AbstractMethodError) { | 66 if (e.getCause() instanceof AbstractMethodError) { |
74 throw e.getCause(); | 67 throw e.getCause(); |
75 } | 68 } |
76 throw e; | 69 throw e; |
77 } | 70 } |
78 } | 71 } |
79 } | 72 } |
80 | 73 |
81 public void onWindowFocusChanged(boolean hasFocus) { | 74 public void onWindowFocusChanged(boolean hasFocus) { |
82 mCallback.onWindowFocusChanged(hasFocus); | 75 mCallback.onWindowFocusChanged(hasFocus); |
83 | 76 |
84 for (WindowFocusChangedListener listener : mWindowFocusListeners) { | 77 for (WindowFocusChangedListener listener : mWindowFocusListeners) { |
85 listener.onWindowFocusChanged(mActivity, hasFocus); | 78 listener.onWindowFocusChanged(mActivity, hasFocus); |
86 } | 79 } |
87 } | 80 } |
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 } | 81 } |
98 @Override | 82 @Override |
99 public void onCreate() { | 83 public void onCreate() { |
100 super.onCreate(); | 84 super.onCreate(); |
101 ApplicationStatus.initialize(this); | 85 ApplicationStatus.initialize(this); |
102 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { | 86 registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { |
103 @Override | 87 @Override |
104 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { | 88 public void onActivityCreated(final Activity activity, Bundle savedI
nstanceState) { |
105 Window.Callback callback = activity.getWindow().getCallback(); | 89 Window.Callback callback = activity.getWindow().getCallback(); |
106 activity.getWindow().setCallback((Window.Callback) Proxy.newProx
yInstance( | 90 activity.getWindow().setCallback((Window.Callback) Proxy.newProx
yInstance( |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 145 |
162 /** | 146 /** |
163 * This must only be called for contexts whose application is a subclass of | 147 * This must only be called for contexts whose application is a subclass of |
164 * {@link BaseChromiumApplication}. | 148 * {@link BaseChromiumApplication}. |
165 */ | 149 */ |
166 @VisibleForTesting | 150 @VisibleForTesting |
167 public static void initCommandLine(Context context) { | 151 public static void initCommandLine(Context context) { |
168 ((BaseChromiumApplication) context.getApplicationContext()).initCommandL
ine(); | 152 ((BaseChromiumApplication) context.getApplicationContext()).initCommandL
ine(); |
169 }; | 153 }; |
170 } | 154 } |
OLD | NEW |