summaryrefslogtreecommitdiff
path: root/android/view/InputFilter.java
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
committerJustin Klaassen <justinklaassen@google.com>2017-09-15 17:58:39 -0400
commit10d07c88d69cc64f73a069163e7ea5ba2519a099 (patch)
tree8dbd149eb350320a29c3d10e7ad3201de1c5cbee /android/view/InputFilter.java
parent677516fb6b6f207d373984757d3d9450474b6b00 (diff)
downloadandroid-28-10d07c88d69cc64f73a069163e7ea5ba2519a099.tar.gz
Import Android SDK Platform PI [4335822]
/google/data/ro/projects/android/fetch_artifact \ --bid 4335822 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4335822.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: Ic8f04be005a71c2b9abeaac754d8da8d6f9a2c32
Diffstat (limited to 'android/view/InputFilter.java')
-rw-r--r--android/view/InputFilter.java255
1 files changed, 255 insertions, 0 deletions
diff --git a/android/view/InputFilter.java b/android/view/InputFilter.java
new file mode 100644
index 00000000..d0dab400
--- /dev/null
+++ b/android/view/InputFilter.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+/**
+ * Filters input events before they are dispatched to the system.
+ * <p>
+ * At most one input filter can be installed by calling
+ * {@link WindowManagerService#setInputFilter}. When an input filter is installed, the
+ * system's behavior changes as follows:
+ * <ul>
+ * <li>Input events are first delivered to the {@link WindowManagerPolicy}
+ * interception methods before queuing as usual. This critical step takes care of managing
+ * the power state of the device and handling wake keys.</li>
+ * <li>Input events are then asynchronously delivered to the input filter's
+ * {@link #onInputEvent(InputEvent)} method instead of being enqueued for dispatch to
+ * applications as usual. The input filter only receives input events that were
+ * generated by an input device; the input filter will not receive input events that were
+ * injected into the system by other means, such as by instrumentation.</li>
+ * <li>The input filter processes and optionally transforms the stream of events. For example,
+ * it may transform a sequence of motion events representing an accessibility gesture into
+ * a different sequence of motion events, key presses or other system-level interactions.
+ * The input filter can send events to be dispatched by calling
+ * {@link #sendInputEvent(InputEvent)} and passing appropriate policy flags for the
+ * input event.</li>
+ * </ul>
+ * </p>
+ * <h3>The importance of input event consistency</h3>
+ * <p>
+ * The input filter mechanism is very low-level. At a minimum, it needs to ensure that it
+ * sends an internally consistent stream of input events to the dispatcher. There are
+ * very important invariants to be maintained.
+ * </p><p>
+ * For example, if a key down is sent, a corresponding key up should also be sent eventually.
+ * Likewise, for touch events, each pointer must individually go down with
+ * {@link MotionEvent#ACTION_DOWN} or {@link MotionEvent#ACTION_POINTER_DOWN} and then
+ * individually go up with {@link MotionEvent#ACTION_POINTER_UP} or {@link MotionEvent#ACTION_UP}
+ * and the sequence of pointer ids used must be consistent throughout the gesture.
+ * </p><p>
+ * Sometimes a filter may wish to cancel a previously dispatched key or motion. It should
+ * use {@link KeyEvent#FLAG_CANCELED} or {@link MotionEvent#ACTION_CANCEL} accordingly.
+ * </p><p>
+ * The input filter must take into account the fact that the input events coming from different
+ * devices or even different sources all consist of distinct streams of input.
+ * Use {@link InputEvent#getDeviceId()} and {@link InputEvent#getSource()} to identify
+ * the source of the event and its semantics. There may be multiple sources of keys,
+ * touches and other input: they must be kept separate.
+ * </p>
+ * <h3>Policy flags</h3>
+ * <p>
+ * Input events received from the dispatcher and sent to the dispatcher have policy flags
+ * associated with them. Policy flags control some functions of the dispatcher.
+ * </p><p>
+ * The early policy interception decides whether an input event should be delivered
+ * to applications or dropped. The policy indicates its decision by setting the
+ * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} policy flag. The input filter may
+ * sometimes receive events that do not have this flag set. It should take note of
+ * the fact that the policy intends to drop the event, clean up its state, and
+ * then send appropriate cancellation events to the dispatcher if needed.
+ * </p><p>
+ * For example, suppose the input filter is processing a gesture and one of the touch events
+ * it receives does not have the {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag set.
+ * The input filter should clear its internal state about the gesture and then send key or
+ * motion events to the dispatcher to cancel any keys or pointers that are down.
+ * </p><p>
+ * Corollary: Events that get sent to the dispatcher should usually include the
+ * {@link WindowManagerPolicy#FLAG_PASS_TO_USER} flag. Otherwise, they will be dropped!
+ * </p><p>
+ * It may be prudent to disable automatic key repeating for synthetic key events
+ * by setting the {@link WindowManagerPolicy#FLAG_DISABLE_KEY_REPEAT} policy flag.
+ * </p>
+ *
+ * @hide
+ */
+public abstract class InputFilter extends IInputFilter.Stub {
+ private static final int MSG_INSTALL = 1;
+ private static final int MSG_UNINSTALL = 2;
+ private static final int MSG_INPUT_EVENT = 3;
+
+ // Consistency verifiers for debugging purposes.
+ private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier =
+ InputEventConsistencyVerifier.isInstrumentationEnabled() ?
+ new InputEventConsistencyVerifier(this,
+ InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
+ "InputFilter#InboundInputEventConsistencyVerifier") : null;
+ private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier =
+ InputEventConsistencyVerifier.isInstrumentationEnabled() ?
+ new InputEventConsistencyVerifier(this,
+ InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT,
+ "InputFilter#OutboundInputEventConsistencyVerifier") : null;
+
+ private final H mH;
+
+ private IInputFilterHost mHost;
+
+ /**
+ * Creates the input filter.
+ *
+ * @param looper The looper to run callbacks on.
+ */
+ public InputFilter(Looper looper) {
+ mH = new H(looper);
+ }
+
+ /**
+ * Called when the input filter is installed.
+ * This method is guaranteed to be non-reentrant.
+ *
+ * @param host The input filter host environment.
+ */
+ public final void install(IInputFilterHost host) {
+ mH.obtainMessage(MSG_INSTALL, host).sendToTarget();
+ }
+
+ /**
+ * Called when the input filter is uninstalled.
+ * This method is guaranteed to be non-reentrant.
+ */
+ public final void uninstall() {
+ mH.obtainMessage(MSG_UNINSTALL).sendToTarget();
+ }
+
+ /**
+ * Called to enqueue the input event for filtering.
+ * The event will be recycled after the input filter processes it.
+ * This method is guaranteed to be non-reentrant.
+ *
+ * @param event The input event to enqueue.
+ */
+ final public void filterInputEvent(InputEvent event, int policyFlags) {
+ mH.obtainMessage(MSG_INPUT_EVENT, policyFlags, 0, event).sendToTarget();
+ }
+
+ /**
+ * Sends an input event to the dispatcher.
+ *
+ * @param event The input event to publish.
+ * @param policyFlags The input event policy flags.
+ */
+ public void sendInputEvent(InputEvent event, int policyFlags) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mHost == null) {
+ throw new IllegalStateException("Cannot send input event because the input filter " +
+ "is not installed.");
+ }
+ if (mOutboundInputEventConsistencyVerifier != null) {
+ mOutboundInputEventConsistencyVerifier.onInputEvent(event, 0);
+ }
+ try {
+ mHost.sendInputEvent(event, policyFlags);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+
+ /**
+ * Called when an input event has been received from the dispatcher.
+ * <p>
+ * The default implementation sends the input event back to the dispatcher, unchanged.
+ * </p><p>
+ * The event will be recycled when this method returns. If you want to keep it around,
+ * make a copy!
+ * </p>
+ *
+ * @param event The input event that was received.
+ * @param policyFlags The input event policy flags.
+ */
+ public void onInputEvent(InputEvent event, int policyFlags) {
+ sendInputEvent(event, policyFlags);
+ }
+
+ /**
+ * Called when the filter is installed into the dispatch pipeline.
+ * <p>
+ * This method is called before the input filter receives any input events.
+ * The input filter should take this opportunity to prepare itself.
+ * </p>
+ */
+ public void onInstalled() {
+ }
+
+ /**
+ * Called when the filter is uninstalled from the dispatch pipeline.
+ * <p>
+ * This method is called after the input filter receives its last input event.
+ * The input filter should take this opportunity to clean up.
+ * </p>
+ */
+ public void onUninstalled() {
+ }
+
+ private final class H extends Handler {
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_INSTALL:
+ mHost = (IInputFilterHost) msg.obj;
+ if (mInboundInputEventConsistencyVerifier != null) {
+ mInboundInputEventConsistencyVerifier.reset();
+ }
+ if (mOutboundInputEventConsistencyVerifier != null) {
+ mOutboundInputEventConsistencyVerifier.reset();
+ }
+ onInstalled();
+ break;
+
+ case MSG_UNINSTALL:
+ try {
+ onUninstalled();
+ } finally {
+ mHost = null;
+ }
+ break;
+
+ case MSG_INPUT_EVENT: {
+ final InputEvent event = (InputEvent)msg.obj;
+ try {
+ if (mInboundInputEventConsistencyVerifier != null) {
+ mInboundInputEventConsistencyVerifier.onInputEvent(event, 0);
+ }
+ onInputEvent(event, msg.arg1);
+ } finally {
+ event.recycle();
+ }
+ break;
+ }
+ }
+ }
+ }
+}