Index: base/android/java/src/org/chromium/base/BaseChromiumApplication.java |
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java |
index 2946f6fb0004ad2da54e4e5985f4f75029ff2901..c87d02d7d33e8fbee7b44f87472af8af74d8973e 100644 |
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java |
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java |
@@ -11,6 +11,10 @@ import android.os.Bundle; |
import android.view.KeyEvent; |
import android.view.Window; |
+import java.lang.reflect.InvocationHandler; |
+import java.lang.reflect.Method; |
+import java.lang.reflect.Proxy; |
+ |
/** |
* Basic application functionality that should be shared among all browser applications. |
*/ |
@@ -30,66 +34,94 @@ public class BaseChromiumApplication extends Application { |
private ObserverList<WindowFocusChangedListener> mWindowFocusListeners = |
new ObserverList<WindowFocusChangedListener>(); |
+ /** |
+ * Intercepts calls to an existing Window.Callback. Most invocations are passed on directly |
+ * to the composed Window.Callback but enables intercepting/manipulating others. |
+ * |
+ * This is used to relay window focus changes throughout the app and remedy a bug in the |
+ * appcompat library. |
+ */ |
+ private class WindowCallbackProxy implements InvocationHandler { |
+ private final Window.Callback mCallback; |
+ private final Activity mActivity; |
+ |
+ public WindowCallbackProxy(Activity activity, Window.Callback callback) { |
+ mCallback = callback; |
+ mActivity = activity; |
+ } |
+ |
+ @Override |
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
+ if (method.getName().equals("onWindowFocusChanged") && args.length == 1 |
+ && args[0] instanceof Boolean) { |
+ onWindowFocusChanged((boolean) args[0]); |
+ return null; |
+ } else if (method.getName().equals("dispatchKeyEvent") && args.length == 1 |
+ && args[0] instanceof KeyEvent) { |
+ return dispatchKeyEvent((KeyEvent) args[0]); |
+ } else { |
+ return method.invoke(mCallback, args); |
+ } |
+ } |
+ |
+ public void onWindowFocusChanged(boolean hasFocus) { |
+ mCallback.onWindowFocusChanged(hasFocus); |
+ |
+ for (WindowFocusChangedListener listener : mWindowFocusListeners) { |
+ listener.onWindowFocusChanged(mActivity, hasFocus); |
+ } |
+ } |
+ |
+ public boolean dispatchKeyEvent(KeyEvent event) { |
+ // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals |
+ // KEYCODE_MENU. (see b/20529185) |
+ if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatchKeyEvent(event)) { |
+ return true; |
+ } |
+ return mCallback.dispatchKeyEvent(event); |
+ } |
+ } |
@Override |
public void onCreate() { |
super.onCreate(); |
ApplicationStatus.initialize(this); |
- |
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { |
@Override |
public void onActivityCreated(final Activity activity, Bundle savedInstanceState) { |
Window.Callback callback = activity.getWindow().getCallback(); |
- activity.getWindow().setCallback(new WindowCallbackWrapper(callback) { |
- @Override |
- public void onWindowFocusChanged(boolean hasFocus) { |
- super.onWindowFocusChanged(hasFocus); |
- |
- for (WindowFocusChangedListener listener : mWindowFocusListeners) { |
- listener.onWindowFocusChanged(activity, hasFocus); |
- } |
- } |
- |
- @Override |
- public boolean dispatchKeyEvent(KeyEvent event) { |
- // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals |
- // KEYCODE_MENU. (see b/20529185) |
- if (event.getKeyCode() == KeyEvent.KEYCODE_MENU |
- && activity.dispatchKeyEvent(event)) { |
- return true; |
- } |
- return super.dispatchKeyEvent(event); |
- } |
- }); |
+ activity.getWindow().setCallback((Window.Callback) Proxy.newProxyInstance( |
+ Window.Callback.class.getClassLoader(), new Class[] {Window.Callback.class}, |
+ new WindowCallbackProxy(activity, callback))); |
} |
@Override |
public void onActivityDestroyed(Activity activity) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
@Override |
public void onActivityPaused(Activity activity) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
@Override |
public void onActivityResumed(Activity activity) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
@Override |
public void onActivitySaveInstanceState(Activity activity, Bundle outState) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
@Override |
public void onActivityStarted(Activity activity) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
@Override |
public void onActivityStopped(Activity activity) { |
- assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper; |
+ assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass()); |
} |
}); |
} |