Smooth animation when dropping a widget in multi-window mode.

Factored in app widget scaling in methods related to estimating
widget size and positions.
ie. Dropping a widget that needs to be resized to fit in the
workspace.

Bug: 32176631
Change-Id: I106fe12041565a090047f146a07d4bc80a074b4a
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index c0087c4..2eed264 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -951,7 +951,7 @@
                 lp.tmpCellX = cellX;
                 lp.tmpCellY = cellY;
             }
-            clc.setupLp(lp);
+            clc.setupLp(child);
             lp.isLockedToGrid = false;
             final int newX = lp.x;
             final int newY = lp.y;
@@ -972,7 +972,7 @@
             va.addUpdateListener(new AnimatorUpdateListener() {
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
-                    float r = ((Float) animation.getAnimatedValue()).floatValue();
+                    float r = (Float) animation.getAnimatedValue();
                     lp.x = (int) ((1 - r) * oldX + r * newX);
                     lp.y = (int) ((1 - r) * oldY + r * newY);
                     child.requestLayout();
@@ -1027,6 +1027,11 @@
 
             if (resize) {
                 cellToRect(cellX, cellY, spanX, spanY, r);
+                if (v instanceof LauncherAppWidgetHostView) {
+                    DeviceProfile profile = mLauncher.getDeviceProfile();
+                    Utilities.shrinkRectAboutCenter(r, profile.appWidgetScale.x,
+                            profile.appWidgetScale.y);
+                }
             } else {
                 // Find the top left corner of the rect the object will occupy
                 final int[] topLeft = mTmpPoint;
@@ -1065,7 +1070,7 @@
                 r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
             }
 
-            Utilities.scaleRectAboutCenter(r, mChildScale);
+            Utilities.shrinkRectAboutCenter(r, mChildScale, mChildScale);
             mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
             mDragOutlineAnims[mDragOutlineCurrent].animateIn();
 
@@ -1836,7 +1841,7 @@
      * the provided point and the provided cell
      */
     private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
-        double angle = Math.atan(((float) deltaY) / deltaX);
+        double angle = Math.atan(deltaY / deltaX);
 
         result[0] = 0;
         result[1] = 0;
@@ -2051,7 +2056,7 @@
             va.addUpdateListener(new AnimatorUpdateListener() {
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
-                    float r = ((Float) animation.getAnimatedValue()).floatValue();
+                    float r = (Float) animation.getAnimatedValue();
                     float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r;
                     float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
                     float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 6c73762..eebce45 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -86,8 +86,15 @@
         }
     }
 
-    public void setupLp(CellLayout.LayoutParams lp) {
-        lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX);
+    public void setupLp(View child) {
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+        if (child instanceof LauncherAppWidgetHostView) {
+            DeviceProfile profile = mLauncher.getDeviceProfile();
+            lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX,
+                    profile.appWidgetScale.x, profile.appWidgetScale.y);
+        } else {
+            lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX);
+        }
     }
 
     // Set whether or not to invert the layout horizontally if the layout is in RTL mode.
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 197aaf7..ce6d5a4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -249,19 +249,18 @@
         return delta;
     }
 
