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 17package android.view; 18 19import android.os.Handler; 20import android.os.Looper; 21import android.os.Message; 22import android.os.RemoteException; 23import android.view.IInputFilter; 24import android.view.InputEvent; 25import android.view.InputEventConsistencyVerifier; 26import android.view.KeyEvent; 27import android.view.MotionEvent; 28import 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} 38 * interception methods before queuing as usual. This critical step takes care of managing 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 43 * generated by an input device; the input filter will not receive input events that were 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 71 * the source of the event and its semantics. There may be multiple sources of keys, 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 84 * then send appropriate cancellation events to the dispatcher if needed. 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> 91 * Corollary: Events that get sent to the dispatcher should usually include the 92 * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag. Otherwise, they will be dropped! 93 * </p><p> 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. 96 * </p> 97 * 98 * @hide 99 */ 100public abstract class InputFilter extends IInputFilter.Stub { 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 105 // Consistency verifiers for debugging purposes. 106 private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier = 107 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 108 new InputEventConsistencyVerifier(this, 109 InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, 110 "InputFilter#InboundInputEventConsistencyVerifier") : null; 111 private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier = 112 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 113 new InputEventConsistencyVerifier(this, 114 InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, 115 "InputFilter#OutboundInputEventConsistencyVerifier") : null; 116 117 private final H mH; 118 119 private IInputFilterHost mHost; 120 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 */ 136 public final void install(IInputFilterHost host) { 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 */ 144 public final void uninstall() { 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 */ 155 final public void filterInputEvent(InputEvent event, int policyFlags) { 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 } 173 if (mOutboundInputEventConsistencyVerifier != null) { 174 mOutboundInputEventConsistencyVerifier.onInputEvent(event, 0); 175 } 176 try { 177 mHost.sendInputEvent(event, policyFlags); 178 } catch (RemoteException re) { 179 /* ignore */ 180 } 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: 228 mHost = (IInputFilterHost) msg.obj; 229 if (mInboundInputEventConsistencyVerifier != null) { 230 mInboundInputEventConsistencyVerifier.reset(); 231 } 232 if (mOutboundInputEventConsistencyVerifier != null) { 233 mOutboundInputEventConsistencyVerifier.reset(); 234 } 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 { 249 if (mInboundInputEventConsistencyVerifier != null) { 250 mInboundInputEventConsistencyVerifier.onInputEvent(event, 0); 251 } 252 onInputEvent(event, msg.arg1); 253 } finally { 254 event.recycle(); 255 } 256 break; 257 } 258 } 259 } 260 } 261} 262