Home | History | Annotate | Download | only in input
      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 com.android.server.input;
     18 
     19 import com.android.server.wm.WindowManagerService;
     20 
     21 import android.os.Handler;
     22 import android.os.Looper;
     23 import android.os.Message;
     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 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 are 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 set 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 public abstract class InputFilter {
     99     private static final int MSG_INSTALL = 1;
    100     private static final int MSG_UNINSTALL = 2;
    101     private static final int MSG_INPUT_EVENT = 3;
    102 
    103     private final H mH;
    104     private Host mHost;
    105 
    106     // Consistency verifiers for debugging purposes.
    107     private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier =
    108             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
    109                     new InputEventConsistencyVerifier(this,
    110                             InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
    111                             "InputFilter#InboundInputEventConsistencyVerifier") : null;
    112     private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier =
    113             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
    114                     new InputEventConsistencyVerifier(this,
    115                             InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
    116                             "InputFilter#OutboundInputEventConsistencyVerifier") : null;
    117 
    118     /**
    119      * Creates the input filter.
    120      *
    121      * @param looper The looper to run callbacks on.
    122      */
    123     public InputFilter(Looper looper) {
    124         mH = new H(looper);
    125     }
    126 
    127     /**
    128      * Called when the input filter is installed.
    129      * This method is guaranteed to be non-reentrant.
    130      *
    131      * @param host The input filter host environment.
    132      */
    133     final void install(Host host) {
    134         mH.obtainMessage(MSG_INSTALL, host).sendToTarget();
    135     }
    136 
    137     /**
    138      * Called when the input filter is uninstalled.
    139      * This method is guaranteed to be non-reentrant.
    140      */
    141     final void uninstall() {
    142         mH.obtainMessage(MSG_UNINSTALL).sendToTarget();
    143     }
    144 
    145     /**
    146      * Called to enqueue the input event for filtering.
    147      * The event will be recycled after the input filter processes it.
    148      * This method is guaranteed to be non-reentrant.
    149      *
    150      * @param event The input event to enqueue.
    151      */
    152     final void filterInputEvent(InputEvent event, int policyFlags) {
    153         mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget();
    154     }
    155 
    156     /**
    157      * Sends an input event to the dispatcher.
    158      *
    159      * @param event The input event to publish.
    160      * @param policyFlags The input event policy flags.
    161      */
    162     public void sendInputEvent(InputEvent event, int policyFlags) {
    163         if (event == null) {
    164             throw new IllegalArgumentException("event must not be null");
    165         }
    166         if (mHost == null) {
    167             throw new IllegalStateException("Cannot send input event because the input filter " +
    168                     "is not installed.");
    169         }
    170         if (mOutboundInputEventConsistencyVerifier != null) {
    171             mOutboundInputEventConsistencyVerifier.onInputEvent(event, 0);
    172         }
    173         mHost.sendInputEvent(event, policyFlags);
    174     }
    175 
    176     /**
    177      * Called when an input event has been received from the dispatcher.
    178      * <p>
    179      * The default implementation sends the input event back to the dispatcher, unchanged.
    180      * </p><p>
    181      * The event will be recycled when this method returns.  If you want to keep it around,
    182      * make a copy!
    183      * </p>
    184      *
    185      * @param event The input event that was received.
    186      * @param policyFlags The input event policy flags.
    187      */
    188     public void onInputEvent(InputEvent event, int policyFlags) {
    189         sendInputEvent(event, policyFlags);
    190     }
    191 
    192     /**
    193      * Called when the filter is installed into the dispatch pipeline.
    194      * <p>
    195      * This method is called before the input filter receives any input events.
    196      * The input filter should take this opportunity to prepare itself.
    197      * </p>
    198      */
    199     public void onInstalled() {
    200     }
    201 
    202     /**
    203      * Called when the filter is uninstalled from the dispatch pipeline.
    204      * <p>
    205      * This method is called after the input filter receives its last input event.
    206      * The input filter should take this opportunity to clean up.
    207      * </p>
    208      */
    209     public void onUninstalled() {
    210     }
    211 
    212     private final class H extends Handler {
    213         public H(Looper looper) {
    214             super(looper);
    215         }
    216 
    217         @Override
    218         public void handleMessage(Message msg) {
    219             switch (msg.what) {
    220                 case MSG_INSTALL:
    221                     mHost = (Host)msg.obj;
    222                     if (mInboundInputEventConsistencyVerifier != null) {
    223                         mInboundInputEventConsistencyVerifier.reset();
    224                     }
    225                     if (mOutboundInputEventConsistencyVerifier != null) {
    226                         mOutboundInputEventConsistencyVerifier.reset();
    227                     }
    228                     onInstalled();
    229                     break;
    230 
    231                 case MSG_UNINSTALL:
    232                     try {
    233                         onUninstalled();
    234                     } finally {
    235                         mHost = null;
    236                     }
    237                     break;
    238 
    239                 case MSG_INPUT_EVENT: {
    240                     final InputEvent event = (InputEvent)msg.obj;
    241                     try {
    242                         if (mInboundInputEventConsistencyVerifier != null) {
    243                             mInboundInputEventConsistencyVerifier.onInputEvent(event, 0);
    244                         }
    245                         onInputEvent(event, msg.arg1);
    246                     } finally {
    247                         event.recycle();
    248                     }
    249                     break;
    250                 }
    251             }
    252         }
    253     }
    254 
    255     interface Host {
    256         public void sendInputEvent(InputEvent event, int policyFlags);
    257     }
    258 }
    259