-    public static void scaleRectAboutCenter(Rect r, float scale) {
-        if (scale != 1.0f) {
-            int cx = r.centerX();
-            int cy = r.centerY();
-            r.offset(-cx, -cy);
+    public static float shrinkRectAboutCenter(Rect r, float scaleX, float scaleY) {
+        float scale = Math.min(Math.min(scaleX, scaleY), 1.0f);
+        if (scale < 1.0f) {
+            int deltaX = (int) (r.width() * (scaleX - scale) * 0.5f);
+            r.left += deltaX;
+            r.right -= deltaX;
 
-            r.left = (int) (r.left * scale + 0.5f);
-            r.top = (int) (r.top * scale + 0.5f);
-            r.right = (int) (r.right * scale + 0.5f);
-            r.bottom = (int) (r.bottom * scale + 0.5f);
-
-            r.offset(cx, cy);
+            int deltaY = (int) (r.height() * (scaleY - scale) * 0.5f);
+            r.top += deltaY;
+            r.bottom -= deltaY;
         }
+        return scale;
     }
 
     public static void startActivityForResultSafely(
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 49e14e4..3ba461a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -383,17 +383,37 @@
         mOnStateChangeListener = listener;
     }
 
-    // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
-    // dimension if unsuccessful
-    public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded) {
+    /**
+     * Estimates the size of an item using spans: hSpan, vSpan.
+     *
+     * @param springLoaded True if we are in spring loaded mode.
+     * @param unscaledSize True if caller wants to return the unscaled size
+     * @return MAX_VALUE for each dimension if unsuccessful.
+     */
+    public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded, boolean unscaledSize) {
         float shrinkFactor = mLauncher.getDeviceProfile().workspaceSpringLoadShrinkFactor;
         int[] size = new int[2];
         if (getChildCount() > 0) {
             // Use the first non-custom page to estimate the child position
             CellLayout cl = (CellLayout) getChildAt(numCustomPages());
+            boolean isWidget = itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+
             Rect r = estimateItemPosition(cl, 0, 0, itemInfo.spanX, itemInfo.spanY);
+
+            float scale = 1;
+            if (isWidget) {
+                DeviceProfile profile = mLauncher.getDeviceProfile();
+                scale = Utilities.shrinkRectAboutCenter(r, profile.appWidgetScale.x,
+                        profile.appWidgetScale.y);
+            }
             size[0] = r.width();
             size[1] = r.height();
+
+            if (isWidget && unscaledSize) {
+                size[0] /= scale;
+                size[1] /= scale;
+            }
+
             if (springLoaded) {
                 size[0] *= shrinkFactor;
                 size[1] *= shrinkFactor;
@@ -3451,7 +3471,7 @@
     }
 
     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
-        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false);
+        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false, true);
         int visibility = layout.getVisibility();
         layout.setVisibility(VISIBLE);
 
@@ -3477,6 +3497,10 @@
         int spanY = info.spanY;
 
         Rect r = estimateItemPosition(layout, targetCell[0], targetCell[1], spanX, spanY);
+        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
+            DeviceProfile profile = mLauncher.getDeviceProfile();
+            Utilities.shrinkRectAboutCenter(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
+        }
         loc[0] = r.left;
         loc[1] = r.top;
 
@@ -3488,11 +3512,8 @@
         float dragViewScaleX = 1f;
         float dragViewScaleY = 1f;
         if (scale) {
-            float width = info.spanX * layout.mCellWidth;
-            float height = info.spanY * layout.mCellHeight;
-
-            dragViewScaleX = r.width() / width;
-            dragViewScaleY = r.height() / height;
+            dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
+            dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
         }
 
         // The animation will scale the dragView about its center, so we need to center about
diff --git a/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
index ac50332..37cc9ad 100644
--- a/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
+++ b/src/com/android/launcher3/dragndrop/ExternalDragPreviewProvider.java
@@ -45,7 +45,7 @@
         mLauncher = launcher;
         mAddInfo = addInfo;
 
-        mOutlineSize = mLauncher.getWorkspace().estimateItemSize(mAddInfo, false);
+        mOutlineSize = mLauncher.getWorkspace().estimateItemSize(mAddInfo, false, false);
     }
 
     public Rect getPreviewBounds() {
diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
index 7c06701..722fbb8 100644
--- a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
+++ b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
@@ -45,7 +45,7 @@
     @Override
     public Bitmap createDragOutline(Canvas canvas) {
         Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace();
-        int[] size = workspace.estimateItemSize(mAddInfo, false);
+        int[] size = workspace.estimateItemSize(mAddInfo, false, false);
 
         int w = size[0];
         int h = size[1];
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 049871f..b196053 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -130,7 +130,7 @@
                 mWidgetLoadingId = -1;
 
                 hostView.setVisibility(View.INVISIBLE);
-                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false);
+                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false, true);
                 // We want the first widget layout to be the correct size. This will be important
                 // for width size reporting to the AppWidgetManager.
                 DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 165d12e..d0ead48 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -200,7 +200,7 @@
             // the widget if this is null, so we break out.
 
             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
-            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
+            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true, false);
 
             Bitmap icon = image.getBitmap();
             float minScale = 1.25f;