| 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 |