protected boolean findAndSetEmptyCells(ShortcutInfo item) {
   int[] emptyCell = new int[2];
   if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
     item.cellX = emptyCell[0];
     item.cellY = emptyCell[1];
     return true;
   } else {
     return false;
   }
 }
  private void placeInReadingOrder(ArrayList<ShortcutInfo> items) {
    int maxX = 0;
    int count = items.size();
    for (int i = 0; i < count; i++) {
      ShortcutInfo item = items.get(i);
      if (item.cellX > maxX) {
        maxX = item.cellX;
      }
    }

    GridComparator gridComparator = new GridComparator(maxX + 1);
    Collections.sort(items, gridComparator);
    final int countX = mContent.getCountX();
    for (int i = 0; i < count; i++) {
      int x = i % countX;
      int y = i / countX;
      ShortcutInfo item = items.get(i);
      item.cellX = x;
      item.cellY = y;
    }
  }
  public void onDrop(DragObject d) {
    Runnable cleanUpRunnable = null;

    // If we are coming from All Apps space, we defer removing the extra empty screen
    // until the folder closes
    if (d.dragSource != mLauncher.getWorkspace() && !(d.dragSource instanceof Folder)) {
      cleanUpRunnable =
          new Runnable() {
            @Override
            public void run() {
              mLauncher.exitSpringLoadedDragModeDelayed(
                  true, Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
            }
          };
    }

    View currentDragView;
    ShortcutInfo si = mCurrentDragInfo;
    if (mIsExternalDrag) {
      si.cellX = mEmptyCell[0];
      si.cellY = mEmptyCell[1];

      // Actually move the item in the database if it was an external drag. Call this
      // before creating the view, so that ShortcutInfo is updated appropriately.
      LauncherModel.addOrMoveItemInDatabase(mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);

      // We only need to update the locations if it doesn't get handled in #onDropCompleted.
      if (d.dragSource != this) {
        updateItemLocationsInDatabaseBatch();
      }
      mIsExternalDrag = false;

      currentDragView = createAndAddShortcut(si);
    } else {
      currentDragView = mCurrentDragView;
      CellLayout.LayoutParams lp = (CellLayout.LayoutParams) currentDragView.getLayoutParams();
      si.cellX = lp.cellX = mEmptyCell[0];
      si.cellX = lp.cellY = mEmptyCell[1];
      mContent.addViewToCellLayout(currentDragView, -1, (int) si.id, lp, true);
    }

    if (d.dragView.hasDrawn()) {

      // Temporarily reset the scale such that the animation target gets calculated correctly.
      float scaleX = getScaleX();
      float scaleY = getScaleY();
      setScaleX(1.0f);
      setScaleY(1.0f);
      mLauncher
          .getDragLayer()
          .animateViewIntoPosition(d.dragView, currentDragView, cleanUpRunnable, null);
      setScaleX(scaleX);
      setScaleY(scaleY);
    } else {
      d.deferDragViewCleanupPostAnimation = false;
      currentDragView.setVisibility(VISIBLE);
    }
    mItemsInvalidated = true;
    setupContentDimensions(getItemCount());

    // Temporarily suppress the listener, as we did all the work already here.
    mSuppressOnAdd = true;
    mInfo.add(si);
    mSuppressOnAdd = false;
    // Clear the drag info, as it is no longer being dragged.
    mCurrentDragInfo = null;
  }