Widget preview improvements

- Make widget preview bitmaps as small as they can be, saving ~0.7-2MB peak memory (5104303)
- When adding/dragging a widget, make the drag outline/drag view much more closely match the actual size (5566938)

Change-Id: I5b5b7b84fa551d56432a76223b1a9e4de620ff56
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index cde0b4b..af5141f 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -86,18 +86,17 @@
         items = l;
         sourceImages = si;
         generatedImages = new ArrayList<Bitmap>();
-        cellWidth = cellHeight = -1;
+        maxImageWidth = maxImageHeight = -1;
         doInBackgroundCallback = bgR;
         postExecuteCallback = postR;
     }
-    AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, int ccx, AsyncTaskCallback bgR,
+    AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR,
             AsyncTaskCallback postR) {
         page = p;
         items = l;
         generatedImages = new ArrayList<Bitmap>();
-        cellWidth = cw;
-        cellHeight = ch;
-        cellCountX = ccx;
+        maxImageWidth = cw;
+        maxImageHeight = ch;
         doInBackgroundCallback = bgR;
         postExecuteCallback = postR;
     }
@@ -124,9 +123,8 @@
     ArrayList<Object> items;
     ArrayList<Bitmap> sourceImages;
     ArrayList<Bitmap> generatedImages;
-    int cellWidth;
-    int cellHeight;
-    int cellCountX;
+    int maxImageWidth;
+    int maxImageHeight;
     AsyncTaskCallback doInBackgroundCallback;
     AsyncTaskCallback postExecuteCallback;
 }
@@ -537,26 +535,23 @@
 
         // Compose the drag image
         Bitmap b;
