Home | History | Annotate | Download | only in view
      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 
     17 package android.view;
     18 
     19 import android.os.Handler;
     20 import android.os.Looper;
     21 import android.os.Message;
     22 import android.os.RemoteException;
     23 import android.view.IInputFilter;
     24 import android.view.InputEvent;
     25 import android.view.InputEventConsistencyVerifier;
     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}
     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  */
    100 public 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