InputEventConsistencyVerifier.java revision 736c2756bf3c14ae9fef7255c119057f7a2be1ed
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
3521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The number of recent events to log when a problem is detected.
3621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Can be set to 0 to disable logging recent events but the runtime overhead of
3721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // this feature is negligible on current hardware.
3821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final int RECENT_EVENTS_TO_LOG = 5;
3921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
4021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The object to which the verifier is attached.
4121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private final Object mCaller;
4221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
4321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Consistency verifier flags.
4421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private final int mFlags;
4521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // Tag for logging which a client can set to help distinguish the output
47736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // from different verifiers since several can be active at the same time.
48736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    // If not provided defaults to the simple class name.
49736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    private final String mLogTag;
50736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
5121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The most recently checked event and the nesting level at which it was checked.
5221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // This is only set when the verifier is called from a nesting level greater than 0
5321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // so that the verifier can detect when it has been asked to verify the same event twice.
5421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // It does not make sense to examine the contents of the last event since it may have
5521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // been recycled.
5621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private InputEvent mLastEvent;
5721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mLastNestingLevel;
5821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
5921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Copy of the most recent events.
6021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private InputEvent[] mRecentEvents;
61bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean[] mRecentEventsUnhandled;
6221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mMostRecentEventIndex;
6321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
6421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Current event and its type.
6521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private InputEvent mCurrentEvent;
6621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private String mCurrentEventType;
6721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
6821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Linked list of key state objects.
6921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private KeyState mKeyStateList;
7021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
7121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Current state of the trackball.
7221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mTrackballDown;
73bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean mTrackballUnhandled;
7421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
7521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Bitfield of pointer ids that are currently down.
7621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Assumes that the largest possible pointer id is 31, which is potentially subject to change.
7721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h)
7821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamPointers;
7921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
8021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The device id and source of the current stream of touch events.
8121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamDeviceId = -1;
8221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private int mTouchEventStreamSource;
8321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
8421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Set to true when we discover that the touch event stream is inconsistent.
8521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Reset on down or cancel.
8621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mTouchEventStreamIsTainted;
8721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
88bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    // Set to true if the touch event stream is partially unhandled.
89bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private boolean mTouchEventStreamUnhandled;
90bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
9121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // Set to true if we received hover enter.
9221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean mHoverEntered;
9321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
9421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The current violation message.
9521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private StringBuilder mViolationMessage;
9621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
9721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
9821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Indicates that the verifier is intended to act on raw device input event streams.
9921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Disables certain checks for invariants that are established by the input dispatcher
10021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * itself as it delivers input events, such as key repeating behavior.
10121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
10221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static final int FLAG_RAW_DEVICE_INPUT = 1 << 0;
10321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
10421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
10521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Creates an input consistency verifier.
10621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param caller The object to which the verifier is attached.
10721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param flags Flags to the verifier, or 0 if none.
10821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
10921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public InputEventConsistencyVerifier(Object caller, int flags) {
110736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName());
111736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    }
112736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
113736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    /**
114736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * Creates an input consistency verifier.
115736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param caller The object to which the verifier is attached.
116736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param flags Flags to the verifier, or 0 if none.
117736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param logTag Tag for logging. If null defaults to the short class name.
118736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     */
119736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public InputEventConsistencyVerifier(Object caller, int flags, String logTag) {
12021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mCaller = caller;
12121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mFlags = flags;
122736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier";
12321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
12421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
12521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
12621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Determines whether the instrumentation should be enabled.
12721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @return True if it should be enabled.
12821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
12921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static boolean isInstrumentationEnabled() {
13021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return IS_ENG_BUILD;
13121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
13221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
13321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
13421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Resets the state of the input event consistency verifier.
13521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
13621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void reset() {
13721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mLastEvent = null;
13821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mLastNestingLevel = 0;
13921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTrackballDown = false;
140bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTrackballUnhandled = false;
14121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamPointers = 0;
14221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamIsTainted = false;
143bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTouchEventStreamUnhandled = false;
14421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mHoverEntered = false;
145bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
146bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        while (mKeyStateList != null) {
147bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = mKeyStateList;
148bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mKeyStateList = state.next;
149bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.recycle();
150bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
15121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
15221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
15321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
15421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks an arbitrary input event.
15521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
15621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
15721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
15821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
15921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
16021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
16121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
16221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onInputEvent(InputEvent event, int nestingLevel) {
16321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (event instanceof KeyEvent) {
16421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
16521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            onKeyEvent(keyEvent, nestingLevel);
16621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
16721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
16821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (motionEvent.isTouchEvent()) {
16921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTouchEvent(motionEvent, nestingLevel);
17021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
17121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTrackballEvent(motionEvent, nestingLevel);
17221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
17321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onGenericMotionEvent(motionEvent, nestingLevel);
17421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
17521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
17621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
17721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
17821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
17921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a key event.
18021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
18121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
18221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
18321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
18421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
18521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
18621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
18721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onKeyEvent(KeyEvent event, int nestingLevel) {
18821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (!startEvent(event, nestingLevel, "KeyEvent")) {
18921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
19021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
19121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
19221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
19321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
19421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
19521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
19621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
19721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
19821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int keyCode = event.getKeyCode();
19921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            switch (action) {
20021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_DOWN: {
20121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
20221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state != null) {
20321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // If the key is already down, ensure it is a repeat.
20421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // We don't perform this check when processing raw device input
20521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // because the input dispatcher itself is responsible for setting
20621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // the key repeat count before it delivers input events.
207bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (state.unhandled) {
208bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            state.unhandled = false;
209bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        } else if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0
21021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                && event.getRepeatCount() == 0) {
21121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but key is already down and this event "
21221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "is not a key repeat.");
21321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
21421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
21521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        addKeyState(deviceId, source, keyCode);
21621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
21721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
21821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
21921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_UP: {
22021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ true);
22121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state == null) {
22221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("ACTION_UP but key was not down.");
22321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
22421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        state.recycle();
22521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
22621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
22721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
22821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_MULTIPLE:
22921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
23021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                default:
23121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Invalid action " + KeyEvent.actionToString(action)
23221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            + " for key event.");
23321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
23421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
23521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
23621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            finishEvent(false);
23721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
23821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
23921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
24021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
24121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a trackball event.
24221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
24321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
24421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
24521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
24621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
24721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
24821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
24921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTrackballEvent(MotionEvent event, int nestingLevel) {
25021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (!startEvent(event, nestingLevel, "TrackballEvent")) {
25121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
25221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
25321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
25421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
25521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
25621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
25721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
25821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
25921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
26021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
26121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
262bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (mTrackballDown && !mTrackballUnhandled) {
26321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but trackball is already down.");
26421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
26521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = true;
266bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
26721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
26821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
26921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
27021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
27121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
27221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mTrackballDown) {
27321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_UP but trackball is not down.");
27421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
27521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = false;
276bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
27721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
27821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
27921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
28021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
28121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
28221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
28321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
28421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
28521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action " + MotionEvent.actionToString(action)
28621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                + " for trackball event.");
28721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
28821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
28921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
29021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (mTrackballDown && event.getPressure() <= 0) {
29121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is down but pressure is not greater than 0.");
29221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else if (!mTrackballDown && event.getPressure() != 0) {
29321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is up but pressure is not equal to 0.");
29421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
29521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
29621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_TRACKBALL.");
29721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
29821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
29921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            finishEvent(false);
30021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
30121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
30221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
30321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
30421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a touch event.
30521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
30621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
30721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
30821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
30921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
31021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
31121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
31221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTouchEvent(MotionEvent event, int nestingLevel) {
31321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (!startEvent(event, nestingLevel, "TouchEvent")) {
31421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
31521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
31621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
31721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int action = event.getAction();
31821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final boolean newStream = action == MotionEvent.ACTION_DOWN
31921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                || action == MotionEvent.ACTION_CANCEL;
320bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled) {
32121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (newStream) {
32221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mTouchEventStreamIsTainted = false;
323bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mTouchEventStreamUnhandled = false;
324bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mTouchEventStreamPointers = 0;
32521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
326bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                finishEvent(mTouchEventStreamIsTainted);
32721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                return;
32821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
32921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
33021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
33221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
33321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
33521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
33621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (!newStream && mTouchEventStreamDeviceId != -1
33821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && (mTouchEventStreamDeviceId != deviceId
33921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            || mTouchEventStreamSource != source)) {
34021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Touch event stream contains events from multiple sources: "
34121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + "previous device id " + mTouchEventStreamDeviceId
34221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", previous source " + Integer.toHexString(mTouchEventStreamSource)
34321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new device id " + deviceId
34421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new source " + Integer.toHexString(source));
34521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
34621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamDeviceId = deviceId;
34721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamSource = source;
34821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
34921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int pointerCount = event.getPointerCount();
35021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
35121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
35221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
35321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
35421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but pointers are already down.  "
35521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "Probably missing ACTION_UP from previous gesture.");
35621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
35721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
35821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
35921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 1 << event.getPointerId(0);
36021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
36121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
36221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
36321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
36421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
36521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
36621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
36721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE: {
36821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int expectedPointerCount =
36921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                Integer.bitCount(mTouchEventStreamPointers);
37021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (pointerCount != expectedPointerCount) {
37121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_MOVE contained " + pointerCount
37221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " pointers but there are currently "
37321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + expectedPointerCount + " pointers down.");
37421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTouchEventStreamIsTainted = true;
37521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
37621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
37721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
37821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_CANCEL:
37921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
38021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
38121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
38221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_OUTSIDE:
38321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
38421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_OUTSIDE but pointers are still down.");
38521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
38621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
38721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
38821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
38921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
39021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default: {
39121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionMasked = event.getActionMasked();
39221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionIndex = event.getActionIndex();
39321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
39421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (mTouchEventStreamPointers == 0) {
39521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN but no other pointers were down.");
39621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
39721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
39821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
39921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN index is " + actionIndex
40021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
40121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
40221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
40321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
40421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
40521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) != 0) {
40621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_DOWN specified pointer id " + id
40721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is already down.");
40821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
40921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
41021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers |= idBit;
41121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
41221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
41321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
41421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else if (actionMasked == MotionEvent.ACTION_POINTER_UP) {
41521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
41621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_UP index is " + actionIndex
41721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
41821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
41921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
42021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
42121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
42221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) == 0) {
42321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_UP specified pointer id " + id
42421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is not currently down.");
42521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
42621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
42721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers &= ~idBit;
42821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
42921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
43021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
43121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
43221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("Invalid action " + MotionEvent.actionToString(action)
43321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " for touch event.");
43421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
43521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
43621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
43721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
43821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
43921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_POINTER.");
44021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
44121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
44221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            finishEvent(false);
44321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
44421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
44521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
44621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
44721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a generic motion event.
44821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
44921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
45021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
45121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
45221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
45321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
45421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
45521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onGenericMotionEvent(MotionEvent event, int nestingLevel) {
45621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (!startEvent(event, nestingLevel, "GenericMotionEvent")) {
45721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
45821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
45921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
46121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
46221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
46421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
46521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
46621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
46721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_ENTER:
46821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
46921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = true;
47021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
47121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_MOVE:
47221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
47321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
47421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_EXIT:
47521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
47621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mHoverEntered) {
47721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_HOVER_EXIT without prior ACTION_HOVER_ENTER");
47821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
47921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = false;
48021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_SCROLL:
48221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
48321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
48421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
48621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic pointer event.");
48721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
48921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
49021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
49121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
49221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
49321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
49421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
49521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic joystick event.");
49621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
49721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
49821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
49921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
50021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            finishEvent(false);
50121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
50221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
50321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
504bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    /**
505bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * Notifies the verifier that a given event was unhandled and the rest of the
506bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * trace for the event should be ignored.
507bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * This method should only be called if the event was previously checked by
508bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * the consistency verifier using {@link #onInputEvent} and other methods.
509bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param event The event.
510bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
511bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
512bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
513bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
514bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * and both dispatching methods call into the consistency verifier.
515bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     */
516bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    public void onUnhandledEvent(InputEvent event, int nestingLevel) {
517bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (nestingLevel != mLastNestingLevel) {
518bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            return;
519bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
520bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
521bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (mRecentEventsUnhandled != null) {
522bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[mMostRecentEventIndex] = true;
523bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
524bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
525bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (event instanceof KeyEvent) {
526bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
527bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int deviceId = keyEvent.getDeviceId();
528bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int source = keyEvent.getSource();
529bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int keyCode = keyEvent.getKeyCode();
530bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
531bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (state != null) {
532bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                state.unhandled = true;
533bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
534bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        } else {
535bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
536bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (motionEvent.isTouchEvent()) {
537bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mTouchEventStreamUnhandled = true;
538bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
539bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                if (mTrackballDown) {
540bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                    mTrackballUnhandled = true;
541bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                }
542bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
543bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
544bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
545bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
54621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureMetaStateIsNormalized(int metaState) {
54721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int normalizedMetaState = KeyEvent.normalizeMetaState(metaState);
54821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (normalizedMetaState != metaState) {
54921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem(String.format("Metastate not normalized.  Was 0x%08x but expected 0x%08x.",
55021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    metaState, normalizedMetaState));
55121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
55221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
55321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
55421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensurePointerCountIsOneForThisAction(MotionEvent event) {
55521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int pointerCount = event.getPointerCount();
55621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (pointerCount != 1) {
55721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("Pointer count is " + pointerCount + " but it should always be 1 for "
55821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
55921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
56021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
56121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
56221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureHistorySizeIsZeroForThisAction(MotionEvent event) {
56321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int historySize = event.getHistorySize();
56421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (historySize != 0) {
56521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("History size is " + historySize + " but it should always be 0 for "
56621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
56721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
56821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
56921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
57021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean startEvent(InputEvent event, int nestingLevel, String eventType) {
57121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        // Ignore the event if it is already tainted.
57221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (event.isTainted()) {
57321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return false;
57421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
57521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
57621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        // Ignore the event if we already checked it at a higher nesting level.
57721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (event == mLastEvent && nestingLevel < mLastNestingLevel) {
57821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return false;
57921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
58021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
58121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (nestingLevel > 0) {
58221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastEvent = event;
58321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = nestingLevel;
58421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
58521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastEvent = null;
58621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = 0;
58721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
58821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
58921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = event;
59021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = eventType;
59121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return true;
59221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
59321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
59421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void finishEvent(boolean tainted) {
59521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage != null && mViolationMessage.length() != 0) {
59621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append("\n  in ").append(mCaller);
597bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mViolationMessage.append("\n  ");
598bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            appendEvent(mViolationMessage, 0, mCurrentEvent, false);
59921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
60021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) {
60121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mViolationMessage.append("\n  -- recent events --");
60221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                for (int i = 0; i < RECENT_EVENTS_TO_LOG; i++) {
60321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    final int index = (mMostRecentEventIndex + RECENT_EVENTS_TO_LOG - i)
60421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            % RECENT_EVENTS_TO_LOG;
60521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    final InputEvent event = mRecentEvents[index];
60621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (event == null) {
60721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
60821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
609bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                    mViolationMessage.append("\n  ");
610bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                    appendEvent(mViolationMessage, i + 1, event, mRecentEventsUnhandled[index]);
61121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
61221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
61321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
614736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov            Log.d(mLogTag, mViolationMessage.toString());
61521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.setLength(0);
61621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            tainted = true;
61721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
61821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
61921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (tainted) {
62021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            // Taint the event so that we do not generate additional violations from it
62121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            // further downstream.
62221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mCurrentEvent.setTainted(true);
62321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
62421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
62521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (RECENT_EVENTS_TO_LOG != 0) {
62621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents == null) {
62721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
628bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mRecentEventsUnhandled = new boolean[RECENT_EVENTS_TO_LOG];
62921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
63021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG;
63121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mMostRecentEventIndex = index;
63221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents[index] != null) {
63321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents[index].recycle();
63421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
63521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mRecentEvents[index] = mCurrentEvent.copy();
636bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[index] = false;
63721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
63821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
63921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = null;
64021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = null;
64121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
64221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
643bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private static void appendEvent(StringBuilder message, int index,
644bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            InputEvent event, boolean unhandled) {
645bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(index).append(": sent at ").append(event.getEventTimeNano());
646bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(", ");
647bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (unhandled) {
648bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            message.append("(unhandled) ");
649bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
650bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(event);
651bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
652bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
65321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void problem(String message) {
65421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage == null) {
65521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage = new StringBuilder();
65621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
65721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage.length() == 0) {
65821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append(mCurrentEventType).append(": ");
65921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
66021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append("\n  ");
66121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
66221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mViolationMessage.append(message);
66321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
66421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
66521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private KeyState findKeyState(int deviceId, int source, int keyCode, boolean remove) {
66621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState last = null;
66721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = mKeyStateList;
66821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        while (state != null) {
66921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (state.deviceId == deviceId && state.source == source
67021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && state.keyCode == keyCode) {
67121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (remove) {
67221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (last != null) {
67321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        last.next = state.next;
67421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
67521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mKeyStateList = state.next;
67621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
67721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state.next = null;
67821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
67921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                return state;
68021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
68121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            last = state;
68221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state = state.next;
68321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
68421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return null;
68521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
68621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
68721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void addKeyState(int deviceId, int source, int keyCode) {
68821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = KeyState.obtain(deviceId, source, keyCode);
68921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        state.next = mKeyStateList;
69021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mKeyStateList = state;
69121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
69221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
69321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final class KeyState {
69421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static Object mRecycledListLock = new Object();
69521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static KeyState mRecycledList;
69621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
69721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public KeyState next;
69821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int deviceId;
69921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int source;
70021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int keyCode;
701bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        public boolean unhandled;
70221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
70321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private KeyState() {
70421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
70521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
70621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public static KeyState obtain(int deviceId, int source, int keyCode) {
70721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            KeyState state;
70821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
70921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                state = mRecycledList;
71021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (state != null) {
71121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    mRecycledList = state.next;
71221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else {
71321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state = new KeyState();
71421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
71521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
71621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.deviceId = deviceId;
71721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.source = source;
71821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.keyCode = keyCode;
719bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.unhandled = false;
72021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return state;
72121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
72221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
72321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public void recycle() {
72421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
72521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                next = mRecycledList;
72621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecycledList = next;
72721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
72821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
72921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
73021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown}
731