Merge "Blocking alpha animation if the initial and final state for the animation are both 0" into ub-launcher3-calgary-polish
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index a82427e..1fb2e82 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -68,7 +68,7 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Cette fonction est désactivée par votre administrateur"</string>
     <string name="accessibility_action_overview" msgid="6257665857640347026">"Présentation"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
-    <string name="allow_rotation_desc" msgid="8662546029078692509">"Quand le téléphone est pivoté"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string>
     <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Le mode d\'affichage actuel ne permet pas le pivotement"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3f2d186..87ef78b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -161,7 +161,7 @@
     <dimen name="deep_shortcuts_spacing">4dp</dimen>
     <dimen name="deep_shortcuts_drag_view_scale">6dp</dimen>
     <!-- an icon with shortcuts must be dragged this far before the container is removed. -->
-    <dimen name="deep_shortcuts_start_drag_threshold">12dp</dimen>
+    <dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
     <dimen name="deep_shortcut_icon_size">36dp</dimen>
     <dimen name="deep_shortcut_padding_start">6dp</dimen>
     <dimen name="deep_shortcut_padding_end">16dp</dimen>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 77f6612..ee21313 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -54,6 +54,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.util.CellAndSpan;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.ParcelableSparseArray;
@@ -1047,15 +1048,16 @@
         return false;
     }
 
