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