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