-        Drawable preview = image.getDrawable();
-        RectF mTmpScaleRect = new RectF(0f,0f,1f,1f);
-        image.getImageMatrix().mapRect(mTmpScaleRect);
-        float scale = mTmpScaleRect.right;
-        int w = (int) (preview.getIntrinsicWidth() * scale);
-        int h = (int) (preview.getIntrinsicHeight() * scale);
         if (createItemInfo instanceof PendingAddWidgetInfo) {
             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
             int[] spanXY = mLauncher.getSpanForWidget(createWidgetInfo, null);
             createItemInfo.spanX = spanXY[0];
             createItemInfo.spanY = spanXY[1];
 
-            b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-            renderDrawableToBitmap(preview, b, 0, 0, w, h, scale, mDragViewMultiplyColor);
+            int[] maxSize = mLauncher.getWorkspace().estimateItemSize(spanXY[0], spanXY[1],
+                    createWidgetInfo, true);
+            b = getWidgetPreview(createWidgetInfo.componentName, createWidgetInfo.previewImage,
+                    createWidgetInfo.icon, spanXY[0], spanXY[1], maxSize[0], maxSize[1]);
         } else {
             // Workaround for the fact that we don't keep the original ResolveInfo associated with
             // the shortcut around.  To get the icon, we just render the preview image (which has
             // the shortcut icon) to a new drag bitmap that clips the non-icon space.
             b = Bitmap.createBitmap(mWidgetPreviewIconPaddedDimension,
                     mWidgetPreviewIconPaddedDimension, Bitmap.Config.ARGB_8888);
+            Drawable preview = image.getDrawable();
             mCanvas.setBitmap(b);
             mCanvas.save();
             preview.draw(mCanvas);
@@ -569,7 +564,7 @@
         // We use a custom alpha clip table for the default widget previews
         Paint alphaClipPaint = null;
         if (createItemInfo instanceof PendingAddWidgetInfo) {
-            if (((PendingAddWidgetInfo) createItemInfo).hasDefaultPreview) {
+            if (((PendingAddWidgetInfo) createItemInfo).previewImage != 0) {
                 MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(0, 255);
                 alphaClipPaint = new Paint();
                 alphaClipPaint.setMaskFilter(alphaClipTable);
@@ -578,8 +573,7 @@
 
         // Start the drag
         mLauncher.lockScreenOrientationOnLargeUI();
-        mLauncher.getWorkspace().onDragStartedWithItemSpans(createItemInfo.spanX,
-                createItemInfo.spanY, b, alphaClipPaint);
+        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, b, alphaClipPaint);
         mDragController.startDrag(image, b, this, createItemInfo,
                 DragController.DRAG_ACTION_COPY, null);
         b.recycle();
@@ -790,7 +784,7 @@
         // We introduce a slight delay to order the loading of side pages so that we don't thrash
         final int sleepMs = getSleepForPage(page + mNumAppsPages);
         AsyncTaskPageData pageData = new AsyncTaskPageData(page, widgets, cellWidth, cellHeight,
-            cellCountX, new AsyncTaskCallback() {
+            new AsyncTaskCallback() {
                 @Override
                 public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
                     try {
@@ -936,7 +930,7 @@
             c.setBitmap(null);
         }
     }
-    private Bitmap getShortcutPreview(ResolveInfo info, int cellWidth, int cellHeight) {
+    private Bitmap getShortcutPreview(ResolveInfo info) {
         // Render the background
         int offset = 0;
         int bitmapSize = mAppIconSize;
@@ -947,73 +941,71 @@
         renderDrawableToBitmap(icon, preview, offset, offset, mAppIconSize, mAppIconSize);
         return preview;
     }
-    private Bitmap getWidgetPreview(AppWidgetProviderInfo info,
-            int cellHSpan, int cellVSpan, int cellWidth, int cellHeight) {
 
+    private Bitmap getWidgetPreview(ComponentName provider, int previewImage, int iconId,
+            int cellHSpan, int cellVSpan, int maxWidth, int maxHeight) {
         // Load the preview image if possible
-        String packageName = info.provider.getPackageName();
-        Drawable drawable = null;
-        Bitmap preview = null;
-        if (info.previewImage != 0) {
-            drawable = mPackageManager.getDrawable(packageName, info.previewImage, null);
-            if (drawable == null) {
-                Log.w(LOG_TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
-                        + " for provider: " + info.provider);
-            } else {
-                // Map the target width/height to the cell dimensions
-                int targetWidth = mWidgetSpacingLayout.estimateCellWidth(cellHSpan);
-                int targetHeight = mWidgetSpacingLayout.estimateCellHeight(cellVSpan);
-                int targetCellWidth;
-                int targetCellHeight;
-                if (targetWidth >= targetHeight) {
-                    targetCellWidth = Math.min(targetWidth, cellWidth);
-                    targetCellHeight = (int) (cellHeight * ((float) targetCellWidth / cellWidth));
-                } else {
-                    targetCellHeight = Math.min(targetHeight, cellHeight);
-                    targetCellWidth = (int) (cellWidth * ((float) targetCellHeight / cellHeight));
-                }
-                // Map the preview to the target cell dimensions
-                int bitmapWidth = Math.min(targetCellWidth, drawable.getIntrinsicWidth());
-                int bitmapHeight = (int) (drawable.getIntrinsicHeight() *
-                        ((float) bitmapWidth / drawable.getIntrinsicWidth()));
+        String packageName = provider.getPackageName();
+        if (maxWidth < 0) maxWidth = Integer.MAX_VALUE;
+        if (maxHeight < 0) maxHeight = Integer.MAX_VALUE;
 
-                preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
-                renderDrawableToBitmap(drawable, preview, 0, 0, bitmapWidth, bitmapHeight);
+        Drawable drawable = null;
+        if (previewImage != 0) {
+            drawable = mPackageManager.getDrawable(packageName, previewImage, null);
+            if (drawable == null) {
+                Log.w(LOG_TAG, "Can't load widget preview drawable 0x" +
+                        Integer.toHexString(previewImage) + " for provider: " + provider);
             }
         }
 
-        // Generate a preview image if we couldn't load one
-        if (drawable == null) {
+        int bitmapWidth;
+        int bitmapHeight;
+        boolean widgetPreviewExists = (drawable != null);
+        if (widgetPreviewExists) {
+            bitmapWidth = drawable.getIntrinsicWidth();
+            bitmapHeight = drawable.getIntrinsicHeight();
+
+            // Cap the size so widget previews don't appear larger than the actual widget
+            maxWidth = Math.min(maxWidth, mWidgetSpacingLayout.estimateCellWidth(cellHSpan));
+            maxHeight = Math.min(maxHeight, mWidgetSpacingLayout.estimateCellHeight(cellVSpan));
+        } else {
+            // Determine the size of the bitmap for the preview image we will generate
             // TODO: This actually uses the apps customize cell layout params, where as we make want
             // the Workspace params for more accuracy.
-            int targetWidth = mWidgetSpacingLayout.estimateCellWidth(cellHSpan);
-            int targetHeight = mWidgetSpacingLayout.estimateCellHeight(cellVSpan);
-            int bitmapWidth = targetWidth;
-            int bitmapHeight = targetHeight;
-            int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
-            float iconScale = 1f;
-
-            // Determine the size of the bitmap we want to draw
+            bitmapWidth = mWidgetSpacingLayout.estimateCellWidth(cellHSpan);
+            bitmapHeight = mWidgetSpacingLayout.estimateCellHeight(cellVSpan);
             if (cellHSpan == cellVSpan) {
                 // For square widgets, we just have a fixed size for 1x1 and larger-than-1x1
+                int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
                 if (cellHSpan <= 1) {
                     bitmapWidth = bitmapHeight = mAppIconSize + 2 * minOffset;
                 } else {
                     bitmapWidth = bitmapHeight = mAppIconSize + 4 * minOffset;
                 }
-            } else {
-                // Otherwise, ensure that we are properly sized within the cellWidth/Height
-                if (targetWidth >= targetHeight) {
-                    bitmapWidth = Math.min(targetWidth, cellWidth);
-                    bitmapHeight = (int) (targetHeight * ((float) bitmapWidth / targetWidth));
-                    iconScale = Math.min((float) bitmapHeight / (mAppIconSize + 2 * minOffset), 1f);
-                } else {
-                    bitmapHeight = Math.min(targetHeight, cellHeight);
-                    bitmapWidth = (int) (targetWidth * ((float) bitmapHeight / targetHeight));
-                    iconScale = Math.min((float) bitmapWidth / (mAppIconSize + 2 * minOffset), 1f);
-                }
             }
-            preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
+        }
+
+        float scale = 1f;
+        if (bitmapWidth > maxWidth) {
+            scale = maxWidth / (float) bitmapWidth;
+        }
+        if (bitmapHeight * scale > maxHeight) {
+            scale = maxHeight / (float) bitmapHeight;
+        }
+        if (scale != 1f) {
+            bitmapWidth = (int) (scale * bitmapWidth);
+            bitmapHeight = (int) (scale * bitmapHeight);
+        }
+
+        Bitmap preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
+
+        if (widgetPreviewExists) {
+            renderDrawableToBitmap(drawable, preview, 0, 0, bitmapWidth, bitmapHeight);
+        } else {
+            // Generate a preview image if we couldn't load one
+            int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
+            int smallestSide = Math.min(bitmapWidth, bitmapHeight);
+            float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), 1f);
             if (cellHSpan != 1 || cellVSpan != 1) {
                 renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0, bitmapWidth,
                         bitmapHeight);
@@ -1024,7 +1016,7 @@
                 Drawable icon = null;
                 int hoffset = (int) (bitmapWidth / 2 - mAppIconSize * iconScale / 2);
                 int yoffset = (int) (bitmapHeight / 2 - mAppIconSize * iconScale / 2);
-                if (info.icon > 0) icon = mIconCache.getFullResIcon(packageName, info.icon);
+                if (iconId > 0) icon = mIconCache.getFullResIcon(packageName, iconId);
                 Resources resources = mLauncher.getResources();
                 if (icon == null) icon = resources.getDrawable(R.drawable.ic_launcher_application);
 
@@ -1036,16 +1028,16 @@
         return preview;
     }
 
-    public void syncWidgetPageItems(int page, boolean immediate) {
+    public void syncWidgetPageItems(final int page, final boolean immediate) {
         int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-        int contentWidth = mWidgetSpacingLayout.getContentWidth();
-        int contentHeight = mWidgetSpacingLayout.getContentHeight();
 
         // Calculate the dimensions of each cell we are giving to each widget
-        ArrayList<Object> items = new ArrayList<Object>();
-        int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight
+        final ArrayList<Object> items = new ArrayList<Object>();
+        int contentWidth = mWidgetSpacingLayout.getContentWidth();
+        final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight
                 - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX);
-        int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom
+        int contentHeight = mWidgetSpacingLayout.getContentHeight();
+        final int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom
                 - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY);
 
         // Prepare the set of widgets to load previews for in the background
@@ -1055,7 +1047,7 @@
         }
 
         // Prepopulate the pages with the other widget info, and fill in the previews later
-        PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page + mNumAppsPages);
+        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page + mNumAppsPages);
         layout.setColumnCount(layout.getCellCountX());
         for (int i = 0; i < items.size(); ++i) {
             Object rawInfo = items.get(i);
@@ -1098,15 +1090,31 @@
             layout.addView(widget, lp);
         }
 
-        // Load the widget previews
-        if (immediate) {
-            AsyncTaskPageData data = new AsyncTaskPageData(page, items, cellWidth, cellHeight,
-                    mWidgetCountX, null, null);
-            loadWidgetPreviewsInBackground(null, data);
-            onSyncWidgetPageItems(data);
-        } else {
-            prepareLoadWidgetPreviewsTask(page, items, cellWidth, cellHeight, mWidgetCountX);
-        }
+        // wait until a call on onLayout to start loading, because
+        // PagedViewWidget.getPreviewSize() will return 0 if it hasn't been laid out
+        // TODO: can we do a measure/layout immediately?
+        layout.setOnLayoutListener(new Runnable() {
+            public void run() {
+                // Load the widget previews
+                int maxPreviewWidth = cellWidth;
+                int maxPreviewHeight = cellHeight;
+                if (layout.getChildCount() > 0) {
+                    PagedViewWidget w = (PagedViewWidget) layout.getChildAt(0);
+                    int[] maxSize = w.getPreviewSize();
+                    maxPreviewWidth = maxSize[0];
+                    maxPreviewHeight = maxSize[1];
+                }
+                if (immediate) {
+                    AsyncTaskPageData data = new AsyncTaskPageData(page, items,
+                            maxPreviewWidth, maxPreviewHeight, null, null);
+                    loadWidgetPreviewsInBackground(null, data);
+                    onSyncWidgetPageItems(data);
+                } else {
+                    prepareLoadWidgetPreviewsTask(page, items,
+                            maxPreviewWidth, maxPreviewHeight, mWidgetCountX);
+                }
+            }
+        });
     }
     private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
             AsyncTaskPageData data) {
@@ -1119,8 +1127,6 @@
         ArrayList<Object> items = data.items;
         ArrayList<Bitmap> images = data.generatedImages;
         int count = items.size();
-        int cellWidth = data.cellWidth;
-        int cellHeight = data.cellHeight;
         for (int i = 0; i < count; ++i) {
             if (task != null) {
                 // Ensure we haven't been cancelled yet
@@ -1134,12 +1140,13 @@
             if (rawInfo instanceof AppWidgetProviderInfo) {
                 AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
                 int[] cellSpans = mLauncher.getSpanForWidget(info, null);
-                images.add(getWidgetPreview(info, cellSpans[0],cellSpans[1],
-                        cellWidth, cellHeight));
+                Bitmap b = getWidgetPreview(info.provider, info.previewImage, info.icon,
+                        cellSpans[0], cellSpans[1], data.maxImageWidth, data.maxImageHeight);
+                images.add(b);
             } else if (rawInfo instanceof ResolveInfo) {
                 // Fill in the shortcuts information
                 ResolveInfo info = (ResolveInfo) rawInfo;
-                images.add(getShortcutPreview(info, cellWidth, cellHeight));
+                images.add(getShortcutPreview(info));
             }
         }
     }
@@ -1153,11 +1160,7 @@
             PagedViewWidget widget = (PagedViewWidget) layout.getChildAt(i);
             if (widget != null) {
                 Bitmap preview = data.generatedImages.get(i);
-                boolean scale =
-                    (preview.getWidth() >= data.cellWidth ||
-                     preview.getHeight() >= data.cellHeight);
-
-                widget.applyPreview(new FastBitmapDrawable(preview), i, scale);
+                widget.applyPreview(new FastBitmapDrawable(preview), i);
             }
         }
         layout.createHardwareLayer();
diff --git a/src/com/android/launcher2/PagedViewGridLayout.java b/src/com/android/launcher2/PagedViewGridLayout.java
index 93626f0..01d7593 100644
--- a/src/com/android/launcher2/PagedViewGridLayout.java
+++ b/src/com/android/launcher2/PagedViewGridLayout.java
@@ -30,6 +30,7 @@
 
     private int mCellCountX;
     private int mCellCountY;
+    private Runnable mOnLayoutListener;
 
     public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
         super(context, null, 0);
@@ -57,6 +58,17 @@
                 heightMeasureSpec);
     }
 
+    public void setOnLayoutListener(Runnable r) {
+        mOnLayoutListener = r;
+    }
+
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mOnLayoutListener != null) {
+            mOnLayoutListener.run();
+        }
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         boolean result = super.onTouchEvent(event);
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 3eb4db4..7d19846 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -135,13 +135,20 @@
         }
     }
 
