// TODO unify this with Android code
        private void OnMouseButtonChange(object sender, MouseButtonEventArgs e)
        {
            double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            float xConversion = SparrowSharpApp.Stage.Width / Size.Width;
            float yConversion = SparrowSharpApp.Stage.Height / Size.Height;
            Touch touchInFocus;

            if (e.Mouse.LeftButton == ButtonState.Pressed)
            {
                Touch newTouch = new Touch();
                newTouch.TouchID = pointerId;
                newTouch.TimeStamp = now;
                newTouch.GlobalX = e.Mouse.X * xConversion;
                newTouch.GlobalY = e.Mouse.Y * yConversion;
                newTouch.InitialGlobalX = newTouch.GlobalX;
                newTouch.InitialGlobalY = newTouch.GlobalY;
                newTouch.Phase = TouchPhase.Began;
                Point touchPosition = Point.Create(newTouch.GlobalX, newTouch.GlobalY);
                newTouch.Target = SparrowSharpApp.Stage.HitTestPoint(touchPosition);

                _touches.Add(newTouch.TouchID, newTouch);
            }
            else
            {
                touchInFocus = _touches[pointerId];
                touchInFocus.Phase = TouchPhase.Ended;
                long downTime = -1; // TODO
                touchInFocus.TimeStamp = now;
                double dist = Math.Sqrt(
                                  (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) * (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) +
                                  (touchInFocus.GlobalY - touchInFocus.InitialGlobalY) * (touchInFocus.GlobalY - touchInFocus.InitialGlobalY));
                // TODO: move the time out to a constant, make dist DPI dependent
                if (downTime < 300 && dist < 50)
                {
                    touchInFocus.IsTap = true;
                }
            }
            processTouch();
        }
        /// <summary>
        /// This function handles touch events. 
        /// It is responsible for maintaining the currently active touch events and dispatching events.
        /// For details see http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent)
        /// </summary>
        override public bool OnTouchEvent(MotionEvent e)
        {
            float xConversion = SparrowSharpApp.Stage.Width / Size.Width;
            float yConversion = SparrowSharpApp.Stage.Height / Size.Height;

            // get pointer index from the event object
            int pointerIndex = e.ActionIndex;
            Touch touchInFocus;
            // get pointer ID
            int pointerId = e.GetPointerId(pointerIndex);

            double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;

            // get masked (not specific to a pointer) action
            MotionEventActions maskedAction = e.ActionMasked;

            switch (maskedAction)
            {
                case MotionEventActions.Down:
                case MotionEventActions.PointerDown:
                    // new pointer
                    Touch newTouch = new Touch();
                    newTouch.TouchID = pointerId;
                    newTouch.TimeStamp = now;
                    newTouch.GlobalX = e.GetX() * xConversion;
                    newTouch.GlobalY = e.GetY() * yConversion;
                    newTouch.InitialGlobalX = newTouch.GlobalX;
                    newTouch.InitialGlobalY = newTouch.GlobalY;
                    newTouch.Phase = TouchPhase.Began;
                    Point touchPosition = Point.Create(newTouch.GlobalX, newTouch.GlobalY);
                    newTouch.Target = SparrowSharpApp.Stage.HitTestPoint(touchPosition);

                    _touches.Add(newTouch.TouchID, newTouch);
                    break;
                case MotionEventActions.Move:
                    for (int size = e.PointerCount, i = 0; i < size; i++)
                    {
                        Touch movedTouch;
                        _touches.TryGetValue(e.GetPointerId(i), out movedTouch);
                        if (movedTouch != null)
                        {
                            // TODO: should we care about historical pointer events?
                            movedTouch.PreviousGlobalX = movedTouch.GlobalX;
                            movedTouch.PreviousGlobalY = movedTouch.GlobalY;
                            movedTouch.TimeStamp = now;
                            float xc = e.GetX(i) * xConversion;
                            float yc = e.GetY(i) * yConversion;
                            if (movedTouch.GlobalX == xc && movedTouch.GlobalY == yc)
                            {
                                movedTouch.Phase = TouchPhase.Stationary;
                            }
                            else
                            {
                                movedTouch.GlobalX = xc;
                                movedTouch.GlobalY = yc;
                                movedTouch.Phase = TouchPhase.Moved;
                            }
                            if (movedTouch.Target == null || movedTouch.Target.Stage == null)
                            {
                                // target could have been removed from stage -> find new target in that case
                                Point updatedTouchPosition = Point.Create(movedTouch.GlobalX, movedTouch.GlobalY);
                                movedTouch.Target = SparrowSharpApp.Root.HitTestPoint(updatedTouchPosition);
                            }
                        }
                    }
                    break;
                case MotionEventActions.Up:
                case MotionEventActions.PointerUp:
                    touchInFocus = _touches[pointerId];
                    touchInFocus.Phase = TouchPhase.Ended;
                    long downTime = Android.OS.SystemClock.UptimeMillis() - e.DownTime;
                    touchInFocus.TimeStamp = now;
                    double dist = Math.Sqrt(
                                      (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) * (touchInFocus.GlobalX - touchInFocus.InitialGlobalX) +
                                      (touchInFocus.GlobalY - touchInFocus.InitialGlobalY) * (touchInFocus.GlobalY - touchInFocus.InitialGlobalY));
                    // TODO: move the time out to a constant, make dist DPI dependent
                    if (downTime < 300 && dist < 50)
                    {
                        touchInFocus.IsTap = true;
                    }
                    break;
                case MotionEventActions.Cancel:
                    touchInFocus = _touches[pointerId];
                    touchInFocus.Phase = TouchPhase.Cancelled;
                    break;
            }

            foreach (Touch tou in _touches.Values)
            {
                TouchEvent touchEvent = new TouchEvent(new List<Touch>(_touches.Values));
                if (tou.Target != null)
                {
                    tou.Target.InvokeTouch(touchEvent);
                }
                //Console.WriteLine ("phase:" + tou.Phase + " ID:" + tou.TouchID + 
                //    " target:" + tou.Target + " isTap:"+ tou.IsTap + " timestamp:" + tou.TimeStamp);
            }

            var touchList = new List<Touch>(_touches.Values);
            foreach (Touch tou in touchList)
            {
                if (tou.Phase == TouchPhase.Ended || tou.Phase == TouchPhase.Cancelled)
                {
                    _touches.Remove(tou.TouchID);
                }
            }
            return true;
        }
        void processTouches(UIEvent evt)
        {
            if (_lastTouchTimestamp != evt.Timestamp)
            {
                SizeF size = Bounds.Size;

                float xConversion = SparrowSharpApp.Stage.Width / size.Width;
                float yConversion = SparrowSharpApp.Stage.Height / size.Height;

                // convert to Touches and forward to stage
                List<Touch> touches = new List<Touch>();

                double now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
                foreach (UITouch uiTouch in evt.TouchesForView(this))
                {
                    PointF location = uiTouch.LocationInView(this);
                    PointF previousLocation = uiTouch.PreviousLocationInView(this);

                    Touch touch = new Touch();
                    touch.TouchID = uiTouch.Handle.ToInt32();
                    touch.TimeStamp = now;
                    touch.GlobalX = location.X * xConversion;
                    touch.GlobalY = location.Y * yConversion;
                    touch.PreviousGlobalX = previousLocation.X * xConversion;
                    touch.PreviousGlobalY = previousLocation.Y * yConversion;
                    if (uiTouch.Phase == UITouchPhase.Began)
                    {
                        touch.InitialGlobalX = touch.GlobalX;
                        touch.InitialGlobalY = touch.GlobalY;
                    }
                    touch.IsTap = (uiTouch.TapCount != 0);
                    touch.Phase = (TouchPhase) uiTouch.Phase;

                    touches.Add(touch);
                }

                _touchProcessor.ProcessTouches(touches);

                _lastTouchTimestamp = evt.Timestamp;
            }
        }