Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f026b0f authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Track unhandled input events in consistency verifiers."

parents dee1640a bbdc50b1
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -590,8 +590,14 @@ public class GestureDetector {
            mHandler.removeMessages(SHOW_PRESS);
            mHandler.removeMessages(SHOW_PRESS);
            mHandler.removeMessages(LONG_PRESS);
            mHandler.removeMessages(LONG_PRESS);
            break;
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_CANCEL:
            cancel();
            cancel();
            break;
        }

        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 0);
        }
        }
        return handled;
        return handled;
    }
    }
+83 −6
Original line number Original line Diff line number Diff line
@@ -54,6 +54,7 @@ public final class InputEventConsistencyVerifier {


    // Copy of the most recent events.
    // Copy of the most recent events.
    private InputEvent[] mRecentEvents;
    private InputEvent[] mRecentEvents;
    private boolean[] mRecentEventsUnhandled;
    private int mMostRecentEventIndex;
    private int mMostRecentEventIndex;


    // Current event and its type.
    // Current event and its type.
@@ -65,6 +66,7 @@ public final class InputEventConsistencyVerifier {


    // Current state of the trackball.
    // Current state of the trackball.
    private boolean mTrackballDown;
    private boolean mTrackballDown;
    private boolean mTrackballUnhandled;


    // Bitfield of pointer ids that are currently down.
    // Bitfield of pointer ids that are currently down.
    // Assumes that the largest possible pointer id is 31, which is potentially subject to change.
    // Assumes that the largest possible pointer id is 31, which is potentially subject to change.
@@ -79,6 +81,9 @@ public final class InputEventConsistencyVerifier {
    // Reset on down or cancel.
    // Reset on down or cancel.
    private boolean mTouchEventStreamIsTainted;
    private boolean mTouchEventStreamIsTainted;


    // Set to true if the touch event stream is partially unhandled.
    private boolean mTouchEventStreamUnhandled;

    // Set to true if we received hover enter.
    // Set to true if we received hover enter.
    private boolean mHoverEntered;
    private boolean mHoverEntered;


@@ -117,9 +122,17 @@ public final class InputEventConsistencyVerifier {
        mLastEvent = null;
        mLastEvent = null;
        mLastNestingLevel = 0;
        mLastNestingLevel = 0;
        mTrackballDown = false;
        mTrackballDown = false;
        mTrackballUnhandled = false;
        mTouchEventStreamPointers = 0;
        mTouchEventStreamPointers = 0;
        mTouchEventStreamIsTainted = false;
        mTouchEventStreamIsTainted = false;
        mTouchEventStreamUnhandled = false;
        mHoverEntered = false;
        mHoverEntered = false;

        while (mKeyStateList != null) {
            final KeyState state = mKeyStateList;
            mKeyStateList = state.next;
            state.recycle();
        }
    }
    }


    /**
    /**
@@ -176,7 +189,9 @@ public final class InputEventConsistencyVerifier {
                        // We don't perform this check when processing raw device input
                        // We don't perform this check when processing raw device input
                        // because the input dispatcher itself is responsible for setting
                        // because the input dispatcher itself is responsible for setting
                        // the key repeat count before it delivers input events.
                        // the key repeat count before it delivers input events.
                        if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0
                        if (state.unhandled) {
                            state.unhandled = false;
                        } else if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0
                                && event.getRepeatCount() == 0) {
                                && event.getRepeatCount() == 0) {
                            problem("ACTION_DOWN but key is already down and this event "
                            problem("ACTION_DOWN but key is already down and this event "
                                    + "is not a key repeat.");
                                    + "is not a key repeat.");
@@ -229,10 +244,11 @@ public final class InputEventConsistencyVerifier {
            if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                switch (action) {
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                    case MotionEvent.ACTION_DOWN:
                        if (mTrackballDown) {
                        if (mTrackballDown && !mTrackballUnhandled) {
                            problem("ACTION_DOWN but trackball is already down.");
                            problem("ACTION_DOWN but trackball is already down.");
                        } else {
                        } else {
                            mTrackballDown = true;
                            mTrackballDown = true;
                            mTrackballUnhandled = false;
                        }
                        }
                        ensureHistorySizeIsZeroForThisAction(event);
                        ensureHistorySizeIsZeroForThisAction(event);
                        ensurePointerCountIsOneForThisAction(event);
                        ensurePointerCountIsOneForThisAction(event);
@@ -242,6 +258,7 @@ public final class InputEventConsistencyVerifier {
                            problem("ACTION_UP but trackball is not down.");
                            problem("ACTION_UP but trackball is not down.");
                        } else {
                        } else {
                            mTrackballDown = false;
                            mTrackballDown = false;
                            mTrackballUnhandled = false;
                        }
                        }
                        ensureHistorySizeIsZeroForThisAction(event);
                        ensureHistorySizeIsZeroForThisAction(event);
                        ensurePointerCountIsOneForThisAction(event);
                        ensurePointerCountIsOneForThisAction(event);
@@ -285,11 +302,13 @@ public final class InputEventConsistencyVerifier {
        final int action = event.getAction();
        final int action = event.getAction();
        final boolean newStream = action == MotionEvent.ACTION_DOWN
        final boolean newStream = action == MotionEvent.ACTION_DOWN
                || action == MotionEvent.ACTION_CANCEL;
                || action == MotionEvent.ACTION_CANCEL;
        if (mTouchEventStreamIsTainted) {
        if (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled) {
            if (newStream) {
            if (newStream) {
                mTouchEventStreamIsTainted = false;
                mTouchEventStreamIsTainted = false;
                mTouchEventStreamUnhandled = false;
                mTouchEventStreamPointers = 0;
            } else {
            } else {
                finishEvent(true);
                finishEvent(mTouchEventStreamIsTainted);
                return;
                return;
            }
            }
        }
        }
@@ -467,6 +486,48 @@ public final class InputEventConsistencyVerifier {
        }
        }
    }
    }


    /**
     * Notifies the verifier that a given event was unhandled and the rest of the
     * trace for the event should be ignored.
     * This method should only be called if the event was previously checked by
     * the consistency verifier using {@link #onInputEvent} and other methods.
     * @param event The event.
     * @param nestingLevel The nesting level: 0 if called from the base class,
     * or 1 from a subclass.  If the event was already checked by this consistency verifier
     * at a higher nesting level, it will not be checked again.  Used to handle the situation
     * where a subclass dispatching method delegates to its superclass's dispatching method
     * and both dispatching methods call into the consistency verifier.
     */
    public void onUnhandledEvent(InputEvent event, int nestingLevel) {
        if (nestingLevel != mLastNestingLevel) {
            return;
        }

        if (mRecentEventsUnhandled != null) {
            mRecentEventsUnhandled[mMostRecentEventIndex] = true;
        }

        if (event instanceof KeyEvent) {
            final KeyEvent keyEvent = (KeyEvent)event;
            final int deviceId = keyEvent.getDeviceId();
            final int source = keyEvent.getSource();
            final int keyCode = keyEvent.getKeyCode();
            final KeyState state = findKeyState(deviceId, source, keyCode, /*remove*/ false);
            if (state != null) {
                state.unhandled = true;
            }
        } else {
            final MotionEvent motionEvent = (MotionEvent)event;
            if (motionEvent.isTouchEvent()) {
                mTouchEventStreamUnhandled = true;
            } else if ((motionEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                if (mTrackballDown) {
                    mTrackballUnhandled = true;
                }
            }
        }
    }

    private void ensureMetaStateIsNormalized(int metaState) {
    private void ensureMetaStateIsNormalized(int metaState) {
        final int normalizedMetaState = KeyEvent.normalizeMetaState(metaState);
        final int normalizedMetaState = KeyEvent.normalizeMetaState(metaState);
        if (normalizedMetaState != metaState) {
        if (normalizedMetaState != metaState) {
@@ -518,7 +579,8 @@ public final class InputEventConsistencyVerifier {
    private void finishEvent(boolean tainted) {
    private void finishEvent(boolean tainted) {
        if (mViolationMessage != null && mViolationMessage.length() != 0) {
        if (mViolationMessage != null && mViolationMessage.length() != 0) {
            mViolationMessage.append("\n  in ").append(mCaller);
            mViolationMessage.append("\n  in ").append(mCaller);
            mViolationMessage.append("\n  ").append(mCurrentEvent);
            mViolationMessage.append("\n  ");
            appendEvent(mViolationMessage, 0, mCurrentEvent, false);


            if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) {
            if (RECENT_EVENTS_TO_LOG != 0 && mRecentEvents != null) {
                mViolationMessage.append("\n  -- recent events --");
                mViolationMessage.append("\n  -- recent events --");
@@ -529,7 +591,8 @@ public final class InputEventConsistencyVerifier {
                    if (event == null) {
                    if (event == null) {
                        break;
                        break;
                    }
                    }
                    mViolationMessage.append("\n  ").append(i + 1).append(": ").append(event);
                    mViolationMessage.append("\n  ");
                    appendEvent(mViolationMessage, i + 1, event, mRecentEventsUnhandled[index]);
                }
                }
            }
            }


@@ -547,6 +610,7 @@ public final class InputEventConsistencyVerifier {
        if (RECENT_EVENTS_TO_LOG != 0) {
        if (RECENT_EVENTS_TO_LOG != 0) {
            if (mRecentEvents == null) {
            if (mRecentEvents == null) {
                mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
                mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
                mRecentEventsUnhandled = new boolean[RECENT_EVENTS_TO_LOG];
            }
            }
            final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG;
            final int index = (mMostRecentEventIndex + 1) % RECENT_EVENTS_TO_LOG;
            mMostRecentEventIndex = index;
            mMostRecentEventIndex = index;
@@ -554,12 +618,23 @@ public final class InputEventConsistencyVerifier {
                mRecentEvents[index].recycle();
                mRecentEvents[index].recycle();
            }
            }
            mRecentEvents[index] = mCurrentEvent.copy();
            mRecentEvents[index] = mCurrentEvent.copy();
            mRecentEventsUnhandled[index] = false;
        }
        }


        mCurrentEvent = null;
        mCurrentEvent = null;
        mCurrentEventType = null;
        mCurrentEventType = null;
    }
    }


    private static void appendEvent(StringBuilder message, int index,
            InputEvent event, boolean unhandled) {
        message.append(index).append(": sent at ").append(event.getEventTimeNano());
        message.append(", ");
        if (unhandled) {
            message.append("(unhandled) ");
        }
        message.append(event);
    }

    private void problem(String message) {
    private void problem(String message) {
        if (mViolationMessage == null) {
        if (mViolationMessage == null) {
            mViolationMessage = new StringBuilder();
            mViolationMessage = new StringBuilder();
@@ -608,6 +683,7 @@ public final class InputEventConsistencyVerifier {
        public int deviceId;
        public int deviceId;
        public int source;
        public int source;
        public int keyCode;
        public int keyCode;
        public boolean unhandled;


        private KeyState() {
        private KeyState() {
        }
        }
@@ -625,6 +701,7 @@ public final class InputEventConsistencyVerifier {
            state.deviceId = deviceId;
            state.deviceId = deviceId;
            state.source = source;
            state.source = source;
            state.keyCode = keyCode;
            state.keyCode = keyCode;
            state.unhandled = false;
            return state;
            return state;
        }
        }


+8 −4
Original line number Original line Diff line number Diff line
@@ -183,15 +183,15 @@ public class ScaleGestureDetector {
        }
        }


        final int action = event.getActionMasked();
        final int action = event.getActionMasked();
        boolean handled = true;


        if (action == MotionEvent.ACTION_DOWN) {
        if (action == MotionEvent.ACTION_DOWN) {
            reset(); // Start fresh
            reset(); // Start fresh
        }
        }


        if (mInvalidGesture) return false;
        boolean handled = true;

        if (mInvalidGesture) {
        if (!mGestureInProgress) {
            handled = false;
        } else if (!mGestureInProgress) {
            switch (action) {
            switch (action) {
            case MotionEvent.ACTION_DOWN: {
            case MotionEvent.ACTION_DOWN: {
                mActiveId0 = event.getPointerId(0);
                mActiveId0 = event.getPointerId(0);
@@ -467,6 +467,10 @@ public class ScaleGestureDetector {
                break;
                break;
            }
            }
        }
        }

        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return handled;
        return handled;
    }
    }


+39 −11
Original line number Original line Diff line number Diff line
@@ -4614,8 +4614,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
            return true;
            return true;
        }
        }


        return event.dispatch(this, mAttachInfo != null
        if (event.dispatch(this, mAttachInfo != null
                ? mAttachInfo.mKeyDispatchState : null, this);
                ? mAttachInfo.mKeyDispatchState : null, this)) {
            return true;
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false;
    }
    }


    /**
    /**
@@ -4640,16 +4647,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }
        }


        if (!onFilterTouchEventForSecurity(event)) {
        if (onFilterTouchEventForSecurity(event)) {
            return false;
        }

            //noinspection SimplifiableIfStatement
            //noinspection SimplifiableIfStatement
            if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
            if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
                    mOnTouchListener.onTouch(this, event)) {
                    mOnTouchListener.onTouch(this, event)) {
                return true;
                return true;
            }
            }
        return onTouchEvent(event);

            if (onTouchEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false;
    }
    }


    /**
    /**
@@ -4682,7 +4695,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
        }
        }


        //Log.i("view", "view=" + this + ", " + event.toString());
        //Log.i("view", "view=" + this + ", " + event.toString());
        return onTrackballEvent(event);
        if (onTrackballEvent(event)) {
            return true;
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false;
    }
    }


    /**
    /**
@@ -4723,7 +4743,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
                && mOnGenericMotionListener.onGenericMotion(this, event)) {
                && mOnGenericMotionListener.onGenericMotion(this, event)) {
            return true;
            return true;
        }
        }
        return onGenericMotionEvent(event);

        if (onGenericMotionEvent(event)) {
            return true;
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false;
    }
    }


    /**
    /**
+151 −132
Original line number Original line Diff line number Diff line
@@ -1131,9 +1131,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
        }


        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
            return super.dispatchKeyEvent(event);
            if (super.dispatchKeyEvent(event)) {
                return true;
            }
        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
            return mFocused.dispatchKeyEvent(event);
            if (mFocused.dispatchKeyEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
        }
        }
        return false;
        return false;
    }
    }
@@ -1161,9 +1169,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        }
        }


        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
            return super.dispatchTrackballEvent(event);
            if (super.dispatchTrackballEvent(event)) {
                return true;
            }
        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
            return mFocused.dispatchTrackballEvent(event);
            if (mFocused.dispatchTrackballEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
        }
        }
        return false;
        return false;
    }
    }
@@ -1344,10 +1360,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }
        }


        if (!onFilterTouchEventForSecurity(ev)) {
        boolean handled = false;
            return false;
        if (onFilterTouchEventForSecurity(ev)) {
        }

            final int action = ev.getAction();
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;
            final int actionMasked = action & MotionEvent.ACTION_MASK;


@@ -1367,7 +1381,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    intercepted = onInterceptTouchEvent(ev);
                ev.setAction(action); // restore action in case onInterceptTouchEvent() changed it
                    ev.setAction(action); // restore action in case it was changed
                } else {
                } else {
                    intercepted = false;
                    intercepted = false;
                }
                }
@@ -1399,7 +1413,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager


                    final int childrenCount = mChildrenCount;
                    final int childrenCount = mChildrenCount;
                    if (childrenCount != 0) {
                    if (childrenCount != 0) {
                    // Find a child that can receive the event.  Scan children from front to back.
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        final View[] children = mChildren;
                        final View[] children = mChildren;
                        final float x = ev.getX(actionIndex);
                        final float x = ev.getX(actionIndex);
                        final float y = ev.getY(actionIndex);
                        final float y = ev.getY(actionIndex);
@@ -1446,7 +1461,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            }
            }


            // Dispatch to touch targets.
            // Dispatch to touch targets.
        boolean handled = false;
            if (mFirstTouchTarget == null) {
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
@@ -1461,7 +1475,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        handled = true;
                        handled = true;
                    } else {
                    } else {
                    final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
                        || intercepted;
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                                target.child, target.pointerIdBits)) {
                            handled = true;
                            handled = true;
@@ -1492,7 +1507,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                removePointersFromTouchTargets(idBitsToRemove);
                removePointersFromTouchTargets(idBitsToRemove);
            }
            }
        }


        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
        }
        return handled;
        return handled;
    }
    }