-    void applyPreview(FastBitmapDrawable preview, int index, boolean scale) {
+    public int[] getPreviewSize() {
+        final ImageView i = (ImageView) findViewById(R.id.widget_preview);
+        int[] maxSize = new int[2];
+        maxSize[0] = i.getWidth() - i.getPaddingLeft() - i.getPaddingRight();
+        maxSize[1] = i.getHeight() - i.getPaddingBottom() - i.getPaddingTop();
+        return maxSize;
+    }
+
+    void applyPreview(FastBitmapDrawable preview, int index) {
         final PagedViewWidgetImageView image =
                 (PagedViewWidgetImageView) findViewById(R.id.widget_preview);
         if (preview != null) {
             image.mAllowRequestLayout = false;
             image.setImageDrawable(preview);
-            image.setScaleType(scale ? ImageView.ScaleType.FIT_START : ImageView.ScaleType.MATRIX);
             image.mAllowRequestLayout = true;
             image.setAlpha(0f);
             image.animate()
diff --git a/src/com/android/launcher2/PendingAddItemInfo.java b/src/com/android/launcher2/PendingAddItemInfo.java
index e243cc0..9c52ecf 100644
--- a/src/com/android/launcher2/PendingAddItemInfo.java
+++ b/src/com/android/launcher2/PendingAddItemInfo.java
@@ -33,7 +33,8 @@
 class PendingAddWidgetInfo extends PendingAddItemInfo {
     int minWidth;
     int minHeight;
-    boolean hasDefaultPreview;
+    int previewImage;
+    int icon;
 
     // Any configuration data that we want to pass to a configuration activity when
     // starting up a widget
@@ -45,7 +46,8 @@
         componentName = i.provider;
         minWidth = i.minWidth;
         minHeight = i.minHeight;
-        hasDefaultPreview = i.previewImage <= 0;
+        previewImage = i.previewImage;
+        icon = i.icon;
         if (dataMimeType != null && data != null) {
             mimeType = dataMimeType;
             configurationData = data;
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 4ad441d..8ac5248 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -26,6 +26,7 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.AlertDialog;
 import android.app.WallpaperManager;
+import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ClipData;
@@ -314,6 +315,43 @@
         setMotionEventSplittingEnabled(true);
     }
 
+    // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
+    // dimension if unsuccessful
+    public int[] estimateItemSize(int hSpan, int vSpan,
+            PendingAddItemInfo pendingItemInfo, boolean springLoaded) {
+        int[] size = new int[2];
+        if (getChildCount() > 0) {
+            CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
+            RectF r = estimateItemPosition(cl, pendingItemInfo, 0, 0, hSpan, vSpan);
+            size[0] = (int) r.width();
+            size[1] = (int) r.height();
+            if (springLoaded) {
+                size[0] *= mSpringLoadedShrinkFactor;
+                size[1] *= mSpringLoadedShrinkFactor;
+            }
+            return size;
+        } else {
+            size[0] = Integer.MAX_VALUE;
+            size[1] = Integer.MAX_VALUE;
+            return size;
+        }
+    }
+    public RectF estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
+            int hCell, int vCell, int hSpan, int vSpan) {
+        RectF r = new RectF();
+        cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
+        if (pendingInfo instanceof PendingAddWidgetInfo) {
+            PendingAddWidgetInfo widgetInfo = (PendingAddWidgetInfo) pendingInfo;
+            Rect p = AppWidgetHostView.getDefaultPaddingForWidget(mContext,
+                    widgetInfo.componentName, null);
+            r.top += p.top;
+            r.left += p.left;
+            r.right -= p.right;
+            r.bottom -= p.bottom;
+        }
+        return r;
+    }
+
     public void buildPageHardwareLayers() {
         if (getWindowToken() != null) {
             final int childCount = getChildCount();
@@ -1463,11 +1501,7 @@
         mDragOutline = createDragOutline(v, canvas, bitmapPadding);
     }
 
-    public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
-        onDragStartedWithItemSpans(spanX, spanY, b, null);
-    }
-
-    public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b, Paint alphaClipPaint) {
+    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) {
         final Canvas canvas = new Canvas();
 
         // We need to add extra padding to the bitmap to make room for the glow effect
@@ -1475,7 +1509,7 @@
 
         CellLayout cl = (CellLayout) getChildAt(0);
 
-        int[] size = cl.cellSpansToSize(spanX, spanY);
+        int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
 
         // The outline is used to visualize where the item will land if dropped
         mDragOutline = createDragOutline(b, canvas, bitmapPadding, size[0], size[1], alphaClipPaint);
@@ -2916,11 +2950,11 @@
 
             // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
             // location and size on the home screen.
+            RectF r = estimateItemPosition(cellLayout, pendingInfo,
+                    mTargetCell[0], mTargetCell[1], spanX, spanY);
             int loc[] = new int[2];
-            cellLayout.cellToPoint(mTargetCell[0], mTargetCell[1], loc);
-
-            RectF r = new RectF();
-            cellLayout.cellToRect(mTargetCell[0], mTargetCell[1], spanX, spanY, r);
+            loc[0] = (int) r.left;
+            loc[1] = (int) r.top;
             setFinalTransitionTransform(cellLayout);
             float cellLayoutScale =
                     mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc);