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. 6121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private InputEvent mLastEvent; 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) { 116736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName()); 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() { 14321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mLastEvent = null; 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 32521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown || action == MotionEvent.ACTION_CANCEL; 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. 576738e7e431c71777100726f6c870e47c354db1337Jeff Brown if (event == mLastEvent && nestingLevel < mLastNestingLevel 577738e7e431c71777100726f6c870e47c354db1337Jeff Brown && eventType == mLastEventType) { 57821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown return false; 57921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 58021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 58121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (nestingLevel > 0) { 58221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mLastEvent = event; 583738e7e431c71777100726f6c870e47c354db1337Jeff Brown mLastEventType = eventType; 58421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mLastNestingLevel = nestingLevel; 58521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } else { 58621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mLastEvent = null; 587738e7e431c71777100726f6c870e47c354db1337Jeff Brown mLastEventType = null; 58821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mLastNestingLevel = 0; 58921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 59021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 59121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mCurrentEvent = event; 59221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mCurrentEventType = eventType; 59321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown return true; 59421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 59521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 5968134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown private void finishEvent() { 59721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (mViolationMessage != null && mViolationMessage.length() != 0) { 5988134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown if (!mCurrentEvent.isTainted()) { 599738e7e431c71777100726f6c870e47c354db1337Jeff Brown // Write a log message only if the event was not already tainted. 600738e7e431c71777100726f6c870e47c354db1337Jeff Brown mViolationMessage.append("\n in ").append(mCaller); 601738e7e431c71777100726f6c870e47c354db1337Jeff Brown mViolationMessage.append("\n "); 602738e7e431c71777100726f6c870e47c354db1337Jeff Brown appendEvent(mViolationMessage, 0, mCurrentEvent, false); 603738e7e431c71777100726f6c870e47c354db1337Jeff Brown 604738e7e431c71777100726f6c870e47c354db1337Jeff Brown if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) { 605738e7e431c71777100726f6c870e47c354db1337Jeff Brown mViolationMessage.append("\n -- recent events --"); 606738e7e431c71777100726f6c870e47c354db1337Jeff Brown for (int i = 0; i < RECENT_EVENTS_TO_LOG; i++) { 607738e7e431c71777100726f6c870e47c354db1337Jeff Brown final int index = (mMostRecentEventIndex + RECENT_EVENTS_TO_LOG - i) 608738e7e431c71777100726f6c870e47c354db1337Jeff Brown % RECENT_EVENTS_TO_LOG; 609738e7e431c71777100726f6c870e47c354db1337Jeff Brown final InputEvent event = mRecentEvents[index]; 610738e7e431c71777100726f6c870e47c354db1337Jeff Brown if (event == null) { 611738e7e431c71777100726f6c870e47c354db1337Jeff Brown break; 612738e7e431c71777100726f6c870e47c354db1337Jeff Brown } 613738e7e431c71777100726f6c870e47c354db1337Jeff Brown mViolationMessage.append("\n "); 614738e7e431c71777100726f6c870e47c354db1337Jeff Brown appendEvent(mViolationMessage, i + 1, event, mRecentEventsUnhandled[index]); 61521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 61621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 61721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 618738e7e431c71777100726f6c870e47c354db1337Jeff Brown Log.d(mLogTag, mViolationMessage.toString()); 6198134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown 6208134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown // Taint the event so that we do not generate additional violations from it 6218134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown // further downstream. 6228134681b25dfff814ffeaad8ff70e84316c1869fJeff Brown mCurrentEvent.setTainted(true); 623738e7e431c71777100726f6c870e47c354db1337Jeff Brown } 62421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mViolationMessage.setLength(0); 62521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 62621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 62721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (RECENT_EVENTS_TO_LOG != 0) { 62821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (mRecentEvents == null) { 62921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG]; 630bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown mRecentEventsUnhandled = new boolean[RECENT_EVENTS_TO_LOG]; 63121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 63221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG; 63321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mMostRecentEventIndex = index; 63421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (mRecentEvents[index] != null) { 63521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mRecentEvents[index].recycle(); 63621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 63721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mRecentEvents[index] = mCurrentEvent.copy(); 638bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown mRecentEventsUnhandled[index] = false; 63921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 64021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 64121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mCurrentEvent = null; 64221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mCurrentEventType = null; 64321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 64421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 645bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown private static void appendEvent(StringBuilder message, int index, 646bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown InputEvent event, boolean unhandled) { 647bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown message.append(index).append(": sent at ").append(event.getEventTimeNano()); 648bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown message.append(", "); 649bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown if (unhandled) { 650bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown message.append("(unhandled) "); 651bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown } 652bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown message.append(event); 653bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown } 654bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown 65521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private void problem(String message) { 65621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (mViolationMessage == null) { 65721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mViolationMessage = new StringBuilder(); 65821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 65921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (mViolationMessage.length() == 0) { 66021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mViolationMessage.append(mCurrentEventType).append(": "); 66121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } else { 66221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mViolationMessage.append("\n "); 66321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 66421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mViolationMessage.append(message); 66521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 66621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 66721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private KeyState findKeyState(int deviceId, int source, int keyCode, boolean remove) { 66821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown KeyState last = null; 66921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown KeyState state = mKeyStateList; 67021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown while (state != null) { 67121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (state.deviceId == deviceId && state.source == source 67221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown && state.keyCode == keyCode) { 67321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (remove) { 67421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (last != null) { 67521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown last.next = state.next; 67621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } else { 67721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mKeyStateList = state.next; 67821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 67921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state.next = null; 68021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 68121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown return state; 68221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 68321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown last = state; 68421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state = state.next; 68521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 68621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown return null; 68721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 68821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 68921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private void addKeyState(int deviceId, int source, int keyCode) { 69021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown KeyState state = KeyState.obtain(deviceId, source, keyCode); 69121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state.next = mKeyStateList; 69221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mKeyStateList = state; 69321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 69421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 69521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private static final class KeyState { 69621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private static Object mRecycledListLock = new Object(); 69721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private static KeyState mRecycledList; 69821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 69921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public KeyState next; 70021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public int deviceId; 70121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public int source; 70221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public int keyCode; 703bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown public boolean unhandled; 70421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 70521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown private KeyState() { 70621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 70721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 70821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public static KeyState obtain(int deviceId, int source, int keyCode) { 70921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown KeyState state; 71021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown synchronized (mRecycledListLock) { 71121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state = mRecycledList; 71221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown if (state != null) { 71321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mRecycledList = state.next; 71421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } else { 71521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state = new KeyState(); 71621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 71721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 71821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state.deviceId = deviceId; 71921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state.source = source; 72021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown state.keyCode = keyCode; 721bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown state.unhandled = false; 72221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown return state; 72321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 72421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown 72521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown public void recycle() { 72621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown synchronized (mRecycledListLock) { 72721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown next = mRecycledList; 72821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown mRecycledList = next; 72921bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 73021bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 73121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown } 73221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown} 733