예제 #1
0
        public virtual bool onTouchEvent(android.view.MotionEvent @event)
        {
            if (mInputEventConsistencyVerifier != null)
            {
                mInputEventConsistencyVerifier.onTouchEvent(@event, 0);
            }
            int action = @event.getActionMasked();

            if (action == android.view.MotionEvent.ACTION_DOWN)
            {
                reset();
            }
            // Start fresh
            bool handled = true;

            if (mInvalidGesture)
            {
                handled = false;
            }
            else
            {
                if (!mGestureInProgress)
                {
                    switch (action)
                    {
                    case android.view.MotionEvent.ACTION_DOWN:
                    {
                        mActiveId0         = @event.getPointerId(0);
                        mActive0MostRecent = true;
                        break;
                    }

                    case android.view.MotionEvent.ACTION_UP:
                    {
                        reset();
                        break;
                    }

                    case android.view.MotionEvent.ACTION_POINTER_DOWN:
                    {
                        // We have a new multi-finger gesture
                        // as orientation can change, query the metrics in touch down
                        android.util.DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
                        mRightSlopEdge  = metrics.widthPixels - mEdgeSlop;
                        mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
                        if (mPrevEvent != null)
                        {
                            mPrevEvent.recycle();
                        }
                        mPrevEvent = android.view.MotionEvent.obtain(@event);
                        mTimeDelta = 0;
                        int index1 = @event.getActionIndex();
                        int index0 = @event.findPointerIndex(mActiveId0);
                        mActiveId1 = @event.getPointerId(index1);
                        if (index0 < 0 || index0 == index1)
                        {
                            // Probably someone sending us a broken event stream.
                            index0     = findNewActiveIndex(@event, index0 == index1 ? -1 : mActiveId1, index0);
                            mActiveId0 = @event.getPointerId(index0);
                        }
                        mActive0MostRecent = false;
                        setContext(@event);
                        // Check if we have a sloppy gesture. If so, delay
                        // the beginning of the gesture until we're sure that's
                        // what the user wanted. Sloppy gestures can happen if the
                        // edge of the user's hand is touching the screen, for example.
                        float edgeSlop = mEdgeSlop;
                        float rightSlop = mRightSlopEdge;
                        float bottomSlop = mBottomSlopEdge;
                        float x0 = getRawX(@event, index0);
                        float y0 = getRawY(@event, index0);
                        float x1 = getRawX(@event, index1);
                        float y1 = getRawY(@event, index1);
                        bool  p0sloppy = x0 <edgeSlop || y0 <edgeSlop || x0> rightSlop || y0> bottomSlop;
                        bool  p1sloppy = x1 <edgeSlop || y1 <edgeSlop || x1> rightSlop || y1> bottomSlop;
                        if (p0sloppy && p1sloppy)
                        {
                            mFocusX        = -1;
                            mFocusY        = -1;
                            mSloppyGesture = true;
                        }
                        else
                        {
                            if (p0sloppy)
                            {
                                mFocusX        = @event.getX(index1);
                                mFocusY        = @event.getY(index1);
                                mSloppyGesture = true;
                            }
                            else
                            {
                                if (p1sloppy)
                                {
                                    mFocusX        = @event.getX(index0);
                                    mFocusY        = @event.getY(index0);
                                    mSloppyGesture = true;
                                }
                                else
                                {
                                    mSloppyGesture     = false;
                                    mGestureInProgress = mListener.onScaleBegin(this);
                                }
                            }
                        }
                        break;
                    }

                    case android.view.MotionEvent.ACTION_MOVE:
                    {
                        if (mSloppyGesture)
                        {
                            // Initiate sloppy gestures if we've moved outside of the slop area.
                            float edgeSlop = mEdgeSlop;
                            float rightSlop = mRightSlopEdge;
                            float bottomSlop = mBottomSlopEdge;
                            int   index0 = @event.findPointerIndex(mActiveId0);
                            int   index1 = @event.findPointerIndex(mActiveId1);
                            float x0 = getRawX(@event, index0);
                            float y0 = getRawY(@event, index0);
                            float x1 = getRawX(@event, index1);
                            float y1 = getRawY(@event, index1);
                            bool  p0sloppy = x0 <edgeSlop || y0 <edgeSlop || x0> rightSlop || y0> bottomSlop;
                            bool  p1sloppy = x1 <edgeSlop || y1 <edgeSlop || x1> rightSlop || y1> bottomSlop;
                            if (p0sloppy)
                            {
                                // Do we have a different pointer that isn't sloppy?
                                int index = findNewActiveIndex(@event, mActiveId1, index0);
                                if (index >= 0)
                                {
                                    index0     = index;
                                    mActiveId0 = @event.getPointerId(index);
                                    x0         = getRawX(@event, index);
                                    y0         = getRawY(@event, index);
                                    p0sloppy   = false;
                                }
                            }
                            if (p1sloppy)
                            {
                                // Do we have a different pointer that isn't sloppy?
                                int index = findNewActiveIndex(@event, mActiveId0, index1);
                                if (index >= 0)
                                {
                                    index1     = index;
                                    mActiveId1 = @event.getPointerId(index);
                                    x1         = getRawX(@event, index);
                                    y1         = getRawY(@event, index);
                                    p1sloppy   = false;
                                }
                            }
                            if (p0sloppy && p1sloppy)
                            {
                                mFocusX = -1;
                                mFocusY = -1;
                            }
                            else
                            {
                                if (p0sloppy)
                                {
                                    mFocusX = @event.getX(index1);
                                    mFocusY = @event.getY(index1);
                                }
                                else
                                {
                                    if (p1sloppy)
                                    {
                                        mFocusX = @event.getX(index0);
                                        mFocusY = @event.getY(index0);
                                    }
                                    else
                                    {
                                        mSloppyGesture     = false;
                                        mGestureInProgress = mListener.onScaleBegin(this);
                                    }
                                }
                            }
                        }
                        break;
                    }

                    case android.view.MotionEvent.ACTION_POINTER_UP:
                    {
                        if (mSloppyGesture)
                        {
                            int pointerCount = @event.getPointerCount();
                            int actionIndex  = @event.getActionIndex();
                            int actionId     = @event.getPointerId(actionIndex);
                            if (pointerCount > 2)
                            {
                                if (actionId == mActiveId0)
                                {
                                    int newIndex = findNewActiveIndex(@event, mActiveId1, actionIndex);
                                    if (newIndex >= 0)
                                    {
                                        mActiveId0 = @event.getPointerId(newIndex);
                                    }
                                }
                                else
                                {
                                    if (actionId == mActiveId1)
                                    {
                                        int newIndex = findNewActiveIndex(@event, mActiveId0, actionIndex);
                                        if (newIndex >= 0)
                                        {
                                            mActiveId1 = @event.getPointerId(newIndex);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // Set focus point to the remaining finger
                                int index = @event.findPointerIndex(actionId == mActiveId0 ? mActiveId1 : mActiveId0
                                                                    );
                                if (index < 0)
                                {
                                    mInvalidGesture = true;
                                    android.util.Log.e(TAG, "Invalid MotionEvent stream detected.", new System.Exception
                                                           ());
                                    if (mGestureInProgress)
                                    {
                                        mListener.onScaleEnd(this);
                                    }
                                    return(false);
                                }
                                mActiveId0         = @event.getPointerId(index);
                                mActive0MostRecent = true;
                                mActiveId1         = -1;
                                mFocusX            = @event.getX(index);
                                mFocusY            = @event.getY(index);
                            }
                        }
                        break;
                    }
                    }
                }
                else
                {
                    switch (action)
                    {
                    case android.view.MotionEvent.ACTION_POINTER_DOWN:
                    {
                        // Transform gesture in progress - attempt to handle it
                        // End the old gesture and begin a new one with the most recent two fingers.
                        mListener.onScaleEnd(this);
                        int oldActive0 = mActiveId0;
                        int oldActive1 = mActiveId1;
                        reset();
                        mPrevEvent         = android.view.MotionEvent.obtain(@event);
                        mActiveId0         = mActive0MostRecent ? oldActive0 : oldActive1;
                        mActiveId1         = @event.getPointerId(@event.getActionIndex());
                        mActive0MostRecent = false;
                        int index0 = @event.findPointerIndex(mActiveId0);
                        if (index0 < 0 || mActiveId0 == mActiveId1)
                        {
                            // Probably someone sending us a broken event stream.
                            android.util.Log.e(TAG, "Got " + android.view.MotionEvent.actionToString(action)
                                               + " with bad state while a gesture was in progress. " + "Did you forget to pass an event to "
                                               + "ScaleGestureDetector#onTouchEvent?");
                            index0 = findNewActiveIndex(@event, mActiveId0 == mActiveId1 ? -1 : mActiveId1, index0
                                                        );
                            mActiveId0 = @event.getPointerId(index0);
                        }
                        setContext(@event);
                        mGestureInProgress = mListener.onScaleBegin(this);
                        break;
                    }

                    case android.view.MotionEvent.ACTION_POINTER_UP:
                    {
                        int  pointerCount = @event.getPointerCount();
                        int  actionIndex  = @event.getActionIndex();
                        int  actionId     = @event.getPointerId(actionIndex);
                        bool gestureEnded = false;
                        if (pointerCount > 2)
                        {
                            if (actionId == mActiveId0)
                            {
                                int newIndex = findNewActiveIndex(@event, mActiveId1, actionIndex);
                                if (newIndex >= 0)
                                {
                                    mListener.onScaleEnd(this);
                                    mActiveId0         = @event.getPointerId(newIndex);
                                    mActive0MostRecent = true;
                                    mPrevEvent         = android.view.MotionEvent.obtain(@event);
                                    setContext(@event);
                                    mGestureInProgress = mListener.onScaleBegin(this);
                                }
                                else
                                {
                                    gestureEnded = true;
                                }
                            }
                            else
                            {
                                if (actionId == mActiveId1)
                                {
                                    int newIndex = findNewActiveIndex(@event, mActiveId0, actionIndex);
                                    if (newIndex >= 0)
                                    {
                                        mListener.onScaleEnd(this);
                                        mActiveId1         = @event.getPointerId(newIndex);
                                        mActive0MostRecent = false;
                                        mPrevEvent         = android.view.MotionEvent.obtain(@event);
                                        setContext(@event);
                                        mGestureInProgress = mListener.onScaleBegin(this);
                                    }
                                    else
                                    {
                                        gestureEnded = true;
                                    }
                                }
                            }
                            mPrevEvent.recycle();
                            mPrevEvent = android.view.MotionEvent.obtain(@event);
                            setContext(@event);
                        }
                        else
                        {
                            gestureEnded = true;
                        }
                        if (gestureEnded)
                        {
                            // Gesture ended
                            setContext(@event);
                            // Set focus point to the remaining finger
                            int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
                            int index    = @event.findPointerIndex(activeId);
                            mFocusX = @event.getX(index);
                            mFocusY = @event.getY(index);
                            mListener.onScaleEnd(this);
                            reset();
                            mActiveId0         = activeId;
                            mActive0MostRecent = true;
                        }
                        break;
                    }

                    case android.view.MotionEvent.ACTION_CANCEL:
                    {
                        mListener.onScaleEnd(this);
                        reset();
                        break;
                    }

                    case android.view.MotionEvent.ACTION_UP:
                    {
                        reset();
                        break;
                    }

                    case android.view.MotionEvent.ACTION_MOVE:
                    {
                        setContext(@event);
                        // Only accept the event if our relative pressure is within
                        // a certain limit - this can help filter shaky data as a
                        // finger is lifted.
                        if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD)
                        {
                            bool updatePrevious = mListener.onScale(this);
                            if (updatePrevious)
                            {
                                mPrevEvent.recycle();
                                mPrevEvent = android.view.MotionEvent.obtain(@event);
                            }
                        }
                        break;
                    }
                    }
                }
            }
            if (!handled && mInputEventConsistencyVerifier != null)
            {
                mInputEventConsistencyVerifier.onUnhandledEvent(@event, 0);
            }
            return(handled);
        }
예제 #2
0
        /// <summary>Checks a touch event.</summary>
        /// <remarks>Checks a touch event.</remarks>
        /// <param name="event">The event.</param>
        /// <param name="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.
        /// </param>
        public void onTouchEvent(android.view.MotionEvent @event, int nestingLevel)
        {
            if (!startEvent(@event, nestingLevel, EVENT_TYPE_TOUCH))
            {
                return;
            }
            int  action    = @event.getAction();
            bool newStream = action == android.view.MotionEvent.ACTION_DOWN || action == android.view.MotionEvent
                             .ACTION_CANCEL;

            if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled))
            {
                mTouchEventStreamIsTainted = false;
                mTouchEventStreamUnhandled = false;
                mTouchEventStreamPointers  = 0;
            }
            if (mTouchEventStreamIsTainted)
            {
                @event.setTainted(true);
            }
            try
            {
                ensureMetaStateIsNormalized(@event.getMetaState());
                int deviceId = @event.getDeviceId();
                int source   = @event.getSource();
                if (!newStream && mTouchEventStreamDeviceId != -1 && (mTouchEventStreamDeviceId !=
                                                                      deviceId || mTouchEventStreamSource != source))
                {
                    problem("Touch event stream contains events from multiple sources: " + "previous device id "
                            + mTouchEventStreamDeviceId + ", previous source " + Sharpen.Util.IntToHexString
                                (mTouchEventStreamSource) + ", new device id " + deviceId + ", new source " + Sharpen.Util.IntToHexString
                                (source));
                }
                mTouchEventStreamDeviceId = deviceId;
                mTouchEventStreamSource   = source;
                int pointerCount = @event.getPointerCount();
                if ((source & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0)
                {
                    switch (action)
                    {
                    case android.view.MotionEvent.ACTION_DOWN:
                    {
                        if (mTouchEventStreamPointers != 0)
                        {
                            problem("ACTION_DOWN but pointers are already down.  " + "Probably missing ACTION_UP from previous gesture."
                                    );
                        }
                        ensureHistorySizeIsZeroForThisAction(@event);
                        ensurePointerCountIsOneForThisAction(@event);
                        mTouchEventStreamPointers = 1 << @event.getPointerId(0);
                        break;
                    }

                    case android.view.MotionEvent.ACTION_UP:
                    {
                        ensureHistorySizeIsZeroForThisAction(@event);
                        ensurePointerCountIsOneForThisAction(@event);
                        mTouchEventStreamPointers  = 0;
                        mTouchEventStreamIsTainted = false;
                        break;
                    }

                    case android.view.MotionEvent.ACTION_MOVE:
                    {
                        int expectedPointerCount = Sharpen.Util.IntGetBitCount(mTouchEventStreamPointers);
                        if (pointerCount != expectedPointerCount)
                        {
                            problem("ACTION_MOVE contained " + pointerCount + " pointers but there are currently "
                                    + expectedPointerCount + " pointers down.");
                            mTouchEventStreamIsTainted = true;
                        }
                        break;
                    }

                    case android.view.MotionEvent.ACTION_CANCEL:
                    {
                        mTouchEventStreamPointers  = 0;
                        mTouchEventStreamIsTainted = false;
                        break;
                    }

                    case android.view.MotionEvent.ACTION_OUTSIDE:
                    {
                        if (mTouchEventStreamPointers != 0)
                        {
                            problem("ACTION_OUTSIDE but pointers are still down.");
                        }
                        ensureHistorySizeIsZeroForThisAction(@event);
                        ensurePointerCountIsOneForThisAction(@event);
                        mTouchEventStreamIsTainted = false;
                        break;
                    }

                    default:
                    {
                        int actionMasked = @event.getActionMasked();
                        int actionIndex  = @event.getActionIndex();
                        if (actionMasked == android.view.MotionEvent.ACTION_POINTER_DOWN)
                        {
                            if (mTouchEventStreamPointers == 0)
                            {
                                problem("ACTION_POINTER_DOWN but no other pointers were down.");
                                mTouchEventStreamIsTainted = true;
                            }
                            if (actionIndex < 0 || actionIndex >= pointerCount)
                            {
                                problem("ACTION_POINTER_DOWN index is " + actionIndex + " but the pointer count is "
                                        + pointerCount + ".");
                                mTouchEventStreamIsTainted = true;
                            }
                            else
                            {
                                int id    = @event.getPointerId(actionIndex);
                                int idBit = 1 << id;
                                if ((mTouchEventStreamPointers & idBit) != 0)
                                {
                                    problem("ACTION_POINTER_DOWN specified pointer id " + id + " which is already down."
                                            );
                                    mTouchEventStreamIsTainted = true;
                                }
                                else
                                {
                                    mTouchEventStreamPointers |= idBit;
                                }
                            }
                            ensureHistorySizeIsZeroForThisAction(@event);
                        }
                        else
                        {
                            if (actionMasked == android.view.MotionEvent.ACTION_POINTER_UP)
                            {
                                if (actionIndex < 0 || actionIndex >= pointerCount)
                                {
                                    problem("ACTION_POINTER_UP index is " + actionIndex + " but the pointer count is "
                                            + pointerCount + ".");
                                    mTouchEventStreamIsTainted = true;
                                }
                                else
                                {
                                    int id    = @event.getPointerId(actionIndex);
                                    int idBit = 1 << id;
                                    if ((mTouchEventStreamPointers & idBit) == 0)
                                    {
                                        problem("ACTION_POINTER_UP specified pointer id " + id + " which is not currently down."
                                                );
                                        mTouchEventStreamIsTainted = true;
                                    }
                                    else
                                    {
                                        mTouchEventStreamPointers &= ~idBit;
                                    }
                                }
                                ensureHistorySizeIsZeroForThisAction(@event);
                            }
                            else
                            {
                                problem("Invalid action " + android.view.MotionEvent.actionToString(action) + " for touch event."
                                        );
                            }
                        }
                        break;
                    }
                    }
                }
                else
                {
                    problem("Source was not SOURCE_CLASS_POINTER.");
                }
            }
            finally
            {
                finishEvent();
            }
        }