public override bool OnTouchEvent(MotionEvent ev)
        {
            MotionEventActions action = ev.Action;
            switch (action & MotionEventActions.Mask) {
            case MotionEventActions.Down:
                mActivePointerId = ev.GetPointerId(0);
                break;
            case MotionEventActions.Cancel:
            case MotionEventActions.Up:
                mActivePointerId = INVALID_POINTER_ID;
                break;
            case MotionEventActions.PointerUp:
                // Ignore deprecation, ACTION_POINTER_ID_MASK and
                // ACTION_POINTER_ID_SHIFT has same value and are deprecated
                // You can have either deprecation or lint target api warning
                int pointerIndex = Compat.GetPointerIndex(ev.Action);
                 int pointerId = ev.GetPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                     int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mActivePointerId = ev.GetPointerId(newPointerIndex);
                    mLastTouchX = ev.GetX(newPointerIndex);
                    mLastTouchY = ev.GetY(newPointerIndex);
                }
                break;
            }

            mActivePointerIndex = ev
                .FindPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
                    : 0);
            return base.OnTouchEvent(ev);
        }
        public void HandleDragEvent(MotionEvent ev)
        {
            MotionEventActions action = ev.Action & MotionEventActions.Mask;
            int pointerIndex;
            switch (action) {
            case MotionEventActions.Down:
                _lastTouchX = ev.RawX;
                _lastTouchY = ev.RawY;
                _activePointerId = ev.GetPointerId (0);
                _posX = _posX == 0 ? Shape.Center_X - Shape.Radius : _posX;
                _posY = _posY == 0 ? Shape.Center_Y - Shape.Radius : _posX;
                break;

            case MotionEventActions.Move:
                pointerIndex = ev.FindPointerIndex (_activePointerId);
                float x = ev.RawX;
                float y = ev.RawY;

                float deltaX = x - _lastTouchX;
                float deltaY = y - _lastTouchY;
                _posX += deltaX;
                _posY += deltaY;
                if (RequestLayout != null)
                    RequestLayout ((int)_posX, (int)_posY, (int)_posX + Shape.Radius * 2, (int)_posY + Shape.Radius * 2);

                _lastTouchX = x;
                _lastTouchY = y;
                break;

            case MotionEventActions.Up:
                _lastTouchX = ev.RawX;
                _lastTouchY = ev.RawY;
                Shape.Center_X = (int)_posX + Shape.Radius;
                Shape.Center_Y = (int)_posY + Shape.Radius;
                _posX = 0;
                _posY = 0;
                break;
            case MotionEventActions.Cancel:
                // We no longer need to keep track of the active pointer.
                _activePointerId = -1;
                break;

            case MotionEventActions.PointerUp:
                // check to make sure that the pointer that went up is for the gesture we're tracking.
                pointerIndex = (int)(ev.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
                int pointerId = ev.GetPointerId (pointerIndex);
                if (pointerId == _activePointerId) {

                    _lastTouchX = ev.RawX;
                    _lastTouchY = ev.RawY;
                    Shape.Center_X = (int)_posX + Shape.Radius;
                    Shape.Center_Y = (int)_posY + Shape.Radius;

                }
                break;

            }
        }
		public override bool OnTouchEvent (MotionEvent ev)
		{
			_scaleDetector.OnTouchEvent (ev);

			MotionEventActions action = ev.Action & MotionEventActions.Mask;
			int pointerIndex;

			switch (action) {
			case MotionEventActions.Down:
				_lastTouchX = ev.GetX ();
				_lastTouchY = ev.GetY ();
				_activePointerId = ev.GetPointerId (0);
				break;

			case MotionEventActions.Move:
				pointerIndex = ev.FindPointerIndex (_activePointerId);
				float x = ev.GetX (pointerIndex);
				float y = ev.GetY (pointerIndex);
				if (!_scaleDetector.IsInProgress) {
					// Only move the ScaleGestureDetector isn't already processing a gesture.
					float deltaX = x - _lastTouchX;
					float deltaY = y - _lastTouchY;
					_posX += deltaX;
					_posY += deltaY;
					Invalidate ();
				}

				_lastTouchX = x;
				_lastTouchY = y;
				break;

			case MotionEventActions.Up:
			case MotionEventActions.Cancel:
                    // This events occur when something cancels the gesture (for example the
                    // activity going in the background) or when the pointer has been lifted up.
                    // We no longer need to keep track of the active pointer.
				_activePointerId = InvalidPointerId;
				break;

			case MotionEventActions.PointerUp:
                    // We only want to update the last touch position if the the appropriate pointer
                    // has been lifted off the screen.
				pointerIndex = (int)(ev.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
				int pointerId = ev.GetPointerId (pointerIndex);
				if (pointerId == _activePointerId) {
					// This was our active pointer going up. Choose a new
					// action pointer and adjust accordingly
					int newPointerIndex = pointerIndex == 0 ? 1 : 0;
					_lastTouchX = ev.GetX (newPointerIndex);
					_lastTouchY = ev.GetY (newPointerIndex);
					_activePointerId = ev.GetPointerId (newPointerIndex);
				}
				break;
			}
			return true;
		}
Exemple #4
0
        public override bool OnTouchEvent(MotionEvent e)
        {
            int touchesCount = e.PointerCount;
            List<Point> TouchPlace = new List<Point>();

            for (int i = 0; i < touchesCount; i++)
            {
                TouchPlace.Add(new Point((int)e.GetX(i), (int)e.GetY(i)));
            }

            switch (e.ActionMasked)
            {
                case MotionEventActions.PointerDown:
                case MotionEventActions.Down:
                    foreach (Point touch in TouchPlace)
                    {
                        foreach (CirclePaint circle in _touches)
                        {
                            if (circle.IsTouched(touch))
                            {
                                circle.Touched = TouchPlace.IndexOf(touch);
                            }
                        }
                    }
                    break;
                case MotionEventActions.Move:
                    foreach (CirclePaint circle in _touches)
                    {
                        if (circle.Touched >= 0)
                        {
                            circle.MoveTo(TouchPlace[e.FindPointerIndex(circle.Touched)]);
                            Invalidate();
                        }
                    }
                    break;
                case MotionEventActions.PointerUp:
                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    foreach (CirclePaint circle in _touches)
                    {
                        if (circle.Touched == e.GetPointerId(e.ActionIndex))
                        {
                            circle.Touched = -1;
                        }

                    }
                    break;
                default:
                    break;
            }

            return true;
        }
        private MotionEvent.PointerCoords GetPointerCoords(Android.Views.MotionEvent e, int pointerId)
        {
            // Get the pointer coords
            var pointerIndex = e.FindPointerIndex(pointerId);

            if (pointerIndex < 0)
            {
                return(null);
            }

            var point = new MotionEvent.PointerCoords();

            e.GetPointerCoords(pointerIndex, point);

            return(point);
        }
		public override bool OnTouchEvent (MotionEvent ev)
		{
			Log.Debug("PullToZoomScrollView", "onTouchEvent --> action = " + (0xFF & (int)ev.Action));
			if (_isHeaderTop && _isEnableZoom) {
				switch ((MotionEventActions)0xFF & ev.Action) {
				case MotionEventActions.Down:
				case MotionEventActions.Outside:
					if (!_scalingRunnable.IsFinished()) {
						_scalingRunnable.AbortAnimation();
					}
					_lastMotionY = ev.GetY();
					_activePointerId = ev.GetPointerId(0);
					_maxScale = (_screenHeight / _zoomHeight);
					_lastScale = (_zoomContainer.Bottom / _zoomHeight);
					if (_onScrollViewZoomListener != null) {
						_onScrollViewZoomListener.onStart();
					}
					break;
				case MotionEventActions.Move:
					Log.Debug("PullToZoomScrollView", "_activePointerId = " + _activePointerId);
					int j = ev.FindPointerIndex(_activePointerId);
					if (j == -1) {
						Log.Error("PullToZoomScrollView", "Invalid pointerId = " + _activePointerId + " in onTouchEvent");
					} else {
						if (_lastMotionY == -1.0F) {
							_lastMotionY = ev.GetY(j);
						}
						if (_zoomContainer.Bottom >= _zoomHeight) {
							FrameLayout.LayoutParams localLayoutParams = (FrameLayout.LayoutParams) _zoomContainer.LayoutParameters;
							ViewGroup.LayoutParams headLayoutParams = _headerContainer.LayoutParameters;
							float f = ((ev.GetY(j) - _lastMotionY + _zoomContainer.Bottom) / _zoomHeight - _lastScale) / 2.0F + _lastScale;
							if ((_lastScale <= 1.0D) && (f < _lastScale)) {
								localLayoutParams.Height = _zoomHeight;
								localLayoutParams.Width = _zoomWidth;
								localLayoutParams.Gravity = GravityFlags.Center;
								headLayoutParams.Height = _zoomHeight;
								_zoomContainer.LayoutParameters=localLayoutParams;
								_headerContainer.LayoutParameters=headLayoutParams;
								return base.OnTouchEvent(ev);
							}
							_lastScale = Math.Min(Math.Max(f, 1.0F), _maxScale);
							localLayoutParams.Height = ((int) (_zoomHeight * _lastScale));
							localLayoutParams.Width = ((int) (_zoomWidth * _lastScale));
							localLayoutParams.Gravity = GravityFlags.Center;
							headLayoutParams.Height = ((int) (_zoomHeight * _lastScale));
							if (localLayoutParams.Height < _screenHeight) {
								_zoomContainer.LayoutParameters=localLayoutParams;
								_headerContainer.LayoutParameters=headLayoutParams;
							}
							_lastMotionY = ev.GetY(j);
							return true;
						}
						_lastMotionY = ev.GetY(j);
					}
					break;
				case MotionEventActions.Up:
					Reset();
					EndScaling();
					if (_onScrollViewZoomListener != null) {
						_onScrollViewZoomListener.onFinish();
					}
					break;
				case MotionEventActions.Cancel:
					int i = ev.ActionIndex;
					_lastMotionY = ev.GetY(i);
					_activePointerId = ev.GetPointerId(i);
					break;
				case MotionEventActions.PointerDown:
					OnSecondaryPointerUp(ev);
					_lastMotionY = ev.GetY(ev.FindPointerIndex(_activePointerId));
					break;
				}
			}
			return base.OnTouchEvent (ev);
		}
        public override bool OnInterceptTouchEvent(MotionEvent ev)
        {
            int currenrMotionX;
            int currentMotionY;

            if (ev.Action == MotionEventActions.Move && this.isBeingDragged)
            {
                return true;
            }

            if (this.ScrollX == 0 && !this.CanScrollVertically(1) &&
                this.ScrollY == 0 && !this.CanScrollHorizontally(1))
            {
                return false;
            }

            switch (ev.Action & MotionEventActions.Mask)
            {
                case MotionEventActions.Move:
                    {
                        this.FindViewWhoScrolling((int)ev.GetX(), (int)ev.GetY(), 1, 1);
                        if (this.childWhoScrolling != null)
                        {
                            return false;
                        }

                        if (this.activePointerId == InvalidPointerId)
                        {
                            break;
                        }

                        int pointerIndex = ev.FindPointerIndex(this.activePointerId);
                        if (pointerIndex == -1)
                        {
                            break;
                        }

                        currenrMotionX = (int)ev.GetX(pointerIndex);
                        currentMotionY = (int)ev.GetY(pointerIndex);
                        int xDiff = Math.Abs(currenrMotionX - this.lastMotionX);
                        int yDiff = Math.Abs(currentMotionY - this.lastMotionY);
                        if (xDiff > this.touchSlop || yDiff > this.touchSlop)
                        {
                            this.isBeingDragged = true;
                            this.lastMotionX = currenrMotionX;
                            this.lastMotionY = currentMotionY;
                            this.InitVelocityTrackerIfNotExists();
                            this.velocityTracker.AddMovement(ev);

                            if (this.Parent != null)
                            {
                                this.Parent.RequestDisallowInterceptTouchEvent(true);
                            }
                        }
                        break;
                    }
                case MotionEventActions.Down:
                    {
                        this.FindViewWhoScrolling((int)ev.GetX(), (int)ev.GetY(), 1, 1);

                        if (this.childWhoScrolling != null)
                        {
                            return false;
                        }

                        // Stop, if touched during movement on inertia
                        if (!this.scroller.IsFinishedY)
                        {
                            this.scroller.AbortAnimation();
                            ////FlingStrictSpan
                        }

                        currenrMotionX = (int)ev.GetX();
                        currentMotionY = (int)ev.GetY();

                        this.lastMotionX = currenrMotionX;
                        this.lastMotionY = currentMotionY;
                        this.activePointerId = ev.GetPointerId(0);

                        ////if (this.inChild(x, y))
                        {
                            this.isBeingDragged = false;
                            this.RecycleVelocityTracker();
                            ////break;
                        }

                        this.InitOrResetVelocityTracker();
                        this.velocityTracker.AddMovement(ev);

                        ////this.isBeingDragged = this.scroller.IsFinished;

                        break;
                    }
                case MotionEventActions.Cancel:
                case MotionEventActions.Up:
                    if (this.childWhoScrolling != null)
                    {
                        this.childWhoScrolling = null;
                        return false;
                    }
                    this.isBeingDragged = false;
                    this.activePointerId = InvalidPointerId;
                    this.RecycleVelocityTracker();

                    //if (this.scroller.SpringBack(this.ScrollX, this.ScrollY, 0, 0, this.GetScrollRangeX(), this.GetScrollRangeY()))
                    //{
                        // TODO: possible something like postInvalidate (postInvalidateOnAnimation)
                    //}
                    break;
                case MotionEventActions.PointerUp:
                    if (this.childWhoScrolling != null)
                    {
                        return false;
                    }
                    this.OnSecondaryPointerUp(ev);
                    break;
            }

            return this.isBeingDragged;
        }
		public override bool OnTouchEvent (MotionEvent e)
		{
			Log.Debug("PullToZoomListView", "action = " + (0xFF & (int)e.Action));
			if (_headerView != null && !_isHideHeader && _isEnableZoom) {
				switch ((MotionEventActions)0xFF & e.Action) {
				case MotionEventActions.Down:
				case MotionEventActions.Outside:
					if (!_scalingRunnable.IsFinished()) {
						_scalingRunnable.AbortAnimation();
					}
					_lastMotionY = e.GetY();
					_activePointerId = e.GetPointerId(0);
					_maxScale = (_screenHeight / _headerHeight);
					_lastScale = (_headerContainer.Bottom / _headerHeight);
					break;
				case MotionEventActions.Move:
					Log.Debug("PullToZoomListView", "_activePointerId" + _activePointerId);
					int j = e.FindPointerIndex(_activePointerId);
					if (j == -1) {
						Log.Error("PullToZoomListView", "Invalid pointerId=" + _activePointerId + " in onTouchEvent");
					} else {
						if (_lastMotionY == -1.0F) {
							_lastMotionY = e.GetY(j);
						}
						if (_headerContainer.Bottom >= _headerHeight) {
							ViewGroup.LayoutParams localLayoutParams = _headerContainer.LayoutParameters;
							float f = ((e.GetY(j) - _lastMotionY + _headerContainer.Bottom) / _headerHeight - _lastScale) / 2.0F + _lastScale;
							if ((_lastScale <= 1.0D) && (f < _lastScale)) {
								localLayoutParams.Height = _headerHeight;
								_headerContainer.LayoutParameters=localLayoutParams;
								return base.OnTouchEvent(e);
							}
							_lastScale = Java.Lang.Math.Min(Java.Lang.Math.Max(f, 1.0F), _maxScale);
							localLayoutParams.Height = ((int) (_headerHeight * _lastScale));
							if (localLayoutParams.Height < _screenHeight) {
								_headerContainer.LayoutParameters=localLayoutParams;
							}
							_lastMotionY = e.GetY(j);
							return true;
						}
						_lastMotionY = e.GetY(j);
					}
					break;
				case MotionEventActions.Up:
					Reset();
					EndScaling();
					break;
				case MotionEventActions.Cancel:
					int i = e.ActionIndex;
					_lastMotionY = e.GetY(i);
					_activePointerId = e.GetPointerId(i);
					break;
				case MotionEventActions.PointerDown:
					OnSecondaryPointerUp(e);
					_lastMotionY = e.GetY(e.FindPointerIndex(_activePointerId));
					break;
				}
			}
			return base.OnTouchEvent (e);
		}
        public override bool OnTouchEvent(MotionEvent ev)
        {
            _scaleDetector.OnTouchEvent(ev);

            MotionEventActions action = ev.Action & MotionEventActions.Mask;
            int pointerIndex;

            switch (action)
            {
                case MotionEventActions.Down:
                    _lastTouchX = ev.GetX();
                    _lastTouchY = ev.GetY();
                    _activePointerId = ev.GetPointerId(0);
                    break;

                case MotionEventActions.Move:
                    pointerIndex = ev.FindPointerIndex(_activePointerId);
                    float x = ev.GetX(pointerIndex);
                    float y = ev.GetY(pointerIndex);
                    if (!_scaleDetector.IsInProgress)
                    {
                        // Only move the ScaleGestureDetector isn't already processing a gesture.
                        float deltaX = x - _lastTouchX;
                        float deltaY = y - _lastTouchY;
                        _posX += deltaX;
                        _posY += deltaY;
                        Invalidate();
                    }

                    _lastTouchX = x;
                    _lastTouchY = y;
                    break;

                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    // We no longer need to keep track of the active pointer.
                    _activePointerId = InvalidPointerId;
                    break;

                case MotionEventActions.PointerUp:
                    // check to make sure that the pointer that went up is for the gesture we're tracking.
                    pointerIndex = (int) (ev.Action & MotionEventActions.PointerIndexMask) >> (int) MotionEventActions.PointerIndexShift;
                    int pointerId = ev.GetPointerId(pointerIndex);
                    if (pointerId == _activePointerId)
                    {
                        // This was our active pointer going up. Choose a new
                        // action pointer and adjust accordingly
                        int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                        _lastTouchX = ev.GetX(newPointerIndex);
                        _lastTouchY = ev.GetY(newPointerIndex);
                        _activePointerId = ev.GetPointerId(newPointerIndex);
                    }
                    break;

            }
            return true;
        }
		public bool OnTouchEvent (MotionEvent evt)
		{
			var action = evt.ActionMasked;

			if (action == MotionEventActions.Down) {
				Reset(); // Start fresh
			}

			bool handled = true;
			if (mInvalidGesture) {
				handled = false;
			} else if (!mGestureInProgress) {
				switch (action) {
				case MotionEventActions.Down: {
					mActiveId0 = evt.GetPointerId(0);
					mActive0MostRecent = true;
				}
					break;

				case MotionEventActions.Up:
					Reset();
					break;

				case MotionEventActions.PointerDown: {
					// We have a new multi-finger gesture
					if (mPrevEvent != null) mPrevEvent.Recycle();
					mPrevEvent = MotionEvent.Obtain(evt);
					mTimeDelta = 0;

					int index1 = evt.ActionIndex;
					int index0 = evt.FindPointerIndex(mActiveId0);
					mActiveId1 = evt.GetPointerId(index1);
					if (index0 < 0 || index0 == index1) {
						// Probably someone sending us a broken evt stream.
						index0 = FindNewActiveIndex(evt, mActiveId1, -1);
						mActiveId0 = evt.GetPointerId(index0);
					}
					mActive0MostRecent = false;

					SetContext(evt);

					mGestureInProgress = mListener.OnScaleBegin(this);
					break;
				}
				}
			} else {
				// Transform gesture in progress - attempt to handle it
				switch (action) {
				case MotionEventActions.Down: {
					// 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 = MotionEvent.Obtain(evt);
					mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1;
					mActiveId1 = evt.GetPointerId(evt.ActionIndex);
					mActive0MostRecent = false;

					int index0 = evt.FindPointerIndex (mActiveId0);
					if (index0 < 0 || mActiveId0 == mActiveId1) {
						index0 = FindNewActiveIndex(evt, mActiveId1, -1);
						mActiveId0 = evt.GetPointerId(index0);
					}

					SetContext(evt);

					mGestureInProgress = mListener.OnScaleBegin(this);
				}
					break;

				case MotionEventActions.PointerUp: {
					int pointerCount = evt.PointerCount;
					int actionIndex = evt.ActionIndex;
					int actionId = evt.GetPointerId(actionIndex);

					bool gestureEnded = false;
					if (pointerCount > 2) {
						if (actionId == mActiveId0) {
							int newIndex = FindNewActiveIndex(evt, mActiveId1, actionIndex);
							if (newIndex >= 0) {
								mListener.OnScaleEnd(this);
								mActiveId0 = evt.GetPointerId(newIndex);
								mActive0MostRecent = true;
								mPrevEvent = MotionEvent.Obtain(evt);
								SetContext(evt);
							mGestureInProgress = mListener.OnScaleBegin(this);
							} else {
								gestureEnded = true;
							}
						} else if (actionId == mActiveId1) {
							int newIndex = FindNewActiveIndex(evt, mActiveId0, actionIndex);
							if (newIndex >= 0) {
								mListener.OnScaleEnd(this);
								mActiveId1 = evt.GetPointerId(newIndex);
								mActive0MostRecent = false;
								mPrevEvent = MotionEvent.Obtain(evt);
								SetContext(evt);
								mGestureInProgress = mListener.OnScaleBegin(this);
							} else {
								gestureEnded = true;
							}
						}
						mPrevEvent.Recycle();
						mPrevEvent = MotionEvent.Obtain(evt);
						SetContext(evt);
					} else {
						gestureEnded = true;
					}

					if (gestureEnded) {
						// Gesture ended
						SetContext(evt);

						// Set focus point to the remaining finger
						int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
						int index = evt.FindPointerIndex(activeId);
						mFocusX = evt.GetX(index);
						mFocusY = evt.GetY(index);

						mListener.OnScaleEnd(this);
						Reset();
						mActiveId0 = activeId;
						mActive0MostRecent = true;
					}
				}
					break;

				case MotionEventActions.Cancel:
					mListener.OnScaleEnd(this);
					Reset();
					break;

				case MotionEventActions.Up:
					Reset();
					break;

				case MotionEventActions.Move: {
					SetContext(evt);

					// Only accept the evt 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 = MotionEvent.Obtain(evt);
						}
					}
				}
					break;
				}
			}

			return handled;
		}
		void SetContext (MotionEvent curr)
		{
			if (mCurrEvent != null) {
				mCurrEvent.Recycle();
			}
			mCurrEvent = MotionEvent.Obtain(curr);

			mCurrLen = -1;
			mPrevLen = -1;
			mScaleFactor = -1;

			MotionEvent prev = mPrevEvent;

			int prevIndex0 = prev.FindPointerIndex(mActiveId0);
			int prevIndex1 = prev.FindPointerIndex(mActiveId1);
			int currIndex0 = curr.FindPointerIndex(mActiveId0);
			int currIndex1 = curr.FindPointerIndex(mActiveId1);

			if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) {
				mInvalidGesture = true;
				if (mGestureInProgress) {
					mListener.OnScaleEnd(this);
				}
				return;
			}

			float px0 = prev.GetX(prevIndex0);
			float py0 = prev.GetY(prevIndex0);
			float px1 = prev.GetX(prevIndex1);
			float py1 = prev.GetY(prevIndex1);
			float cx0 = curr.GetX(currIndex0);
			float cy0 = curr.GetY(currIndex0);
			float cx1 = curr.GetX(currIndex1);
			float cy1 = curr.GetY(currIndex1);

			float pvx = px1 - px0;
			float pvy = py1 - py0;
			float cvx = cx1 - cx0;
			float cvy = cy1 - cy0;
			mPrevFingerDiffX = pvx;
			mPrevFingerDiffY = pvy;
			mCurrFingerDiffX = cvx;
			mCurrFingerDiffY = cvy;

			mFocusX = cx0 + cvx * 0.5f;
			mFocusY = cy0 + cvy * 0.5f;
			mTimeDelta = curr.EventTime - prev.EventTime;
			mCurrPressure = curr.GetPressure(currIndex0) + curr.GetPressure(currIndex1);
			mPrevPressure = prev.GetPressure(prevIndex0) + prev.GetPressure(prevIndex1);
		}
		int FindNewActiveIndex(MotionEvent ev, int otherActiveId, int removedPointerIndex)
		{
			int pointerCount = ev.PointerCount;

			// It's ok if this isn't found and returns -1, it simply won't match.
			int otherActiveIndex = ev.FindPointerIndex(otherActiveId);

			// Pick a new id and update tracking state.
			for (int i = 0; i < pointerCount; i++) {
				if (i != removedPointerIndex && i != otherActiveIndex) {
					return i;
				}
			}
			return -1;
		}
		//TODO: Step 5 - Subscribe to touch events in the view
        public override bool OnTouchEvent(MotionEvent ev)
        {
            Log.Debug(GetType().FullName, "Number of touches: {0}", ev.PointerCount);

            Log.Debug(GetType().FullName, "Touch Type: {0}", ev.Action);

            float width = _icon.IntrinsicWidth, height = _icon.IntrinsicHeight;

			//TODO: Step 6 - Detect scale events
            _scaleDetector.OnTouchEvent(ev);

            MotionEventActions action = ev.Action & MotionEventActions.Mask;
            int pointerIndex;

            switch (action)
            {
				case MotionEventActions.Down:
					_lastTouchX = ev.GetX ();
					_lastTouchY = ev.GetY ();
					_activePointerId = ev.GetPointerId (0);
                    break;

				case MotionEventActions.Move:
					pointerIndex = ev.FindPointerIndex (_activePointerId);
					float x = ev.GetX (pointerIndex);
					float y = ev.GetY (pointerIndex);

					if (!_scaleDetector.IsInProgress) {
						// Only move the ScaleGestureDetector isn't already processing a gesture.
						float deltaX = x - _lastTouchX;
						float deltaY = y - _lastTouchY;
						_posX += deltaX;
						_posY += deltaY;
						Invalidate ();
					}

					_lastTouchX = x;
					_lastTouchY = y;
                    break;

                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    // This events occur when something cancels the gesture (for example the
                    // activity going in the background) or when the pointer has been lifted up.
                    // We no longer need to keep track of the active pointer.
                    _activePointerId = InvalidPointerId;
                    break;

				case MotionEventActions.PointerUp:
                    // We only want to update the last touch position if the the appropriate pointer
                    // has been lifted off the screen.
					pointerIndex = (int)(ev.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
					int pointerId = ev.GetPointerId (pointerIndex);
					if (pointerId == _activePointerId) {
						// This was our active pointer going up. Choose a new
						// action pointer and adjust accordingly
						int newPointerIndex = pointerIndex == 0 ? 1 : 0;
						_lastTouchX = ev.GetX (newPointerIndex);
						_lastTouchY = ev.GetY (newPointerIndex);
						_activePointerId = ev.GetPointerId (newPointerIndex);
					}
                    break;
            }

            //Determine if the image is within the touch area
            if (Math.Abs(_scaleFactor - 1.0f) > 0.001) { width *= _scaleFactor; height *= _scaleFactor; }
            var rc = new RectF(_posX, _posY, _posX + width, _posY + height);
            float touchX = ev.GetX(), touchY = ev.GetY();
            bool contains = rc.Contains(touchX, touchY);
            Log.Debug(GetType().FullName, "{0} - ({1},{2}) - CONTAINS: {3}", rc, touchX, touchY, contains);

            return true;
        }