-    void visualizeDropLocation(View v, Bitmap dragOutline, int cellX, int cellY, int spanX,
-            int spanY, boolean resize, DropTarget.DragObject dragObject) {
+    void visualizeDropLocation(View v, DragPreviewProvider outlineProvider, int cellX, int cellY,
+            int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) {
         final int oldDragCellX = mDragCell[0];
         final int oldDragCellY = mDragCell[1];
 
-        if (dragOutline == null && v == null) {
+        if (outlineProvider == null || outlineProvider.gerenatedDragOutline == null) {
             return;
         }
 
+        Bitmap dragOutline = outlineProvider.gerenatedDragOutline;
         if (cellX != oldDragCellX || cellY != oldDragCellY) {
             Point dragOffset = dragObject.dragView.getDragVisualizeOffset();
             Rect dragRegion = dragObject.dragView.getDragRegion();
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index 427acea..6822311 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -84,7 +84,7 @@
         applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
     }
 
-    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+    public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
             int outlineColor, boolean clipAlpha) {
 
         // We start by removing most of the alpha channel so as to ignore shadows, and
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 084de70..6605654 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -171,7 +171,6 @@
 
     @Override
     public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
-        target.itemType = LauncherLogProto.APP_ICON;
         target.gridX = info.cellX;
         target.gridY = info.cellY;
         targetParent.containerType = LauncherLogProto.HOTSEAT;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 886c5f0..334db4a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2809,7 +2809,7 @@
         mDragLayer.onAccessibilityStateChanged(enabled);
     }
 
-    public void onDragStarted(View view) {
+    public void onDragStarted() {
         if (isOnCustomContent()) {
             // Custom content screen doesn't participate in drag and drop. If on custom
             // content screen, move to default.
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2cbad53..50f7156 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -45,7 +45,6 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
 import android.os.Build;
-import android.os.Build.VERSION;
 import android.os.Bundle;
 import android.os.PowerManager;
 import android.text.Spannable;
@@ -59,7 +58,6 @@
 import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewParent;
 import android.widget.Toast;
 
 import com.android.launcher3.compat.UserHandleCompat;
@@ -71,7 +69,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -108,9 +105,7 @@
     private static final int[] sLoc1 = new int[2];
 
     public static boolean isNycMR1OrAbove() {
-        // TODO: Use the check from support lib
-        return !"REL".equals(VERSION.CODENAME)
-                && "NMR1".compareTo(VERSION.CODENAME) <= 0;
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
     }
 
     public static final boolean ATLEAST_MARSHMALLOW =
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 5105c1a..4c2d4bb 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -69,12 +69,12 @@
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.dragndrop.DragScroller;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.SpringLoadedDragController;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutsContainerListener;
@@ -247,8 +247,7 @@
     /** Is the user is dragging an item near the edge of a page? */
     private boolean mInScrollArea = false;
 
-    private HolographicOutlineHelper mOutlineHelper;
-    @Thunk Bitmap mDragOutline = null;
+    private DragPreviewProvider mOutlineProvider = null;
     public static final int DRAG_BITMAP_PADDING = DragPreviewProvider.DRAG_BITMAP_PADDING;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
@@ -343,8 +342,6 @@
     public Workspace(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mOutlineHelper = HolographicOutlineHelper.obtain(context);
-
         mLauncher = (Launcher) context;
         mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
         final Resources res = getResources();
@@ -417,7 +414,13 @@
             enfoceDragParity("onDragStart", 0, 0);
         }
 
+        if (mOutlineProvider != null) {
+            // The outline is used to visualize where the item will land if dropped
+            mOutlineProvider.generateDragOutline(mCanvas);
+        }
+
         updateChildrenLayersEnabled(false);
+        mLauncher.onDragStarted();
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
@@ -426,6 +429,27 @@
         if (mAddNewPageOnDrag) {
             mDeferRemoveExtraEmptyScreen = false;
             addExtraEmptyScreenOnDrag();
+
+            if (source != this && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
+                // When dragging a widget from different source, move to a page which has
+                // enough space to place this widget (after rearranging/resizing). We special case
+                // widgets as they cannot be placed inside a folder.
+                // Start at the current page and search right (on LTR) until finding a page with
+                // enough space. Since an empty screen is the furthest right, a page must be found.
+                int currentPage = getPageNearestToCenterOfScreen();
+                for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) {
+                    CellLayout page = (CellLayout) getPageAt(pageIndex);
+                    if (page.hasReorderSolution(info)) {
+                        setCurrentPage(pageIndex);
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
+            // Always enter the spring loaded mode
+            mLauncher.enterSpringLoadedDragMode();
         }
     }
 
@@ -1999,23 +2023,8 @@
                 position[0], position[1], 0, null);
     }
 
-    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
-        // Find a page that has enough space to place this widget (after rearranging/resizing).
-        // Start at the current page and search right (on LTR) until finding a page with enough
-        // space. Since an empty screen is the furthest right, a page must be found.
-        int currentPageInOverview = getPageNearestToCenterOfScreen();
-        for (int pageIndex = currentPageInOverview; pageIndex < getPageCount(); pageIndex++) {
-            CellLayout page = (CellLayout) getPageAt(pageIndex);
-            if (page.hasReorderSolution(info)) {
-                setCurrentPage(pageIndex);
-                break;
-            }
-        }
-
-        int[] size = estimateItemSize(info, false);
-
-        // The outline is used to visualize where the item will land if dropped
-        mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);
+    public void prepareDragWithProvider(DragPreviewProvider outlineProvider) {
+        mOutlineProvider = outlineProvider;
     }
 
     public void exitWidgetResizeMode() {
@@ -2271,34 +2280,6 @@
         return null;
     }
 
-    /**
-     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
-     * Responsibility for the bitmap is transferred to the caller.
-     */
-    private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,
-            boolean clipAlpha) {
-        final int outlineColor = getResources().getColor(R.color.outline_color);
-        final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-        mCanvas.setBitmap(b);
-
-        Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
-        float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
-                (h - padding) / (float) orig.getHeight());
-        int scaledWidth = (int) (scaleFactor * orig.getWidth());
-        int scaledHeight = (int) (scaleFactor * orig.getHeight());
-        Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
-
-        // center the image
-        dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
-
-        mCanvas.drawBitmap(orig, src, dst, null);
-        mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,
-                clipAlpha);
-        mCanvas.setBitmap(null);
-
-        return b;
-    }
-
     public void startDrag(CellLayout.CellInfo cellInfo) {
         startDrag(cellInfo, false);
     }
@@ -2337,11 +2318,8 @@
             ItemInfo dragObject, DragPreviewProvider previewProvider) {
         child.clearFocus();
         child.setPressed(false);
+        mOutlineProvider = previewProvider;
 
-        // The outline is used to visualize where the item will land if dropped
-        mDragOutline = previewProvider.createDragOutline(mCanvas);
-
-        mLauncher.onDragStarted(child);
         // The drag bitmap follows the touch point around on the screen
         final Bitmap b = previewProvider.createDragBitmap(mCanvas);
         int halfPadding = previewProvider.previewPadding / 2;
@@ -2384,12 +2362,7 @@
                 dragObject, DragController.DRAG_ACTION_MOVE, dragVisualizeOffset,
                 dragRect, scale, accessible);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
-
         b.recycle();
-
-        if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) {
-            mLauncher.enterSpringLoadedDragMode();
-        }
         return dv;
     }
 
@@ -3180,7 +3153,7 @@
                     item.spanY, child, mTargetCell);
 
             if (!nearestDropOccupied) {
-                mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+                mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
                         mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d);
             } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
                     && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||
@@ -3325,7 +3298,7 @@
             }
 
             boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
