private boolean drop(float x, float y) {
    invalidate();

    final int[] coordinates = mDropCoordinates;
    DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);

    if (mTagPopup != null) {
      // don't perform dismiss action when the popup closes
      ((QuickActionWindow) mTagPopup).setOnDismissListener(null);
    }
    if (dropTarget != null) {
      dropTarget.onDragExit(
          mDragSource,
          coordinates[0],
          coordinates[1],
          (int) mTouchOffsetX,
          (int) mTouchOffsetY,
          mDragInfo);
      if (dropTarget.acceptDrop(
          mDragSource,
          coordinates[0],
          coordinates[1],
          (int) mTouchOffsetX,
          (int) mTouchOffsetY,
          mDragInfo)) {
        boolean success = false;
        if (mTagPopup == null || !(dropTarget instanceof Workspace)) {
          mTagPopup = null;
          dropTarget.onDrop(
              mDragSource,
              coordinates[0],
              coordinates[1],
              (int) mTouchOffsetX,
              (int) mTouchOffsetY,
              mDragInfo);
          success = true;
        }
        mDragSource.onDropCompleted((View) dropTarget, success);
        return true;
      } else {
        mDragSource.onDropCompleted((View) dropTarget, false);
        return true;
      }
    }
    return false;
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (!mDragging) {
      return false;
    }

    final int action = ev.getAction();
    final float x = ev.getX();
    final float y = ev.getY();

    switch (action) {
      case MotionEvent.ACTION_DOWN:

        // Remember where the motion event started
        mLastMotionX = x;
        mLastMotionY = y;

        if ((x < SCROLL_ZONE) || (x > getWidth() - SCROLL_ZONE)) {
          mScrollState = SCROLL_WAITING_IN_ZONE;
          postDelayed(mScrollRunnable, SCROLL_DELAY);
        } else {
          mScrollState = SCROLL_OUTSIDE_ZONE;
        }

        break;
      case MotionEvent.ACTION_MOVE:
        final int scrollX = mScrollX;
        final int scrollY = mScrollY;

        final float touchX = mTouchOffsetX;
        final float touchY = mTouchOffsetY;

        final int offsetX = mBitmapOffsetX;
        final int offsetY = mBitmapOffsetY;

        int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
        int top = (int) (scrollY + mLastMotionY - touchY - offsetY);

        int width;
        int height;
        if (mDrawModeBitmap && mDragBitmap != null) {
          final Bitmap dragBitmap = mDragBitmap;
          width = dragBitmap.getWidth();
          height = dragBitmap.getHeight();
        } else {
          width = mDrawWidth;
          height = mDrawHeight;
        }
        final Rect rect = mRect;
        rect.set(left - 1, top - 1, left + width + 1, top + height + 1);

        mLastMotionX = x;
        mLastMotionY = y;

        left = (int) (scrollX + x - touchX - offsetX);
        top = (int) (scrollY + y - touchY - offsetY);

        // Invalidate current icon position
        rect.union(left - 1, top - 1, left + width + 1, top + height + 1);

        final int[] coordinates = mDropCoordinates;
        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
        if (dropTarget != null) {
          if (mLastDropTarget == dropTarget) {
            dropTarget.onDragOver(
                mDragSource,
                coordinates[0],
                coordinates[1],
                (int) mTouchOffsetX,
                (int) mTouchOffsetY,
                mDragInfo);
          } else {
            if (mLastDropTarget != null) {
              mLastDropTarget.onDragExit(
                  mDragSource,
                  coordinates[0],
                  coordinates[1],
                  (int) mTouchOffsetX,
                  (int) mTouchOffsetY,
                  mDragInfo);
            }
            dropTarget.onDragEnter(
                mDragSource,
                coordinates[0],
                coordinates[1],
                (int) mTouchOffsetX,
                (int) mTouchOffsetY,
                mDragInfo);
          }
        } else {
          if (mLastDropTarget != null) {
            mLastDropTarget.onDragExit(
                mDragSource,
                coordinates[0],
                coordinates[1],
                (int) mTouchOffsetX,
                (int) mTouchOffsetY,
                mDragInfo);
          }
        }

        invalidate(rect);

        mLastDropTarget = dropTarget;
        if (mTagPopup != null) {
          if (Math.abs(mOriginalX - mLastMotionX) > SCROLL_ZONE
              || Math.abs(mOriginalY - mLastMotionY) > SCROLL_ZONE) {
            final QuickActionWindow qa = (QuickActionWindow) mTagPopup;
            qa.dismiss();
            mTagPopup = null;
          }
        }
        boolean inDragRegion = false;
        if (mDragRegion != null) {
          final RectF region = mDragRegion;
          final boolean inRegion = region.contains(ev.getRawX(), ev.getRawY());
          if (!mEnteredRegion && inRegion) {
            mDragPaint = mTrashPaint;
            mRectPaint.setColor(COLOR_TRASH);
            mEnteredRegion = true;
            inDragRegion = true;
          } else if (mEnteredRegion && !inRegion) {
            mDragPaint = null;
            mRectPaint.setColor(COLOR_NORMAL);
            mEnteredRegion = false;
          }
        }

        if (!inDragRegion && x < SCROLL_ZONE) {
          if (mScrollState == SCROLL_OUTSIDE_ZONE) {
            mScrollState = SCROLL_WAITING_IN_ZONE;
            mScrollRunnable.setDirection(SCROLL_LEFT);
            postDelayed(mScrollRunnable, SCROLL_DELAY);
          }
        } else if (!inDragRegion && x > getWidth() - SCROLL_ZONE) {
          if (mScrollState == SCROLL_OUTSIDE_ZONE) {
            mScrollState = SCROLL_WAITING_IN_ZONE;
            mScrollRunnable.setDirection(SCROLL_RIGHT);
            postDelayed(mScrollRunnable, SCROLL_DELAY);
          }
        } else {
          if (mScrollState == SCROLL_WAITING_IN_ZONE) {
            mScrollState = SCROLL_OUTSIDE_ZONE;
            mScrollRunnable.setDirection(SCROLL_RIGHT);
            removeCallbacks(mScrollRunnable);
          }
        }

        break;
      case MotionEvent.ACTION_UP:
        removeCallbacks(mScrollRunnable);
        if (mShouldDrop) {
          drop(x, y);
          mShouldDrop = false;
        }
        endDrag();

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

    return true;
  }