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