-            mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+            mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
                 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, dragObject);
         }
     }
@@ -3716,7 +3689,7 @@
                 && mDragInfo.cell != null) {
             mDragInfo.cell.setVisibility(VISIBLE);
         }
-        mDragOutline = null;
+        mOutlineProvider = null;
         mDragInfo = null;
 
         if (!isFlingToDelete) {
@@ -4318,7 +4291,6 @@
 
     @Override
     public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
-        target.itemType = LauncherLogProto.APP_ICON;
         target.gridX = info.cellX;
         target.gridY = info.cellY;
         target.pageIndex = getCurrentPage();
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3684136..96da181 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1428,7 +1428,6 @@
 
     @Override
     public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
-        target.itemType = LauncherLogProto.APP_ICON;
         target.gridX = info.cellX;
         target.gridY = info.cellY;
         target.pageIndex = mContent.getCurrentPage();
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index b90c2fd..e078d9b 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.PreloadIconDrawable;
 import com.android.launcher3.R;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.folder.FolderIcon;
 
 /**
@@ -45,6 +46,8 @@
     // The padding added to the drag view during the preview generation.
     public final int previewPadding;
 
+    public Bitmap gerenatedDragOutline;
+
     public DragPreviewProvider(View view) {
         mView = view;
 
@@ -118,6 +121,14 @@
         return b;
     }
 
+    public final void generateDragOutline(Canvas canvas) {
+        if (ProviderConfig.IS_DOGFOOD_BUILD && gerenatedDragOutline != null) {
+            throw new RuntimeException("Drag outline generated twice");
+        }
+
+        gerenatedDragOutline = createDragOutline(canvas);
+    }
+
     /**
      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
      * Responsibility for the bitmap is transferred to the caller.
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index aad266b..dc04597 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -1,5 +1,9 @@
 package com.android.launcher3.logging;
 
+import android.view.View;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -47,17 +51,25 @@
             return typeStr;
         }
         switch(t.itemType){
-            case LauncherLogProto.APP_ICON: typeStr = "ICON"; break;
+            case LauncherLogProto.APP_ICON: typeStr = "APPICON"; break;
             case LauncherLogProto.SHORTCUT: typeStr = "SHORTCUT"; break;
             case LauncherLogProto.WIDGET: typeStr = "WIDGET"; break;
             case LauncherLogProto.DEEPSHORTCUT: typeStr = "DEEPSHORTCUT"; break;
+            case LauncherLogProto.FOLDER_ICON: typeStr = "FOLDERICON"; break;
+
             default: typeStr = "UNKNOWN";
         }
 
-        return typeStr + ", packageHash=" + t.packageNameHash
-                + ", componentHash=" + t.componentHash
-                + ", intentHash=" + t.intentHash
-                + ", grid=(" + t.gridX + "," + t.gridY + "), id=" + t.pageIndex;
+        if (t.packageNameHash != 0) {
+            typeStr += ", packageHash=" + t.packageNameHash;
+        }
+        if (t.componentHash != 0) {
+            typeStr += ", componentHash=" + t.componentHash;
+        }
+        if (t.intentHash != 0) {
+            typeStr += ", intentHash=" + t.intentHash;
+        }
+        return typeStr += ", grid=(" + t.gridX + "," + t.gridY + "), id=" + t.pageIndex;
     }
 
     private static String getControlStr(Target t) {
@@ -116,16 +128,17 @@
         return str + " id=" + t.pageIndex;
     }
 
-
+    /**
+     * Used for launching an event by tapping on an icon.
+     */
     public static LauncherLogProto.LauncherEvent initLauncherEvent(
             int actionType,
-            int childTargetType,
+            View v,
             int parentTargetType){
         LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
 
         event.srcTarget = new LauncherLogProto.Target[2];
-        event.srcTarget[0] = new LauncherLogProto.Target();
-        event.srcTarget[0].type = childTargetType;
+        event.srcTarget[0] = initTarget(v);
         event.srcTarget[1] = new LauncherLogProto.Target();
         event.srcTarget[1].type = parentTargetType;
 
@@ -134,6 +147,9 @@
         return event;
     }
 
+    /**
+     * Used for clicking on controls and buttons.
+     */
     public static LauncherLogProto.LauncherEvent initLauncherEvent(
             int actionType,
             int childTargetType){
@@ -147,4 +163,31 @@
         event.action.type = actionType;
         return event;
     }
+
+    private static Target initTarget(View v) {
+        Target t = new LauncherLogProto.Target();
+        t.type = Target.ITEM;
+        if (!(v.getTag() instanceof ItemInfo)) {
+            return t;
+        }
+        ItemInfo itemInfo = (ItemInfo) v.getTag();
+        switch (itemInfo.itemType) {
+            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+                t.itemType = LauncherLogProto.APP_ICON;
+                break;
+            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                t.itemType = LauncherLogProto.SHORTCUT;
+                break;
+            case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+                t.itemType = LauncherLogProto.FOLDER_ICON;
+                break;
+            case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                t.itemType = LauncherLogProto.WIDGET;
+                break;
+            case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+                t.itemType = LauncherLogProto.DEEPSHORTCUT;
+                break;
+        }
+        return t;
+    }
 }
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 64a5f57..e4cc182 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -97,13 +97,16 @@
 
     protected LauncherEvent createLauncherEvent(View v, Intent intent) {
         LauncherEvent event = LoggerUtils.initLauncherEvent(
-                Action.TOUCH, Target.ITEM, Target.CONTAINER);
+                Action.TOUCH, v, Target.CONTAINER);
         event.action.touch = Action.TAP;
 
         // Fill in grid(x,y), pageIndex of the child and container type of the parent
         // TODO: make this percolate up the view hierarchy if needed.
         int idx = 0;
         LaunchSourceProvider provider = getLaunchProviderRecursive(v);
+        if (!(v.getTag() instanceof ItemInfo)) {
+            return null;
+        }
         ItemInfo itemInfo = (ItemInfo) v.getTag();
         provider.fillInLaunchSourceData(v, itemInfo, event.srcTarget[idx], event.srcTarget[idx + 1]);
 
@@ -125,7 +128,11 @@
     }
 
     public void logAppLaunch(View v, Intent intent) {
-        dispatchUserEvent(createLauncherEvent(v, intent), intent);
+        LauncherEvent ev = createLauncherEvent(v, intent);
+        if (ev == null) {
+            return;
+        }
+        dispatchUserEvent(ev, intent);
     }
 
     public void logActionOnControl(int action, int controlType) {
@@ -149,21 +156,19 @@
 
     public void logDeepShortcutsOpen(View icon) {
         LauncherEvent event = LoggerUtils.initLauncherEvent(
-                Action.TOUCH, Target.ITEM, Target.CONTAINER);
+                Action.TOUCH, icon, Target.CONTAINER);
         LaunchSourceProvider provider = getLaunchProviderRecursive(icon);
+        if (!(icon.getTag() instanceof ItemInfo)) {
+            return;
+        }
         ItemInfo info = (ItemInfo) icon.getTag();
         provider.fillInLaunchSourceData(icon, info, event.srcTarget[0], event.srcTarget[1]);
-        event.srcTarget[0].itemType = LauncherLogProto.DEEPSHORTCUT;
         event.action.touch = Action.LONGPRESS;
         event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
         event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
         dispatchUserEvent(event, null);
     }
 
-    public void logDragNDrop() {
-        // TODO
-    }
-
     public void setPredictedApps(List<ComponentKey> predictedApps) {
         mPredictedApps = predictedApps;
     }
@@ -187,17 +192,20 @@
     public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
         if (DEBUG_LOGGING) {
             Log.d(TAG, String.format(Locale.US,
-                    "action:%s\nchild:%s\nparent:%s\nelapsed container %d ms session %d ms",
+                    "\naction:%s\n Source child:%s\tparent:%s",
                     LoggerUtils.getActionStr(ev.action),
                     LoggerUtils.getTargetStr(ev.srcTarget != null ? ev.srcTarget[0] : null),
-                    LoggerUtils.getTargetStr(ev.srcTarget.length > 1 ? ev.srcTarget[1] : null),
+                    LoggerUtils.getTargetStr(ev.srcTarget.length > 1 ? ev.srcTarget[1] : null)));
+            if (ev.destTarget != null && ev.destTarget.length > 0) {
+                Log.d(TAG, String.format(Locale.US,
+                        " Destination child:%s\tparent:%s",
+                        LoggerUtils.getTargetStr(ev.destTarget != null ? ev.destTarget[0] : null),
+                        LoggerUtils.getTargetStr(ev.destTarget.length > 1 ? ev.destTarget[1] : null)));
+            }
+            Log.d(TAG, String.format(Locale.US,
+                    " Elapsed container %d ms session %d ms",
                     ev.elapsedContainerMillis,
                     ev.elapsedSessionMillis));
         }
     }
-
-    public int getPredictedRank(ComponentKey key) {
-        if (mPredictedApps == null) return -1;
-        return mPredictedApps.indexOf(key);
-    }
 }
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
index 450d36d..42086fc 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -17,15 +17,23 @@
 package com.android.launcher3.shortcuts;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 
 /**
  * A {@link BubbleTextView} that has the shortcut icon on the left and drag handle on the right.
  */
 public class DeepShortcutTextView extends BubbleTextView {
+    private final Rect mDragHandleBounds = new Rect();
+    private final int mDragHandleWidth;
+    private boolean mShouldPerformClick = true;
 
     public DeepShortcutTextView(Context context) {
         this(context, null, 0);
@@ -37,10 +45,39 @@
 
     public DeepShortcutTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+
+        Resources resources = getResources();
+        mDragHandleWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_padding_end)
+                + resources.getDimensionPixelSize(R.dimen.deep_shortcut_drag_handle_size)
+                + resources.getDimensionPixelSize(R.dimen.deep_shortcut_drawable_padding) / 2;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        mDragHandleBounds.set(0, 0, mDragHandleWidth, getMeasuredHeight());
+        if (!Utilities.isRtl(getResources())) {
+            mDragHandleBounds.offset(getMeasuredWidth() - mDragHandleBounds.width(), 0);
+        }
     }
 
     @Override
     protected void applyCompoundDrawables(Drawable icon) {
         // The icon is drawn in a separate view.
     }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            // Ignore clicks on the drag handle (long clicks still start the drag).
+            mShouldPerformClick = !mDragHandleBounds.contains((int) ev.getX(), (int) ev.getY());
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean performClick() {
+        return mShouldPerformClick && super.performClick();
+    }
 }
diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
new file mode 100644
index 0000000..8739390
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.View;
+
+import com.android.launcher3.HolographicOutlineHelper;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.graphics.DragPreviewProvider;
+
+/**
+ * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
+ * dragged from the widget tray.
+ */
+public class PendingItemPreviewProvider extends DragPreviewProvider {
+
+    private final PendingAddItemInfo mAddInfo;
+    private final Bitmap mPreviewBitmap;
+
+    public PendingItemPreviewProvider(View view, PendingAddItemInfo addInfo, Bitmap preview) {
+        super(view);
+        mAddInfo = addInfo;
+        mPreviewBitmap = preview;
+    }
+
+    @Override
+    public Bitmap createDragOutline(Canvas canvas) {
+        Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace();
+        int[] size = workspace.estimateItemSize(mAddInfo, false);
+
+        int w = size[0];
+        int h = size[1];
+        final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+        canvas.setBitmap(b);
+
+        Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
+        float scaleFactor = Math.min((w - DRAG_BITMAP_PADDING) / (float) mPreviewBitmap.getWidth(),
+                (h - DRAG_BITMAP_PADDING) / (float) mPreviewBitmap.getHeight());
+        int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth());
+        int scaledHeight = (int) (scaleFactor * mPreviewBitmap.getHeight());
+        Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
+
+        // center the image
+        dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
+
+        canvas.drawBitmap(mPreviewBitmap, src, dst, null);
+
+        // Don't clip alpha values for the drag outline if we're using the default widget preview
+        boolean clipAlpha = !(mAddInfo instanceof PendingAddWidgetInfo &&
+                (((PendingAddWidgetInfo) mAddInfo).previewImage == 0));
+        final int outlineColor = mView.getResources().getColor(R.color.outline_color);
+        HolographicOutlineHelper.obtain(mView.getContext())
+                .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, clipAlpha);
+        canvas.setBitmap(null);
+
+        return b;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 34bee1b..352cea4 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -205,7 +205,7 @@
 
         // Compose the drag image
         Bitmap preview;
-        float scale = 1f;
+        final float scale;
         final Rect bounds = image.getBitmapBounds();
 
         if (createItemInfo instanceof PendingAddWidgetInfo) {
@@ -242,19 +242,14 @@
             scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
         }
 
-        // Don't clip alpha values for the drag outline if we're using the default widget preview
-        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
-                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
+        // Since we are not going through the workspace for starting the drag, set drag related
+        // information on the workspace before starting the drag.
+        mLauncher.getWorkspace().prepareDragWithProvider(
+                new PendingItemPreviewProvider(v, createItemInfo, preview));
 
         // Start the drag
-        mLauncher.lockScreenOrientation();
         mDragController.startDrag(image, preview, this, createItemInfo,
                 bounds, DragController.DRAG_ACTION_COPY, scale);
-        // This call expects the extra empty screen to already be created, which is why we call it
-        // after mDragController.startDrag().
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, preview, clipAlpha);
-
-        preview.recycle();
         return true;
     }