onInterceptTouchEvent only gets ACTION_DOWN

I'll answer my own question: onInterceptTouchEvent only get called if the parent has a child view which returns "true" from onTouchEvent. Once the child returns true, the parent now has a chance to intercept that event.

enter image description here


dispatchTouchEvent, onInterceptTouchEvent, requestDisallowInterceptTouchEvent

[Touch event flow]

The official doc

Activity.dispatchTouchEvent(MotionEvent) - This allows your Activity to intercept all touch events before they are dispatched to the window.

ViewGroup.onInterceptTouchEvent(MotionEvent) - This allows a ViewGroup to watch events as they are dispatched to child Views. It is recursively function (from parent to parent)

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Call this upon a parent View to indicate that it should not intercept touch events with onInterceptTouchEvent(MotionEvent).


I get the same problem. I had read many posts about it:
onInterceptTouchEvent only gets ACTION_DOWN
onInterceptTouchEvent's ACTION_UP and ACTION_MOVE never gets called
onInterceptTouchEvent, onTouchEvent only see ACTION_DOWN
onInterceptTouchEvent never receives action_move

I also had read android doc:
http://developer.android.com/training/gestures/viewgroup.html
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)

All answers are same. I tried many times, always not get onInterceptTouchEvent () be called if not down event.

I read source code, I guess that something is changed:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
    }

    boolean handled = false;
    if (onFilterTouchEventForSecurity(ev)) {
        final int action = ev.getAction();
        final int actionMasked = action & MotionEvent.ACTION_MASK;

        // Handle an initial down.
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Throw away all previous state when starting a new touch gesture.
            // The framework may have dropped the up or cancel event for the previous gesture
            // due to an app switch, ANR, or some other state change.
            cancelAndClearTouchTargets(ev);
            resetTouchState();
        }

        // Check for interception.
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
                intercepted = onInterceptTouchEvent(ev);
                ev.setAction(action); // restore action in case it was changed
            } else {
                intercepted = false;
            }
        } else {
            // There are no touch targets and this action is not an initial down
            // so this view group continues to intercept touches.
            intercepted = true;
        }


According above code, onInterceptTouchEvent(ev) is only be called when MotionEvent.ACTION_DOWN, this is what we tried and found. So, what I guess is, the code is changed, but doc not.

If you want spy or monitor all the events include those been sent to child views, you can override dispatchTouchEvent() like this:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    MyLog.d(MyLog.DEBUG, "dispatchTouchEvent(): "+event.getAction());
    if (isEnabled()) {
        MyLog.d(MyLog.DEBUG, "dispatchTouchEvent()2: "+event.getAction());

        processEvent(event);//here you get all events include move & up

        super.dispatchTouchEvent(event);

        return true; //to keep receive event that follow down event
    }
    return super.dispatchTouchEvent(event);
}

I have the runnable code at: https://github.com/maxyou/gesturebutton/blob/master/src/com/maxproj/gesturebutton/GestureButtonLayout.java

Tags:

Java

Android