Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 17 | package android.view; |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 18 | |
| 19 | import android.os.Handler; |
| 20 | import android.os.Looper; |
| 21 | import android.os.Message; |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 22 | import android.os.RemoteException; |
| 23 | import android.view.IInputFilter; |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 24 | import android.view.InputEvent; |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 25 | import android.view.InputEventConsistencyVerifier; |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 26 | import android.view.KeyEvent; |
| 27 | import android.view.MotionEvent; |
| 28 | import android.view.WindowManagerPolicy; |
| 29 | |
| 30 | /** |
| 31 | * Filters input events before they are dispatched to the system. |
| 32 | * <p> |
| 33 | * At most one input filter can be installed by calling |
| 34 | * {@link WindowManagerService#setInputFilter}. When an input filter is installed, the |
| 35 | * system's behavior changes as follows: |
| 36 | * <ul> |
| 37 | * <li>Input events are first delivered to the {@link WindowManagerPolicy} |
Jeff Brown | 4532e61 | 2012-04-05 14:27:12 -0700 | [diff] [blame] | 38 | * interception methods before queuing as usual. This critical step takes care of managing |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 39 | * the power state of the device and handling wake keys.</li> |
| 40 | * <li>Input events are then asynchronously delivered to the input filter's |
| 41 | * {@link #onInputEvent(InputEvent)} method instead of being enqueued for dispatch to |
| 42 | * applications as usual. The input filter only receives input events that were |
John Spurlock | 600cba9 | 2013-04-18 08:53:56 -0400 | [diff] [blame] | 43 | * generated by an input device; the input filter will not receive input events that were |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 44 | * injected into the system by other means, such as by instrumentation.</li> |
| 45 | * <li>The input filter processes and optionally transforms the stream of events. For example, |
| 46 | * it may transform a sequence of motion events representing an accessibility gesture into |
| 47 | * a different sequence of motion events, key presses or other system-level interactions. |
| 48 | * The input filter can send events to be dispatched by calling |
| 49 | * {@link #sendInputEvent(InputEvent)} and passing appropriate policy flags for the |
| 50 | * input event.</li> |
| 51 | * </ul> |
| 52 | * </p> |
| 53 | * <h3>The importance of input event consistency</h3> |
| 54 | * <p> |
| 55 | * The input filter mechanism is very low-level. At a minimum, it needs to ensure that it |
| 56 | * sends an internally consistent stream of input events to the dispatcher. There are |
| 57 | * very important invariants to be maintained. |
| 58 | * </p><p> |
| 59 | * For example, if a key down is sent, a corresponding key up should also be sent eventually. |
| 60 | * Likewise, for touch events, each pointer must individually go down with |
| 61 | * {@link MotionEvent#ACTION_DOWN} or {@link MotionEvent#ACTION_POINTER_DOWN} and then |
| 62 | * individually go up with {@link MotionEvent#ACTION_POINTER_UP} or {@link MotionEvent#ACTION_UP} |
| 63 | * and the sequence of pointer ids used must be consistent throughout the gesture. |
| 64 | * </p><p> |
| 65 | * Sometimes a filter may wish to cancel a previously dispatched key or motion. It should |
| 66 | * use {@link KeyEvent#FLAG_CANCELED} or {@link MotionEvent#ACTION_CANCEL} accordingly. |
| 67 | * </p><p> |
| 68 | * The input filter must take into account the fact that the input events coming from different |
| 69 | * devices or even different sources all consist of distinct streams of input. |
| 70 | * Use {@link InputEvent#getDeviceId()} and {@link InputEvent#getSource()} to identify |
John Spurlock | 600cba9 | 2013-04-18 08:53:56 -0400 | [diff] [blame] | 71 | * the source of the event and its semantics. There may be multiple sources of keys, |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 72 | * touches and other input: they must be kept separate. |
| 73 | * </p> |
| 74 | * <h3>Policy flags</h3> |
| 75 | * <p> |
| 76 | * Input events received from the dispatcher and sent to the dispatcher have policy flags |
| 77 | * associated with them. Policy flags control some functions of the dispatcher. |
| 78 | * </p><p> |
| 79 | * The early policy interception decides whether an input event should be delivered |
| 80 | * to applications or dropped. The policy indicates its decision by setting the |
| 81 | * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} policy flag. The input filter may |
| 82 | * sometimes receive events that do not have this flag set. It should take note of |
| 83 | * the fact that the policy intends to drop the event, clean up its state, and |
Jeff Brown | 4532e61 | 2012-04-05 14:27:12 -0700 | [diff] [blame] | 84 | * then send appropriate cancellation events to the dispatcher if needed. |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 85 | * </p><p> |
| 86 | * For example, suppose the input filter is processing a gesture and one of the touch events |
| 87 | * it receives does not have the {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag set. |
| 88 | * The input filter should clear its internal state about the gesture and then send key or |
| 89 | * motion events to the dispatcher to cancel any keys or pointers that are down. |
| 90 | * </p><p> |
John Spurlock | 600cba9 | 2013-04-18 08:53:56 -0400 | [diff] [blame] | 91 | * Corollary: Events that get sent to the dispatcher should usually include the |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 92 | * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag. Otherwise, they will be dropped! |
| 93 | * </p><p> |
Jeff Brown | 4532e61 | 2012-04-05 14:27:12 -0700 | [diff] [blame] | 94 | * It may be prudent to disable automatic key repeating for synthetic key events |
| 95 | * by setting the {@link WindowManagerPolicy#FLAG_DISABLE_KEY_REPEAT} policy flag. |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 96 | * </p> |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 97 | * |
| 98 | * @hide |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 99 | */ |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 100 | public abstract class InputFilter extends IInputFilter.Stub { |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 101 | private static final int MSG_INSTALL = 1; |
| 102 | private static final int MSG_UNINSTALL = 2; |
| 103 | private static final int MSG_INPUT_EVENT = 3; |
| 104 | |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 105 | // Consistency verifiers for debugging purposes. |
| 106 | private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier = |
| 107 | InputEventConsistencyVerifier.isInstrumentationEnabled() ? |
| 108 | new InputEventConsistencyVerifier(this, |
Svetoslav Ganov | 736c275 | 2011-04-22 18:30:36 -0700 | [diff] [blame] | 109 | InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, |
| 110 | "InputFilter#InboundInputEventConsistencyVerifier") : null; |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 111 | private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier = |
| 112 | InputEventConsistencyVerifier.isInstrumentationEnabled() ? |
| 113 | new InputEventConsistencyVerifier(this, |
Svetoslav Ganov | 736c275 | 2011-04-22 18:30:36 -0700 | [diff] [blame] | 114 | InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, |
| 115 | "InputFilter#OutboundInputEventConsistencyVerifier") : null; |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 116 | |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 117 | private final H mH; |
| 118 | |
| 119 | private IInputFilterHost mHost; |
| 120 | |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 121 | /** |
| 122 | * Creates the input filter. |
| 123 | * |
| 124 | * @param looper The looper to run callbacks on. |
| 125 | */ |
| 126 | public InputFilter(Looper looper) { |
| 127 | mH = new H(looper); |
| 128 | } |
| 129 | |
| 130 | /** |
| 131 | * Called when the input filter is installed. |
| 132 | * This method is guaranteed to be non-reentrant. |
| 133 | * |
| 134 | * @param host The input filter host environment. |
| 135 | */ |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 136 | public final void install(IInputFilterHost host) { |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 137 | mH.obtainMessage(MSG_INSTALL, host).sendToTarget(); |
| 138 | } |
| 139 | |
| 140 | /** |
| 141 | * Called when the input filter is uninstalled. |
| 142 | * This method is guaranteed to be non-reentrant. |
| 143 | */ |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 144 | public final void uninstall() { |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 145 | mH.obtainMessage(MSG_UNINSTALL).sendToTarget(); |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | * Called to enqueue the input event for filtering. |
| 150 | * The event will be recycled after the input filter processes it. |
| 151 | * This method is guaranteed to be non-reentrant. |
| 152 | * |
| 153 | * @param event The input event to enqueue. |
| 154 | */ |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 155 | final public void filterInputEvent(InputEvent event, int policyFlags) { |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 156 | mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget(); |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * Sends an input event to the dispatcher. |
| 161 | * |
| 162 | * @param event The input event to publish. |
| 163 | * @param policyFlags The input event policy flags. |
| 164 | */ |
| 165 | public void sendInputEvent(InputEvent event, int policyFlags) { |
| 166 | if (event == null) { |
| 167 | throw new IllegalArgumentException("event must not be null"); |
| 168 | } |
| 169 | if (mHost == null) { |
| 170 | throw new IllegalStateException("Cannot send input event because the input filter " + |
| 171 | "is not installed."); |
| 172 | } |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 173 | if (mOutboundInputEventConsistencyVerifier != null) { |
| 174 | mOutboundInputEventConsistencyVerifier.onInputEvent(event, 0); |
| 175 | } |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 176 | try { |
| 177 | mHost.sendInputEvent(event, policyFlags); |
| 178 | } catch (RemoteException re) { |
| 179 | /* ignore */ |
| 180 | } |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | /** |
| 184 | * Called when an input event has been received from the dispatcher. |
| 185 | * <p> |
| 186 | * The default implementation sends the input event back to the dispatcher, unchanged. |
| 187 | * </p><p> |
| 188 | * The event will be recycled when this method returns. If you want to keep it around, |
| 189 | * make a copy! |
| 190 | * </p> |
| 191 | * |
| 192 | * @param event The input event that was received. |
| 193 | * @param policyFlags The input event policy flags. |
| 194 | */ |
| 195 | public void onInputEvent(InputEvent event, int policyFlags) { |
| 196 | sendInputEvent(event, policyFlags); |
| 197 | } |
| 198 | |
| 199 | /** |
| 200 | * Called when the filter is installed into the dispatch pipeline. |
| 201 | * <p> |
| 202 | * This method is called before the input filter receives any input events. |
| 203 | * The input filter should take this opportunity to prepare itself. |
| 204 | * </p> |
| 205 | */ |
| 206 | public void onInstalled() { |
| 207 | } |
| 208 | |
| 209 | /** |
| 210 | * Called when the filter is uninstalled from the dispatch pipeline. |
| 211 | * <p> |
| 212 | * This method is called after the input filter receives its last input event. |
| 213 | * The input filter should take this opportunity to clean up. |
| 214 | * </p> |
| 215 | */ |
| 216 | public void onUninstalled() { |
| 217 | } |
| 218 | |
| 219 | private final class H extends Handler { |
| 220 | public H(Looper looper) { |
| 221 | super(looper); |
| 222 | } |
| 223 | |
| 224 | @Override |
| 225 | public void handleMessage(Message msg) { |
| 226 | switch (msg.what) { |
| 227 | case MSG_INSTALL: |
Svetoslav Ganov | c9c9a48 | 2012-07-16 08:46:07 -0700 | [diff] [blame] | 228 | mHost = (IInputFilterHost) msg.obj; |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 229 | if (mInboundInputEventConsistencyVerifier != null) { |
| 230 | mInboundInputEventConsistencyVerifier.reset(); |
| 231 | } |
| 232 | if (mOutboundInputEventConsistencyVerifier != null) { |
| 233 | mOutboundInputEventConsistencyVerifier.reset(); |
| 234 | } |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 235 | onInstalled(); |
| 236 | break; |
| 237 | |
| 238 | case MSG_UNINSTALL: |
| 239 | try { |
| 240 | onUninstalled(); |
| 241 | } finally { |
| 242 | mHost = null; |
| 243 | } |
| 244 | break; |
| 245 | |
| 246 | case MSG_INPUT_EVENT: { |
| 247 | final InputEvent event = (InputEvent)msg.obj; |
| 248 | try { |
Jeff Brown | 21bc5c9 | 2011-02-28 18:27:14 -0800 | [diff] [blame] | 249 | if (mInboundInputEventConsistencyVerifier != null) { |
| 250 | mInboundInputEventConsistencyVerifier.onInputEvent(event, 0); |
| 251 | } |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 252 | onInputEvent(event, msg.arg1); |
| 253 | } finally { |
| 254 | event.recycle(); |
| 255 | } |
| 256 | break; |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | } |
Jeff Brown | 0029c66 | 2011-03-30 02:25:18 -0700 | [diff] [blame] | 261 | } |