121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown/*
221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * Copyright (C) 2010 The Android Open Source Project
321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown *
421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * you may not use this file except in compliance with the License.
621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * You may obtain a copy of the License at
721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown *
821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown *
1021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * Unless required by applicable law or agreed to in writing, software
1121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * See the License for the specific language governing permissions and
1421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * limitations under the License.
1521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown */
1621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
1721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownpackage android.view;
1821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
1921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownimport android.os.Build;
2021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownimport android.util.Log;
2121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
2221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown/**
2321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * Checks whether a sequence of input events is self-consistent.
2421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * Logs a description of each problem detected.
2521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * <p>
2621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * When a problem is detected, the event is tainted.  This mechanism prevents the same
2721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * error from being reported multiple times.
2821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * </p>
2921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown *
3021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown * @hide
3121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown */
3221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brownpublic final class InputEventConsistencyVerifier {
3321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE);
3421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
35738e7e431c71777100726f6c870e47c354db1337Jeff Brown    private static final String EVENT_TYPE_KEY = "KeyEvent";
36738e7e431c71777100726f6c870e47c354db1337Jeff Brown    private static final String EVENT_TYPE_TRACKBALL = "TrackballEvent";
37738e7e431c71777100726f6c870e47c354db1337Jeff Brown    private static final String EVENT_TYPE_TOUCH = "TouchEvent";
38738e7e431c71777100726f6c870e47c354db1337Jeff Brown    private static final String EVENT_TYPE_GENERIC_MOTION = "GenericMotionEvent";
39738e7e431c71777100726f6c870e47c354db1337Jeff Brown
4021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The number of recent events to log when a problem is detected.
4121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Can be set to 0 to disable logging recent events but the runtime overhead of
4221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // this feature is negligible on current hardware.
4321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final int RECENT_EVENTS_TO_LOG = 5;
4421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
4521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The object to which the verifier is attached.
4621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private final Object mCaller;
4721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
4821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Consistency verifier flags.
4921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private final int mFlags;
5021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
51736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // Tag for logging which a client can set to help distinguish the output
52736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // from different verifiers since several can be active at the same time.
53736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // If not provided defaults to the simple class name.
54736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    private final String mLogTag;
55736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
5621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The most recently checked event and the nesting level at which it was checked.
5721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // This is only set when the verifier is called from a nesting level greater than 0
5821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // so that the verifier can detect when it has been asked to verify the same event twice.
5921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // It does not make sense to examine the contents of the last event since it may have
6021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // been recycled.
6132cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown    private int mLastEventSeq;
62738e7e431c71777100726f6c870e47c354db1337Jeff Brown    private String mLastEventType;
6321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mLastNestingLevel;
6421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
6521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Copy of the most recent events.
6621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private InputEvent[] mRecentEvents;
67bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean[] mRecentEventsUnhandled;
6821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mMostRecentEventIndex;
6921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
7021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Current event and its type.
7121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private InputEvent mCurrentEvent;
7221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private String mCurrentEventType;
7321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
7421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Linked list of key state objects.
7521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private KeyState mKeyStateList;
7621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
7721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Current state of the trackball.
7821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mTrackballDown;
79bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean mTrackballUnhandled;
8021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
8121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Bitfield of pointer ids that are currently down.
8221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Assumes that the largest possible pointer id is 31, which is potentially subject to change.
8321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
8421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamPointers;
8521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
8621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The device id and source of the current stream of touch events.
8721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamDeviceId = -1;
8821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamSource;
8921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
9021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Set to true when we discover that the touch event stream is inconsistent.
9121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Reset on down or cancel.
9221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mTouchEventStreamIsTainted;
9321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
94bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    // Set to true if the touch event stream is partially unhandled.
95bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean mTouchEventStreamUnhandled;
96bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
9721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Set to true if we received hover enter.
9821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mHoverEntered;
9921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
1005bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright    // The bitset of buttons which we've received ACTION_BUTTON_PRESS for.
1015bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright    private int mButtonsPressed;
1025bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
10321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The current violation message.
10421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private StringBuilder mViolationMessage;
10521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
10621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
10721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Indicates that the verifier is intended to act on raw device input event streams.
10821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Disables certain checks for invariants that are established by the input dispatcher
10921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * itself as it delivers input events, such as key repeating behavior.
11021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
11121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static final int FLAG_RAW_DEVICE_INPUT = 1 << 0;
11221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
11321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
11421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Creates an input consistency verifier.
11521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param caller The object to which the verifier is attached.
11621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param flags Flags to the verifier, or 0 if none.
11721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
11821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public InputEventConsistencyVerifier(Object caller, int flags) {
119957d620267045521603051a2816d5c538ba8d0a7Michael Wright        this(caller, flags, null);
120736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    }
121736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
122736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    /**
123736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * Creates an input consistency verifier.
124736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param caller The object to which the verifier is attached.
125736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param flags Flags to the verifier, or 0 if none.
126736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param logTag Tag for logging. If null defaults to the short class name.
127736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     */
128736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public InputEventConsistencyVerifier(Object caller, int flags, String logTag) {
12921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mCaller = caller;
13021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mFlags = flags;
131736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier";
13221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
13321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
13421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
13521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Determines whether the instrumentation should be enabled.
13621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @return True if it should be enabled.
13721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
13821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static boolean isInstrumentationEnabled() {
13921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return IS_ENG_BUILD;
14021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
14121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
14221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
14321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Resets the state of the input event consistency verifier.
14421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
14521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void reset() {
14632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        mLastEventSeq = -1;
14721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mLastNestingLevel = 0;
14821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTrackballDown = false;
149bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTrackballUnhandled = false;
15021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamPointers = 0;
15121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamIsTainted = false;
152bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTouchEventStreamUnhandled = false;
15321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mHoverEntered = false;
1545bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright        mButtonsPressed = 0;
155bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
156bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        while (mKeyStateList != null) {
157bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = mKeyStateList;
158bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mKeyStateList = state.next;
159bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.recycle();
160bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
16121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
16221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
16321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
16421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks an arbitrary input event.
16521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
16621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
16721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
16821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
16921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
17021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
17121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
17221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onInputEvent(InputEvent event, int nestingLevel) {
17321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (event instanceof KeyEvent) {
17421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
17521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            onKeyEvent(keyEvent, nestingLevel);
17621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
17721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
17821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (motionEvent.isTouchEvent()) {
17921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTouchEvent(motionEvent, nestingLevel);
18021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
18121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTrackballEvent(motionEvent, nestingLevel);
18221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
18321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onGenericMotionEvent(motionEvent, nestingLevel);
18421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
18521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
18621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
18721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
18821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
18921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a key event.
19021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
19121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
19221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
19321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
19421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
19521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
19621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
19721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onKeyEvent(KeyEvent event, int nestingLevel) {
198738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_KEY)) {
19921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
20021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
20121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
20221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
20321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
20421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
20521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
20621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
20721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
20821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int keyCode = event.getKeyCode();
20921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            switch (action) {
21021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_DOWN: {
21121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
21221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state != null) {
21321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // If the key is already down, ensure it is a repeat.
21421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // We don't perform this check when processing raw device input
21521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // because the input dispatcher itself is responsible for setting
21621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // the key repeat count before it delivers input events.
217bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (state.unhandled) {
218bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            state.unhandled = false;
219bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        } else if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0
22021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                && event.getRepeatCount() == 0) {
22121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but key is already down and this event "
22221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "is not a key repeat.");
22321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
22421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
22521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        addKeyState(deviceId, source, keyCode);
22621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
22721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
22821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
22921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_UP: {
23021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ true);
23121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state == null) {
23221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("ACTION_UP but key was not down.");
23321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
23421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        state.recycle();
23521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
23621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
23721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
23821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_MULTIPLE:
23921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
24021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                default:
24121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Invalid action " + KeyEvent.actionToString(action)
24221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            + " for key event.");
24321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
24421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
24521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
2468134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
24721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
24821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
24921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
25021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
25121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a trackball event.
25221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
25321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
25421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
25521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
25621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
25721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
25821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
25921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTrackballEvent(MotionEvent event, int nestingLevel) {
260738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_TRACKBALL)) {
26121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
26221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
26321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
26421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
26521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
26621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
26721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
26821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
26921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
27021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
27121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
272bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (mTrackballDown && !mTrackballUnhandled) {
27321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but trackball is already down.");
27421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
27521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = true;
276bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
27721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
27821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
27921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
28021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
28121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
28221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mTrackballDown) {
28321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_UP but trackball is not down.");
28421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
28521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = false;
286bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
28721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
28821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
28921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
29021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
29121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
29221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
29321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
29421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
29521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action " + MotionEvent.actionToString(action)
29621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                + " for trackball event.");
29721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
29821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
29921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
30021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (mTrackballDown && event.getPressure() <= 0) {
30121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is down but pressure is not greater than 0.");
30221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else if (!mTrackballDown && event.getPressure() != 0) {
30321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is up but pressure is not equal to 0.");
30421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
30521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
30621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_TRACKBALL.");
30721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
30821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
3098134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
31021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
31121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
31221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
31321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
31421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a touch event.
31521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
31621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
31721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
31821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
31921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
32021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
32121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
32221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTouchEvent(MotionEvent event, int nestingLevel) {
323738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_TOUCH)) {
32421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
32521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
32621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
32721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int action = event.getAction();
32821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final boolean newStream = action == MotionEvent.ACTION_DOWN
329b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE;
330738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled)) {
331738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamIsTainted = false;
332738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamUnhandled = false;
333738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamPointers = 0;
33421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
3358134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown        if (mTouchEventStreamIsTainted) {
3368134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            event.setTainted(true);
3378134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown        }
33821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
34021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
34121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
34221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
34321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
34421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
34521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (!newStream && mTouchEventStreamDeviceId != -1
34621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && (mTouchEventStreamDeviceId != deviceId
34721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            || mTouchEventStreamSource != source)) {
34821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Touch event stream contains events from multiple sources: "
34921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + "previous device id " + mTouchEventStreamDeviceId
35021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", previous source " + Integer.toHexString(mTouchEventStreamSource)
35121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new device id " + deviceId
35221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new source " + Integer.toHexString(source));
35321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
35421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamDeviceId = deviceId;
35521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamSource = source;
35621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
35721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int pointerCount = event.getPointerCount();
35821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
35921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
36021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
36121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
36221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but pointers are already down.  "
36321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "Probably missing ACTION_UP from previous gesture.");
36421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
36521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
36621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
36721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 1 << event.getPointerId(0);
36821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
36921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
37021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
37121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
37221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
37321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
37421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
37521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE: {
37621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int expectedPointerCount =
37721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                Integer.bitCount(mTouchEventStreamPointers);
37821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (pointerCount != expectedPointerCount) {
37921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_MOVE contained " + pointerCount
38021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " pointers but there are currently "
38121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + expectedPointerCount + " pointers down.");
38221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTouchEventStreamIsTainted = true;
38321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
38421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
38521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
38621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_CANCEL:
38721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
38821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
38921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
39021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_OUTSIDE:
39121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
39221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_OUTSIDE but pointers are still down.");
39321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
39421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
39521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
39621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
39721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
39821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default: {
39921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionMasked = event.getActionMasked();
40021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionIndex = event.getActionIndex();
40121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
40221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (mTouchEventStreamPointers == 0) {
40321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN but no other pointers were down.");
40421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
40521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
40621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
40721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN index is " + actionIndex
40821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
40921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
41021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
41121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
41221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
41321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) != 0) {
41421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_DOWN specified pointer id " + id
41521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is already down.");
41621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
41721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
41821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers |= idBit;
41921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
42021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
42121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
42221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else if (actionMasked == MotionEvent.ACTION_POINTER_UP) {
42321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
42421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_UP index is " + actionIndex
42521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
42621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
42721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
42821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
42921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
43021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) == 0) {
43121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_UP specified pointer id " + id
43221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is not currently down.");
43321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
43421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
43521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers &= ~idBit;
43621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
43721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
43821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
43921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
44021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("Invalid action " + MotionEvent.actionToString(action)
44121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " for touch event.");
44221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
44321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
44421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
44521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
44621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
44721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_POINTER.");
44821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
44921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
4508134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
45121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
45221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
45321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
45421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
45521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a generic motion event.
45621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
45721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
45821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
45921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
46021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
46121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
46221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
46321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onGenericMotionEvent(MotionEvent event, int nestingLevel) {
464738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_GENERIC_MOTION)) {
46521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
46621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
46721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
46921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
47021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
47121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
47221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
4735bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright            final int buttonState = event.getButtonState();
4745bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright            final int actionButton = event.getActionButton();
47521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
47621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
47721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_ENTER:
47821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
47921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = true;
48021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_MOVE:
48221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
48321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_EXIT:
48521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
48621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mHoverEntered) {
48721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_HOVER_EXIT without prior ACTION_HOVER_ENTER");
48821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
48921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = false;
49021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
49121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_SCROLL:
49221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
49321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
49421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
4955bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                    case MotionEvent.ACTION_BUTTON_PRESS:
4965bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        ensureActionButtonIsNonZeroForThisAction(event);
4975bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if ((mButtonsPressed & actionButton) != 0) {
4985bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            problem("Action button for ACTION_BUTTON_PRESS event is " +
4995bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    actionButton + ", but it has already been pressed and " +
5005bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "has yet to be released.");
5015bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5025bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
5035bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        mButtonsPressed |= actionButton;
5045bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // The system will automatically mirror the stylus buttons onto the button
5055bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // state as the old set of generic buttons for apps targeting pre-M. If
5065bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // it looks this has happened, go ahead and set the generic buttons as
5075bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // pressed to prevent spurious errors.
5085bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY &&
5095bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                (buttonState & MotionEvent.BUTTON_SECONDARY) != 0) {
5105bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            mButtonsPressed |= MotionEvent.BUTTON_SECONDARY;
5115bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY &&
5125bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                (buttonState & MotionEvent.BUTTON_TERTIARY) != 0) {
5135bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            mButtonsPressed |= MotionEvent.BUTTON_TERTIARY;
5145bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5155bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
5165bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if (mButtonsPressed != buttonState) {
5175bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            problem(String.format("Reported button state differs from " +
5185bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "expected button state based on press and release events. " +
5195bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "Is 0x%08x but expected 0x%08x.",
5205bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    buttonState, mButtonsPressed));
5215bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5225bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        break;
5235bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                    case MotionEvent.ACTION_BUTTON_RELEASE:
5245bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        ensureActionButtonIsNonZeroForThisAction(event);
5255bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if ((mButtonsPressed & actionButton) != actionButton) {
5265bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            problem("Action button for ACTION_BUTTON_RELEASE event is " +
5275bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    actionButton + ", but it was either never pressed or has " +
5285bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "already been released.");
5295bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5305bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
5315bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        mButtonsPressed &= ~actionButton;
5325bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // The system will automatically mirror the stylus buttons onto the button
5335bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // state as the old set of generic buttons for apps targeting pre-M. If
5345bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // it looks this has happened, go ahead and set the generic buttons as
5355bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        // released to prevent spurious errors.
5365bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY &&
5375bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                (buttonState & MotionEvent.BUTTON_SECONDARY) == 0) {
5385bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            mButtonsPressed &= ~MotionEvent.BUTTON_SECONDARY;
5395bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY &&
5405bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                (buttonState & MotionEvent.BUTTON_TERTIARY) == 0) {
5415bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            mButtonsPressed &= ~MotionEvent.BUTTON_TERTIARY;
5425bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5435bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
5445bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        if (mButtonsPressed != buttonState) {
5455bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                            problem(String.format("Reported button state differs from " +
5465bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "expected button state based on press and release events. " +
5475bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    "Is 0x%08x but expected 0x%08x.",
5485bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                                    buttonState, mButtonsPressed));
5495bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        }
5505bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                        break;
55121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
55221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic pointer event.");
55321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
55421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
55521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
55621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
55721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
55821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
55921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
56021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
56121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic joystick event.");
56221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
56321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
56421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
56521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
5668134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
56721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
56821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
56921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
570bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    /**
571bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * Notifies the verifier that a given event was unhandled and the rest of the
572bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * trace for the event should be ignored.
573bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * This method should only be called if the event was previously checked by
574bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * the consistency verifier using {@link #onInputEvent} and other methods.
575bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param event The event.
576bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
577bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
578bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
579bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
580bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * and both dispatching methods call into the consistency verifier.
581bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     */
582bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    public void onUnhandledEvent(InputEvent event, int nestingLevel) {
583bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (nestingLevel != mLastNestingLevel) {
584bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            return;
585bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
586bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
587bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (mRecentEventsUnhandled != null) {
588bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[mMostRecentEventIndex] = true;
589bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
590bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
591bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (event instanceof KeyEvent) {
592bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
593bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int deviceId = keyEvent.getDeviceId();
594bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int source = keyEvent.getSource();
595bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int keyCode = keyEvent.getKeyCode();
596bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
597bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (state != null) {
598bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                state.unhandled = true;
599bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
600bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        } else {
601bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
602bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (motionEvent.isTouchEvent()) {
603bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mTouchEventStreamUnhandled = true;
604bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
605bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                if (mTrackballDown) {
606bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                    mTrackballUnhandled = true;
607bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                }
608bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
609bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
610bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
611bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
61221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureMetaStateIsNormalized(int metaState) {
61321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int normalizedMetaState = KeyEvent.normalizeMetaState(metaState);
61421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (normalizedMetaState != metaState) {
61521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem(String.format("Metastate not normalized.  Was 0x%08x but expected 0x%08x.",
61621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    metaState, normalizedMetaState));
61721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
61821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
61921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
62021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensurePointerCountIsOneForThisAction(MotionEvent event) {
62121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int pointerCount = event.getPointerCount();
62221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (pointerCount != 1) {
62321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("Pointer count is " + pointerCount + " but it should always be 1 for "
62421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
62521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
62621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
62721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
6285bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright    private void ensureActionButtonIsNonZeroForThisAction(MotionEvent event) {
6295bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright        final int actionButton = event.getActionButton();
6305bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright        if (actionButton == 0) {
6315bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright            problem("No action button set. Action button should always be non-zero for " +
6325bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright                    MotionEvent.actionToString(event.getAction()));
6335bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
6345bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright        }
6355bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright    }
6365bd69e6e6164c59a0423edd0d5243fc8c07e6af3Michael Wright
63721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureHistorySizeIsZeroForThisAction(MotionEvent event) {
63821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int historySize = event.getHistorySize();
63921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (historySize != 0) {
64021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("History size is " + historySize + " but it should always be 0 for "
64121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
64221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
64321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
64421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
64521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean startEvent(InputEvent event, int nestingLevel, String eventType) {
64621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        // Ignore the event if we already checked it at a higher nesting level.
64732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        final int seq = event.getSequenceNumber();
64832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        if (seq == mLastEventSeq && nestingLevel < mLastNestingLevel
649738e7e431c71777100726f6c870e47c354db1337Jeff Brown                && eventType == mLastEventType) {
65021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return false;
65121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
65221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
65321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (nestingLevel > 0) {
65432cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown            mLastEventSeq = seq;
655738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mLastEventType = eventType;
65621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = nestingLevel;
65721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
65832cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown            mLastEventSeq = -1;
659738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mLastEventType = null;
66021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = 0;
66121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
66221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
66321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = event;
66421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = eventType;
66521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return true;
66621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
66721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
6688134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown    private void finishEvent() {
66921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage != null && mViolationMessage.length() != 0) {
6708134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            if (!mCurrentEvent.isTainted()) {
671738e7e431c71777100726f6c870e47c354db1337Jeff Brown                // Write a log message only if the event was not already tainted.
672738e7e431c71777100726f6c870e47c354db1337Jeff Brown                mViolationMessage.append("\n  in ").append(mCaller);
673738e7e431c71777100726f6c870e47c354db1337Jeff Brown                mViolationMessage.append("\n  ");
674738e7e431c71777100726f6c870e47c354db1337Jeff Brown                appendEvent(mViolationMessage, 0, mCurrentEvent, false);
675738e7e431c71777100726f6c870e47c354db1337Jeff Brown
676738e7e431c71777100726f6c870e47c354db1337Jeff Brown                if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) {
677738e7e431c71777100726f6c870e47c354db1337Jeff Brown                    mViolationMessage.append("\n  -- recent events --");
678738e7e431c71777100726f6c870e47c354db1337Jeff Brown                    for (int i = 0; i < RECENT_EVENTS_TO_LOG; i++) {
679738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        final int index = (mMostRecentEventIndex + RECENT_EVENTS_TO_LOG - i)
680738e7e431c71777100726f6c870e47c354db1337Jeff Brown                                % RECENT_EVENTS_TO_LOG;
681738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        final InputEvent event = mRecentEvents[index];
682738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        if (event == null) {
683738e7e431c71777100726f6c870e47c354db1337Jeff Brown                            break;
684738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        }
685738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        mViolationMessage.append("\n  ");
686738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        appendEvent(mViolationMessage, i + 1, event, mRecentEventsUnhandled[index]);
68721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
68821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
68921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
690738e7e431c71777100726f6c870e47c354db1337Jeff Brown                Log.d(mLogTag, mViolationMessage.toString());
6918134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown
6928134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                // Taint the event so that we do not generate additional violations from it
6938134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                // further downstream.
6948134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                mCurrentEvent.setTainted(true);
695738e7e431c71777100726f6c870e47c354db1337Jeff Brown            }
69621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.setLength(0);
69721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
69821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
69921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (RECENT_EVENTS_TO_LOG != 0) {
70021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents == null) {
70121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
702bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mRecentEventsUnhandled = new boolean[RECENT_EVENTS_TO_LOG];
70321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
70421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG;
70521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mMostRecentEventIndex = index;
70621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents[index] != null) {
70721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents[index].recycle();
70821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
70921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mRecentEvents[index] = mCurrentEvent.copy();
710bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[index] = false;
71121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
71221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
71321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = null;
71421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = null;
71521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
71621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
717bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private static void appendEvent(StringBuilder message, int index,
718bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            InputEvent event, boolean unhandled) {
719bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(index).append(": sent at ").append(event.getEventTimeNano());
720bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(", ");
721bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (unhandled) {
722bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            message.append("(unhandled) ");
723bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
724bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(event);
725bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
726bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
72721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void problem(String message) {
72821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage == null) {
72921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage = new StringBuilder();
73021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
73121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage.length() == 0) {
73221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append(mCurrentEventType).append(": ");
73321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
73421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append("\n  ");
73521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
73621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mViolationMessage.append(message);
73721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
73821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
73921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private KeyState findKeyState(int deviceId, int source, int keyCode, boolean remove) {
74021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState last = null;
74121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = mKeyStateList;
74221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        while (state != null) {
74321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (state.deviceId == deviceId && state.source == source
74421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && state.keyCode == keyCode) {
74521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (remove) {
74621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (last != null) {
74721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        last.next = state.next;
74821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
74921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mKeyStateList = state.next;
75021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
75121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state.next = null;
75221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
75321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                return state;
75421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
75521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            last = state;
75621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state = state.next;
75721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
75821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return null;
75921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
76021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
76121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void addKeyState(int deviceId, int source, int keyCode) {
76221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = KeyState.obtain(deviceId, source, keyCode);
76321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        state.next = mKeyStateList;
76421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mKeyStateList = state;
76521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
76621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
76721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final class KeyState {
76821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static Object mRecycledListLock = new Object();
76921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static KeyState mRecycledList;
77021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
77121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public KeyState next;
77221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int deviceId;
77321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int source;
77421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int keyCode;
775bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        public boolean unhandled;
77621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
77721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private KeyState() {
77821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
77921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
78021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public static KeyState obtain(int deviceId, int source, int keyCode) {
78121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            KeyState state;
78221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
78321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                state = mRecycledList;
78421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (state != null) {
78521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    mRecycledList = state.next;
78621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else {
78721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state = new KeyState();
78821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
78921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
79021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.deviceId = deviceId;
79121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.source = source;
79221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.keyCode = keyCode;
793bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.unhandled = false;
79421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return state;
79521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
79621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
79721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public void recycle() {
79821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
79921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                next = mRecycledList;
80021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecycledList = next;
80121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
80221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
80321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
80421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown}
805