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
10021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    // The current violation message.
10121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private StringBuilder mViolationMessage;
10221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
10321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
10421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Indicates that the verifier is intended to act on raw device input event streams.
10521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Disables certain checks for invariants that are established by the input dispatcher
10621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * itself as it delivers input events, such as key repeating behavior.
10721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
10821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static final int FLAG_RAW_DEVICE_INPUT = 1 << 0;
10921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
11021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
11121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Creates an input consistency verifier.
11221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param caller The object to which the verifier is attached.
11321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param flags Flags to the verifier, or 0 if none.
11421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
11521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public InputEventConsistencyVerifier(Object caller, int flags) {
116957d620267045521603051a2816d5c538ba8d0a7Michael Wright        this(caller, flags, null);
117736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    }
118736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
119736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    /**
120736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * Creates an input consistency verifier.
121736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param caller The object to which the verifier is attached.
122736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param flags Flags to the verifier, or 0 if none.
123736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     * @param logTag Tag for logging. If null defaults to the short class name.
124736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov     */
125736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public InputEventConsistencyVerifier(Object caller, int flags, String logTag) {
12621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mCaller = caller;
12721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        this.mFlags = flags;
128736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier";
12921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
13021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
13121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
13221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Determines whether the instrumentation should be enabled.
13321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @return True if it should be enabled.
13421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
13521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public static boolean isInstrumentationEnabled() {
13621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return IS_ENG_BUILD;
13721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
13821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
13921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
14021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Resets the state of the input event consistency verifier.
14121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
14221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void reset() {
14332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        mLastEventSeq = -1;
14421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mLastNestingLevel = 0;
14521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTrackballDown = false;
146bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTrackballUnhandled = false;
14721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamPointers = 0;
14821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mTouchEventStreamIsTainted = false;
149bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        mTouchEventStreamUnhandled = false;
15021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mHoverEntered = false;
151bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
152bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        while (mKeyStateList != null) {
153bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = mKeyStateList;
154bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mKeyStateList = state.next;
155bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.recycle();
156bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
15721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
15821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
15921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
16021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks an arbitrary input event.
16121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
16221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
16321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
16421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
16521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
16621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
16721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
16821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onInputEvent(InputEvent event, int nestingLevel) {
16921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (event instanceof KeyEvent) {
17021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
17121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            onKeyEvent(keyEvent, nestingLevel);
17221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
17321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
17421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (motionEvent.isTouchEvent()) {
17521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTouchEvent(motionEvent, nestingLevel);
17621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
17721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onTrackballEvent(motionEvent, nestingLevel);
17821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
17921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                onGenericMotionEvent(motionEvent, nestingLevel);
18021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
18121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
18221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
18321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
18421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
18521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a key event.
18621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
18721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
18821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
18921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
19021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
19121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
19221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
19321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onKeyEvent(KeyEvent event, int nestingLevel) {
194738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_KEY)) {
19521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
19621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
19721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
19821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
19921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
20021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
20121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
20221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
20321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
20421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int keyCode = event.getKeyCode();
20521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            switch (action) {
20621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_DOWN: {
20721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
20821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state != null) {
20921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // If the key is already down, ensure it is a repeat.
21021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // We don't perform this check when processing raw device input
21121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // because the input dispatcher itself is responsible for setting
21221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        // the key repeat count before it delivers input events.
213bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (state.unhandled) {
214bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            state.unhandled = false;
215bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        } else if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0
21621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                && event.getRepeatCount() == 0) {
21721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but key is already down and this event "
21821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "is not a key repeat.");
21921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
22021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
22121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        addKeyState(deviceId, source, keyCode);
22221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
22321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
22421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
22521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_UP: {
22621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ true);
22721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (state == null) {
22821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("ACTION_UP but key was not down.");
22921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
23021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        state.recycle();
23121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
23221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
23321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
23421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                case KeyEvent.ACTION_MULTIPLE:
23521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
23621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                default:
23721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Invalid action " + KeyEvent.actionToString(action)
23821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            + " for key event.");
23921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    break;
24021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
24121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
2428134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
24321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
24421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
24521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
24621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
24721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a trackball event.
24821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
24921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
25021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
25121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
25221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
25321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
25421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
25521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTrackballEvent(MotionEvent event, int nestingLevel) {
256738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_TRACKBALL)) {
25721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
25821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
25921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
26021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
26121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
26221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
26321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
26421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
26521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
26621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
26721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
268bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                        if (mTrackballDown && !mTrackballUnhandled) {
26921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but trackball is already down.");
27021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
27121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = true;
272bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
27321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
27421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
27521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
27621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
27721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
27821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mTrackballDown) {
27921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_UP but trackball is not down.");
28021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
28121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTrackballDown = false;
282bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                            mTrackballUnhandled = false;
28321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
28421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
28521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
28621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
28721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
28821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
28921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
29021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
29121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action " + MotionEvent.actionToString(action)
29221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                + " for trackball event.");
29321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
29421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
29521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
29621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (mTrackballDown && event.getPressure() <= 0) {
29721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is down but pressure is not greater than 0.");
29821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else if (!mTrackballDown && event.getPressure() != 0) {
29921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    problem("Trackball is up but pressure is not equal to 0.");
30021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
30121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
30221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_TRACKBALL.");
30321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
30421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
3058134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
30621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
30721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
30821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
30921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
31021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a touch event.
31121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
31221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
31321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
31421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
31521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
31621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
31721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
31821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onTouchEvent(MotionEvent event, int nestingLevel) {
319738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_TOUCH)) {
32021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
32121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
32221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
32321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int action = event.getAction();
32421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final boolean newStream = action == MotionEvent.ACTION_DOWN
325b38070caa5143ab9fd1883e0c7c879533a480bc7Victoria Lease                || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE;
326738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled)) {
327738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamIsTainted = false;
328738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamUnhandled = false;
329738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mTouchEventStreamPointers = 0;
33021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
3318134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown        if (mTouchEventStreamIsTainted) {
3328134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            event.setTainted(true);
3338134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown        }
33421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
33621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
33721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
33821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int deviceId = event.getDeviceId();
33921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
34021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
34121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (!newStream && mTouchEventStreamDeviceId != -1
34221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && (mTouchEventStreamDeviceId != deviceId
34321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            || mTouchEventStreamSource != source)) {
34421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Touch event stream contains events from multiple sources: "
34521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + "previous device id " + mTouchEventStreamDeviceId
34621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", previous source " + Integer.toHexString(mTouchEventStreamSource)
34721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new device id " + deviceId
34821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        + ", new source " + Integer.toHexString(source));
34921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
35021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamDeviceId = deviceId;
35121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mTouchEventStreamSource = source;
35221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
35321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int pointerCount = event.getPointerCount();
35421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
35521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
35621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_DOWN:
35721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
35821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_DOWN but pointers are already down.  "
35921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + "Probably missing ACTION_UP from previous gesture.");
36021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
36121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
36221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
36321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 1 << event.getPointerId(0);
36421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
36521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_UP:
36621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
36721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
36821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
36921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
37021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
37121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE: {
37221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int expectedPointerCount =
37321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                Integer.bitCount(mTouchEventStreamPointers);
37421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (pointerCount != expectedPointerCount) {
37521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_MOVE contained " + pointerCount
37621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " pointers but there are currently "
37721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + expectedPointerCount + " pointers down.");
37821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            mTouchEventStreamIsTainted = true;
37921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
38021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
38121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
38221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_CANCEL:
38321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamPointers = 0;
38421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
38521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
38621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_OUTSIDE:
38721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (mTouchEventStreamPointers != 0) {
38821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_OUTSIDE but pointers are still down.");
38921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
39021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
39121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
39221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mTouchEventStreamIsTainted = false;
39321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
39421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default: {
39521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionMasked = event.getActionMasked();
39621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        final int actionIndex = event.getActionIndex();
39721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
39821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (mTouchEventStreamPointers == 0) {
39921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN but no other pointers were down.");
40021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
40121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
40221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
40321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_DOWN index is " + actionIndex
40421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
40521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
40621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
40721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
40821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
40921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) != 0) {
41021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_DOWN specified pointer id " + id
41121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is already down.");
41221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
41321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
41421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers |= idBit;
41521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
41621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
41721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
41821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else if (actionMasked == MotionEvent.ACTION_POINTER_UP) {
41921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            if (actionIndex < 0 || actionIndex >= pointerCount) {
42021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                problem("ACTION_POINTER_UP index is " + actionIndex
42121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                        + " but the pointer count is " + pointerCount + ".");
42221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                mTouchEventStreamIsTainted = true;
42321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            } else {
42421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int id = event.getPointerId(actionIndex);
42521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                final int idBit = 1 << id;
42621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                if ((mTouchEventStreamPointers & idBit) == 0) {
42721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    problem("ACTION_POINTER_UP specified pointer id " + id
42821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                            + " which is not currently down.");
42921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamIsTainted = true;
43021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                } else {
43121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    mTouchEventStreamPointers &= ~idBit;
43221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                }
43321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            }
43421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            ensureHistorySizeIsZeroForThisAction(event);
43521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        } else {
43621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("Invalid action " + MotionEvent.actionToString(action)
43721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                                    + " for touch event.");
43821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
43921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
44021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
44121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
44221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else {
44321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                problem("Source was not SOURCE_CLASS_POINTER.");
44421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
44521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
4468134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
44721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
44821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
44921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
45021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
45121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Checks a generic motion event.
45221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param event The event.
45321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
45421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
45521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
45621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
45721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * and both dispatching methods call into the consistency verifier.
45821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
45921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    public void onGenericMotionEvent(MotionEvent event, int nestingLevel) {
460738e7e431c71777100726f6c870e47c354db1337Jeff Brown        if (!startEvent(event, nestingLevel, EVENT_TYPE_GENERIC_MOTION)) {
46121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return;
46221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
46321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        try {
46521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            ensureMetaStateIsNormalized(event.getMetaState());
46621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
46721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int action = event.getAction();
46821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int source = event.getSource();
46921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
47021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
47121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_ENTER:
47221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
47321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = true;
47421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
47521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_MOVE:
47621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
47721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
47821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_HOVER_EXIT:
47921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
48021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        if (!mHoverEntered) {
48121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                            problem("ACTION_HOVER_EXIT without prior ACTION_HOVER_ENTER");
48221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        }
48321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mHoverEntered = false;
48421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_SCROLL:
48621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensureHistorySizeIsZeroForThisAction(event);
48721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
48821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
48921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
49021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic pointer event.");
49121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
49221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
49321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
49421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                switch (action) {
49521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    case MotionEvent.ACTION_MOVE:
49621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        ensurePointerCountIsOneForThisAction(event);
49721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
49821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    default:
49921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        problem("Invalid action for generic joystick event.");
50021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        break;
50121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
50221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
50321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } finally {
5048134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            finishEvent();
50521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
50621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
50721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
508bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    /**
509bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * Notifies the verifier that a given event was unhandled and the rest of the
510bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * trace for the event should be ignored.
511bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * This method should only be called if the event was previously checked by
512bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * the consistency verifier using {@link #onInputEvent} and other methods.
513bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param event The event.
514bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * @param nestingLevel The nesting level: 0 if called from the base class,
515bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * or 1 from a subclass.  If the event was already checked by this consistency verifier
516bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * at a higher nesting level, it will not be checked again.  Used to handle the situation
517bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * where a subclass dispatching method delegates to its superclass's dispatching method
518bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     * and both dispatching methods call into the consistency verifier.
519bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown     */
520bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    public void onUnhandledEvent(InputEvent event, int nestingLevel) {
521bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (nestingLevel != mLastNestingLevel) {
522bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            return;
523bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
524bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
525bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (mRecentEventsUnhandled != null) {
526bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[mMostRecentEventIndex] = true;
527bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
528bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
529bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (event instanceof KeyEvent) {
530bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyEvent keyEvent = (KeyEvent)event;
531bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int deviceId = keyEvent.getDeviceId();
532bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int source = keyEvent.getSource();
533bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final int keyCode = keyEvent.getKeyCode();
534bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
535bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (state != null) {
536bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                state.unhandled = true;
537bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
538bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        } else {
539bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            final MotionEvent motionEvent = (MotionEvent)event;
540bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            if (motionEvent.isTouchEvent()) {
541bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mTouchEventStreamUnhandled = true;
542bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
543bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                if (mTrackballDown) {
544bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                    mTrackballUnhandled = true;
545bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                }
546bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            }
547bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
548bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
549bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
55021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureMetaStateIsNormalized(int metaState) {
55121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int normalizedMetaState = KeyEvent.normalizeMetaState(metaState);
55221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (normalizedMetaState != metaState) {
55321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem(String.format("Metastate not normalized.  Was 0x%08x but expected 0x%08x.",
55421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    metaState, normalizedMetaState));
55521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
55621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
55721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
55821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensurePointerCountIsOneForThisAction(MotionEvent event) {
55921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int pointerCount = event.getPointerCount();
56021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (pointerCount != 1) {
56121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("Pointer count is " + pointerCount + " but it should always be 1 for "
56221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
56321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
56421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
56521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
56621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void ensureHistorySizeIsZeroForThisAction(MotionEvent event) {
56721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        final int historySize = event.getHistorySize();
56821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (historySize != 0) {
56921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            problem("History size is " + historySize + " but it should always be 0 for "
57021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    + MotionEvent.actionToString(event.getAction()));
57121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
57221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
57321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
57421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private boolean startEvent(InputEvent event, int nestingLevel, String eventType) {
57521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        // Ignore the event if we already checked it at a higher nesting level.
57632cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        final int seq = event.getSequenceNumber();
57732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown        if (seq == mLastEventSeq && nestingLevel < mLastNestingLevel
578738e7e431c71777100726f6c870e47c354db1337Jeff Brown                && eventType == mLastEventType) {
57921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return false;
58021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
58121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
58221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (nestingLevel > 0) {
58332cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown            mLastEventSeq = seq;
584738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mLastEventType = eventType;
58521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = nestingLevel;
58621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
58732cbc3855c2a971aa5a801fd339fb6a37db91a1aJeff Brown            mLastEventSeq = -1;
588738e7e431c71777100726f6c870e47c354db1337Jeff Brown            mLastEventType = null;
58921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mLastNestingLevel = 0;
59021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
59121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
59221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = event;
59321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = eventType;
59421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return true;
59521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
59621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
5978134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown    private void finishEvent() {
59821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage != null && mViolationMessage.length() != 0) {
5998134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown            if (!mCurrentEvent.isTainted()) {
600738e7e431c71777100726f6c870e47c354db1337Jeff Brown                // Write a log message only if the event was not already tainted.
601738e7e431c71777100726f6c870e47c354db1337Jeff Brown                mViolationMessage.append("\n  in ").append(mCaller);
602738e7e431c71777100726f6c870e47c354db1337Jeff Brown                mViolationMessage.append("\n  ");
603738e7e431c71777100726f6c870e47c354db1337Jeff Brown                appendEvent(mViolationMessage, 0, mCurrentEvent, false);
604738e7e431c71777100726f6c870e47c354db1337Jeff Brown
605738e7e431c71777100726f6c870e47c354db1337Jeff Brown                if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) {
606738e7e431c71777100726f6c870e47c354db1337Jeff Brown                    mViolationMessage.append("\n  -- recent events --");
607738e7e431c71777100726f6c870e47c354db1337Jeff Brown                    for (int i = 0; i < RECENT_EVENTS_TO_LOG; i++) {
608738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        final int index = (mMostRecentEventIndex + RECENT_EVENTS_TO_LOG - i)
609738e7e431c71777100726f6c870e47c354db1337Jeff Brown                                % RECENT_EVENTS_TO_LOG;
610738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        final InputEvent event = mRecentEvents[index];
611738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        if (event == null) {
612738e7e431c71777100726f6c870e47c354db1337Jeff Brown                            break;
613738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        }
614738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        mViolationMessage.append("\n  ");
615738e7e431c71777100726f6c870e47c354db1337Jeff Brown                        appendEvent(mViolationMessage, i + 1, event, mRecentEventsUnhandled[index]);
61621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
61721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
61821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
619738e7e431c71777100726f6c870e47c354db1337Jeff Brown                Log.d(mLogTag, mViolationMessage.toString());
6208134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown
6218134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                // Taint the event so that we do not generate additional violations from it
6228134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                // further downstream.
6238134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown                mCurrentEvent.setTainted(true);
624738e7e431c71777100726f6c870e47c354db1337Jeff Brown            }
62521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.setLength(0);
62621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
62721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
62821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (RECENT_EVENTS_TO_LOG != 0) {
62921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents == null) {
63021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
631bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown                mRecentEventsUnhandled = new boolean[RECENT_EVENTS_TO_LOG];
63221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
63321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG;
63421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mMostRecentEventIndex = index;
63521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (mRecentEvents[index] != null) {
63621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecentEvents[index].recycle();
63721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
63821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mRecentEvents[index] = mCurrentEvent.copy();
639bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mRecentEventsUnhandled[index] = false;
64021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
64121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
64221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEvent = null;
64321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mCurrentEventType = null;
64421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
64521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
646bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    private static void appendEvent(StringBuilder message, int index,
647bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            InputEvent event, boolean unhandled) {
648bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(index).append(": sent at ").append(event.getEventTimeNano());
649bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(", ");
650bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (unhandled) {
651bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            message.append("(unhandled) ");
652bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
653bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        message.append(event);
654bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown    }
655bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
65621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void problem(String message) {
65721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage == null) {
65821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage = new StringBuilder();
65921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
66021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mViolationMessage.length() == 0) {
66121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append(mCurrentEventType).append(": ");
66221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        } else {
66321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mViolationMessage.append("\n  ");
66421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
66521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mViolationMessage.append(message);
66621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
66721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
66821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private KeyState findKeyState(int deviceId, int source, int keyCode, boolean remove) {
66921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState last = null;
67021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = mKeyStateList;
67121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        while (state != null) {
67221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            if (state.deviceId == deviceId && state.source == source
67321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    && state.keyCode == keyCode) {
67421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (remove) {
67521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    if (last != null) {
67621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        last.next = state.next;
67721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    } else {
67821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                        mKeyStateList = state.next;
67921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    }
68021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state.next = null;
68121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
68221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                return state;
68321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
68421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            last = state;
68521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state = state.next;
68621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
68721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        return null;
68821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
68921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
69021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private void addKeyState(int deviceId, int source, int keyCode) {
69121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        KeyState state = KeyState.obtain(deviceId, source, keyCode);
69221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        state.next = mKeyStateList;
69321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        mKeyStateList = state;
69421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
69521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
69621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private static final class KeyState {
69721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static Object mRecycledListLock = new Object();
69821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private static KeyState mRecycledList;
69921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
70021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public KeyState next;
70121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int deviceId;
70221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int source;
70321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public int keyCode;
704bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        public boolean unhandled;
70521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
70621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        private KeyState() {
70721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
70821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
70921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public static KeyState obtain(int deviceId, int source, int keyCode) {
71021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            KeyState state;
71121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
71221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                state = mRecycledList;
71321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                if (state != null) {
71421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    mRecycledList = state.next;
71521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                } else {
71621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    state = new KeyState();
71721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                }
71821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
71921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.deviceId = deviceId;
72021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.source = source;
72121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            state.keyCode = keyCode;
722bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            state.unhandled = false;
72321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            return state;
72421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
72521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
72621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        public void recycle() {
72721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            synchronized (mRecycledListLock) {
72821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                next = mRecycledList;
72921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                mRecycledList = next;
73021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            }
73121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
73221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    }
73321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown}
734