blob: 36d558630da9954c1ba52e30c9cc40c70d15b179 [file] [log] [blame]
Jeff Brown0029c662011-03-30 02:25:18 -07001/*
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 Ganovc9c9a482012-07-16 08:46:07 -070017package android.view;
Jeff Brown0029c662011-03-30 02:25:18 -070018
Artur Satayevad9254c2019-12-10 17:47:54 +000019import android.compat.annotation.UnsupportedAppUsage;
Jeff Brown0029c662011-03-30 02:25:18 -070020import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070023import android.os.RemoteException;
Jeff Brown0029c662011-03-30 02:25:18 -070024
25/**
26 * Filters input events before they are dispatched to the system.
27 * <p>
28 * At most one input filter can be installed by calling
29 * {@link WindowManagerService#setInputFilter}. When an input filter is installed, the
30 * system's behavior changes as follows:
31 * <ul>
32 * <li>Input events are first delivered to the {@link WindowManagerPolicy}
Jeff Brown4532e612012-04-05 14:27:12 -070033 * interception methods before queuing as usual. This critical step takes care of managing
Jeff Brown0029c662011-03-30 02:25:18 -070034 * the power state of the device and handling wake keys.</li>
35 * <li>Input events are then asynchronously delivered to the input filter's
36 * {@link #onInputEvent(InputEvent)} method instead of being enqueued for dispatch to
37 * applications as usual. The input filter only receives input events that were
John Spurlock600cba92013-04-18 08:53:56 -040038 * generated by an input device; the input filter will not receive input events that were
Jeff Brown0029c662011-03-30 02:25:18 -070039 * injected into the system by other means, such as by instrumentation.</li>
40 * <li>The input filter processes and optionally transforms the stream of events. For example,
41 * it may transform a sequence of motion events representing an accessibility gesture into
42 * a different sequence of motion events, key presses or other system-level interactions.
43 * The input filter can send events to be dispatched by calling
44 * {@link #sendInputEvent(InputEvent)} and passing appropriate policy flags for the
45 * input event.</li>
46 * </ul>
47 * </p>
48 * <h3>The importance of input event consistency</h3>
49 * <p>
50 * The input filter mechanism is very low-level. At a minimum, it needs to ensure that it
51 * sends an internally consistent stream of input events to the dispatcher. There are
52 * very important invariants to be maintained.
53 * </p><p>
54 * For example, if a key down is sent, a corresponding key up should also be sent eventually.
55 * Likewise, for touch events, each pointer must individually go down with
56 * {@link MotionEvent#ACTION_DOWN} or {@link MotionEvent#ACTION_POINTER_DOWN} and then
57 * individually go up with {@link MotionEvent#ACTION_POINTER_UP} or {@link MotionEvent#ACTION_UP}
58 * and the sequence of pointer ids used must be consistent throughout the gesture.
59 * </p><p>
60 * Sometimes a filter may wish to cancel a previously dispatched key or motion. It should
61 * use {@link KeyEvent#FLAG_CANCELED} or {@link MotionEvent#ACTION_CANCEL} accordingly.
62 * </p><p>
63 * The input filter must take into account the fact that the input events coming from different
64 * devices or even different sources all consist of distinct streams of input.
65 * Use {@link InputEvent#getDeviceId()} and {@link InputEvent#getSource()} to identify
John Spurlock600cba92013-04-18 08:53:56 -040066 * the source of the event and its semantics. There may be multiple sources of keys,
Jeff Brown0029c662011-03-30 02:25:18 -070067 * touches and other input: they must be kept separate.
68 * </p>
69 * <h3>Policy flags</h3>
70 * <p>
71 * Input events received from the dispatcher and sent to the dispatcher have policy flags
72 * associated with them. Policy flags control some functions of the dispatcher.
73 * </p><p>
74 * The early policy interception decides whether an input event should be delivered
75 * to applications or dropped. The policy indicates its decision by setting the
Adrian Roose99bc052017-11-20 17:55:31 +010076 * {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} policy flag. The input filter may
Jeff Brown0029c662011-03-30 02:25:18 -070077 * sometimes receive events that do not have this flag set. It should take note of
78 * the fact that the policy intends to drop the event, clean up its state, and
Jeff Brown4532e612012-04-05 14:27:12 -070079 * then send appropriate cancellation events to the dispatcher if needed.
Jeff Brown0029c662011-03-30 02:25:18 -070080 * </p><p>
81 * For example, suppose the input filter is processing a gesture and one of the touch events
Adrian Roose99bc052017-11-20 17:55:31 +010082 * it receives does not have the {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} flag set.
Jeff Brown0029c662011-03-30 02:25:18 -070083 * The input filter should clear its internal state about the gesture and then send key or
84 * motion events to the dispatcher to cancel any keys or pointers that are down.
85 * </p><p>
John Spurlock600cba92013-04-18 08:53:56 -040086 * Corollary: Events that get sent to the dispatcher should usually include the
Adrian Roose99bc052017-11-20 17:55:31 +010087 * {@link WindowManagerPolicyConstants#FLAG_PASS_TO_USER} flag. Otherwise, they will be dropped!
Jeff Brown0029c662011-03-30 02:25:18 -070088 * </p><p>
Jeff Brown4532e612012-04-05 14:27:12 -070089 * It may be prudent to disable automatic key repeating for synthetic key events
Adrian Roose99bc052017-11-20 17:55:31 +010090 * by setting the {@link WindowManagerPolicyConstants#FLAG_DISABLE_KEY_REPEAT} policy flag.
Jeff Brown0029c662011-03-30 02:25:18 -070091 * </p>
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070092 *
93 * @hide
Jeff Brown0029c662011-03-30 02:25:18 -070094 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -070095public abstract class InputFilter extends IInputFilter.Stub {
Jeff Brown0029c662011-03-30 02:25:18 -070096 private static final int MSG_INSTALL = 1;
97 private static final int MSG_UNINSTALL = 2;
98 private static final int MSG_INPUT_EVENT = 3;
99
Jeff Brown21bc5c92011-02-28 18:27:14 -0800100 // Consistency verifiers for debugging purposes.
101 private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier =
102 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
103 new InputEventConsistencyVerifier(this,
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700104 InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
105 "InputFilter#InboundInputEventConsistencyVerifier") : null;
Jeff Brown21bc5c92011-02-28 18:27:14 -0800106 private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier =
107 InputEventConsistencyVerifier.isInstrumentationEnabled() ?
108 new InputEventConsistencyVerifier(this,
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700109 InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
110 "InputFilter#OutboundInputEventConsistencyVerifier") : null;
Jeff Brown21bc5c92011-02-28 18:27:14 -0800111
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700112 private final H mH;
113
114 private IInputFilterHost mHost;
115
Jeff Brown0029c662011-03-30 02:25:18 -0700116 /**
117 * Creates the input filter.
118 *
119 * @param looper The looper to run callbacks on.
120 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100121 @UnsupportedAppUsage
Jeff Brown0029c662011-03-30 02:25:18 -0700122 public InputFilter(Looper looper) {
123 mH = new H(looper);
124 }
125
126 /**
127 * Called when the input filter is installed.
128 * This method is guaranteed to be non-reentrant.
129 *
130 * @param host The input filter host environment.
131 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700132 public final void install(IInputFilterHost host) {
Jeff Brown0029c662011-03-30 02:25:18 -0700133 mH.obtainMessage(MSG_INSTALL, host).sendToTarget();
134 }
135
136 /**
137 * Called when the input filter is uninstalled.
138 * This method is guaranteed to be non-reentrant.
139 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700140 public final void uninstall() {
Jeff Brown0029c662011-03-30 02:25:18 -0700141 mH.obtainMessage(MSG_UNINSTALL).sendToTarget();
142 }
143
144 /**
145 * Called to enqueue the input event for filtering.
146 * The event will be recycled after the input filter processes it.
147 * This method is guaranteed to be non-reentrant.
148 *
149 * @param event The input event to enqueue.
150 */
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700151 final public void filterInputEvent(InputEvent event, int policyFlags) {
Jeff Brown0029c662011-03-30 02:25:18 -0700152 mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget();
153 }
154
155 /**
156 * Sends an input event to the dispatcher.
157 *
158 * @param event The input event to publish.
159 * @param policyFlags The input event policy flags.
160 */
161 public void sendInputEvent(InputEvent event, int policyFlags) {
162 if (event == null) {
163 throw new IllegalArgumentException("event must not be null");
164 }
165 if (mHost == null) {
166 throw new IllegalStateException("Cannot send input event because the input filter " +
167 "is not installed.");
168 }
Jeff Brown21bc5c92011-02-28 18:27:14 -0800169 if (mOutboundInputEventConsistencyVerifier != null) {
170 mOutboundInputEventConsistencyVerifier.onInputEvent(event, 0);
171 }
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700172 try {
173 mHost.sendInputEvent(event, policyFlags);
174 } catch (RemoteException re) {
175 /* ignore */
176 }
Jeff Brown0029c662011-03-30 02:25:18 -0700177 }
178
179 /**
180 * Called when an input event has been received from the dispatcher.
181 * <p>
182 * The default implementation sends the input event back to the dispatcher, unchanged.
183 * </p><p>
184 * The event will be recycled when this method returns. If you want to keep it around,
185 * make a copy!
186 * </p>
187 *
188 * @param event The input event that was received.
189 * @param policyFlags The input event policy flags.
190 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100191 @UnsupportedAppUsage
Jeff Brown0029c662011-03-30 02:25:18 -0700192 public void onInputEvent(InputEvent event, int policyFlags) {
193 sendInputEvent(event, policyFlags);
194 }
195
196 /**
197 * Called when the filter is installed into the dispatch pipeline.
198 * <p>
199 * This method is called before the input filter receives any input events.
200 * The input filter should take this opportunity to prepare itself.
201 * </p>
202 */
203 public void onInstalled() {
204 }
205
206 /**
207 * Called when the filter is uninstalled from the dispatch pipeline.
208 * <p>
209 * This method is called after the input filter receives its last input event.
210 * The input filter should take this opportunity to clean up.
211 * </p>
212 */
213 public void onUninstalled() {
214 }
215
216 private final class H extends Handler {
217 public H(Looper looper) {
218 super(looper);
219 }
220
221 @Override
222 public void handleMessage(Message msg) {
223 switch (msg.what) {
224 case MSG_INSTALL:
Svetoslav Ganovc9c9a482012-07-16 08:46:07 -0700225 mHost = (IInputFilterHost) msg.obj;
Jeff Brown21bc5c92011-02-28 18:27:14 -0800226 if (mInboundInputEventConsistencyVerifier != null) {
227 mInboundInputEventConsistencyVerifier.reset();
228 }
229 if (mOutboundInputEventConsistencyVerifier != null) {
230 mOutboundInputEventConsistencyVerifier.reset();
231 }
Jeff Brown0029c662011-03-30 02:25:18 -0700232 onInstalled();
233 break;
234
235 case MSG_UNINSTALL:
236 try {
237 onUninstalled();
238 } finally {
239 mHost = null;
240 }
241 break;
242
243 case MSG_INPUT_EVENT: {
244 final InputEvent event = (InputEvent)msg.obj;
245 try {
Jeff Brown21bc5c92011-02-28 18:27:14 -0800246 if (mInboundInputEventConsistencyVerifier != null) {
247 mInboundInputEventConsistencyVerifier.onInputEvent(event, 0);
248 }
Jeff Brown0029c662011-03-30 02:25:18 -0700249 onInputEvent(event, msg.arg1);
250 } finally {
251 event.recycle();
252 }
253 break;
254 }
255 }
256 }
257 }
Jeff Brown0029c662011-03-30 02:25:18 -0700258}