Merge "Some optimizations in blur outline generator" into ub-launcher3-calgary-polish
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index e0694f3..604b164 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -125,11 +125,8 @@
     }
 
     @Override
-    public String toString() {
-        return "ApplicationInfo(title=" + title + " id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container
-                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
-                + " spanX=" + spanX + " spanY=" + spanY + " user=" + user + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " componentName=" + componentName;
     }
 
     /**
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 0f6073e..2dde7ca 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -43,6 +43,7 @@
 
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.util.Thunk;
 
@@ -199,8 +200,8 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
-        mActive = supportsDrop(source, info);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        mActive = supportsDrop(dragObject.dragSource, dragObject.dragInfo);
         mDrawable.setColorFilter(null);
         if (mCurrentColorAnim != null) {
             mCurrentColorAnim.cancel();
@@ -209,6 +210,9 @@
         setTextColor(mOriginalTextColor);
         (mHideParentOnDisable ? ((ViewGroup) getParent()) : this)
                 .setVisibility(mActive ? View.VISIBLE : View.GONE);
+
+        mAccessibleDrag = options.isAccessibleDrag;
+        setOnClickListener(mAccessibleDrag ? this : null);
     }
 
     @Override
@@ -227,6 +231,7 @@
     @Override
     public void onDragEnd() {
         mActive = false;
+        setOnClickListener(null);
     }
 
     /**
@@ -308,11 +313,6 @@
         return to;
     }
 
-    public void enableAccessibleDrag(boolean enable) {
-        mAccessibleDrag = enable;
-        setOnClickListener(enable ? this : null);
-    }
-
     @Override
     public void onClick(View v) {
         mLauncher.getAccessibilityDelegate().handleAccessibleDrop(this, null, null);
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index f24e00b..705f841 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -25,6 +25,7 @@
 import android.view.animation.AnimationUtils;
 
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.util.FlingAnimation;
 import com.android.launcher3.util.Thunk;
@@ -49,9 +50,9 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
-        super.onDragStart(source, info, dragAction);
-        setTextBasedOnDragSource(source);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        super.onDragStart(dragObject, options);
+        setTextBasedOnDragSource(dragObject.dragSource);
     }
 
     /** @return true for items that should have a "Remove" action in accessibility. */
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index da32d82..efbb9d7 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -19,11 +19,12 @@
 import android.view.View;
 
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.logging.UserEventDispatcher.LaunchSourceProvider;
 
 /**
  * Interface defining an object that can originate a drag.
  */
-public interface DragSource {
+public interface DragSource extends LaunchSourceProvider {
 
     /**
      * @return whether items dragged from this source supports
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index 90b8f1c..efdeb1f 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -48,9 +48,12 @@
         /** The view that moves around while you drag.  */
         public DragView dragView = null;
 
-        /** The data associated with the object being dragged */
+        /** The data associated with the object, after item is dropped. */
         public ItemInfo dragInfo = null;
 
+        /** The data associated with the object  being dragged */
+        public ItemInfo originalDragInfo = null;
+
         /** Where the drag originated */
         public DragSource dragSource = null;
 
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 5966af5..42bab47 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -27,6 +27,7 @@
 import android.widget.LinearLayout;
 
 import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
 
 /*
  * The top bar containing various drop targets: Delete/App Info/Uninstall.
@@ -120,17 +121,11 @@
         }
     }
 
-    public void enableAccessibleDrag(boolean enable) {
-        mDeleteDropTarget.enableAccessibleDrag(enable);
-        mAppInfoDropTarget.enableAccessibleDrag(enable);
-        mUninstallDropTarget.enableAccessibleDrag(enable);
-    }
-
     /*
      * DragController.DragListener implementation
      */
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         animateToVisibility(true);
     }
 
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 9a99852..c0a8caa 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -126,14 +126,6 @@
         public void onItemsChanged(boolean animate);
     }
 
-    @Override
-    public String toString() {
-        return "FolderInfo(id=" + this.id + " type=" + this.itemType
-                + " container=" + this.container + " screen=" + screenId
-                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
-                + " spanY=" + spanY + ")";
-    }
-
     public boolean hasOption(int optionFlag) {
         return (options & optionFlag) != 0;
     }
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 2a94e55..c0c22a3 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -189,10 +189,24 @@
     }
 
     @Override
-    public String toString() {
-        return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
-            + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
-            + " spanY=" + spanY + " user=" + user + ")";
+    public final String toString() {
+        return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+    }
+
+    protected String dumpProperties() {
+        return "id=" + id
+                + " type=" + itemType
+                + " container=" + container
+                + " screen=" + screenId
+                + " cellX=" + cellX
+                + " cellY=" + cellY
+                + " spanX=" + spanX
+                + " spanY=" + spanY
+                + " minSpanX=" + minSpanX
+                + " minSpanY=" + minSpanY
+                + " rank=" + rank
+                + " user=" + user
+                + " title=" + title;
     }
 
     /**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c919db8..1d5ece2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -102,6 +102,7 @@
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dynamicui.ExtractedColors;
 import com.android.launcher3.folder.Folder;
@@ -3150,6 +3151,14 @@
         }
     }
 
+    public View getTopFloatingView() {
+        View topView = getOpenShortcutsContainer();
+        if (topView == null) {
+            topView = getWorkspace().getOpenFolder();
+        }
+        return topView;
+    }
+
     /**
      * @return The open shortcuts container, or null if there is none
      */
@@ -3222,7 +3231,7 @@
                                         longClickCellInfo.cellX, longClickCellInfo.cellY));
                 if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {
                     // User long pressed on an item
-                    mWorkspace.startDrag(longClickCellInfo);
+                    mWorkspace.startDrag(longClickCellInfo, new DragOptions());
                 }
             }
         }
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index f22c2a4..66d8957 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -143,8 +143,8 @@
     }
 
     @Override
-    public String toString() {
-        return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " appWidgetId=" + appWidgetId;
     }
 
     public final boolean isWidgetIdAllocated() {
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index 1aaf85b..31820d7 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -29,4 +29,9 @@
      * The component that will be created.
      */
     public ComponentName componentName;
+
+    @Override
+    protected String dumpProperties() {
+        return super.dumpProperties() + " componentName=" + componentName;
+    }
 }
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index 6ee96fc..48a75d1 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -102,8 +102,8 @@
             // once the state switching animation is complete.
             return false;
         }
-        if (mWorkspace.getOpenFolder() != null) {
-            // Don't listen for the pinch gesture if a folder is open.
+        if (mLauncher.getTopFloatingView() != null) {
+            // Don't listen for the pinch gesture if a floating view is open.
             return false;
         }
 
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 21fa8a0..9d7be16 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -270,14 +270,6 @@
         }
     }
 
-    @Override
-    public String toString() {
-        return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId
-                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
-                + " user=" + user + ")";
-    }
-
     public ComponentName getTargetComponent() {
         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9079837..e34f509 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -58,6 +58,8 @@
 import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
 
 import com.android.launcher3.compat.UserHandleCompat;
@@ -108,6 +110,10 @@
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1;
     }
 
+    public static boolean isNycOrAbove() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+    }
+
     public static final boolean ATLEAST_MARSHMALLOW =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
 
@@ -156,33 +162,14 @@
         if (isNycOrAbove()) {
             // If the device was scaled, used the original dimensions to determine if rotation
             // is allowed of not.
-            try {
-                // TODO: Use the actual field when the API is finalized.
-                int originalDensity =
-                        DisplayMetrics.class.getField("DENSITY_DEVICE_STABLE").getInt(null);
-                Resources res = context.getResources();
-                int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
-                        * res.getDisplayMetrics().densityDpi / originalDensity;
-                return originalSmallestWidth >= 600;
-            } catch (Exception e) {
-                // Ignore
-            }
+            Resources res = context.getResources();
+            int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
+                    * res.getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEVICE_STABLE;
+            return originalSmallestWidth >= 600;
         }
         return false;
     }
 
-    public static boolean isNycOrAbove() {
-        // TODO(vadimt): Replace using reflection with looking at the API version once
-        // Build.VERSION.SDK_INT gets bumped to 24. b/22942492.
-        try {
-            View.class.getDeclaredField("DRAG_FLAG_OPAQUE");
-            // View.DRAG_FLAG_OPAQUE doesn't exist in M-release, so it's an indication of N+.
-            return true;
-        } catch (NoSuchFieldException e) {
-            return false;
-        }
-    }
-
     public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
         byte[] data = c.getBlob(iconIndex);
         try {
@@ -921,4 +908,15 @@
         ta.recycle();
         return colorAccent;
     }
+
+    public static void sendCustomAccessibilityEvent(View target, int type, String text) {
+        AccessibilityManager accessibilityManager = (AccessibilityManager)
+                target.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (accessibilityManager.isEnabled()) {
+            AccessibilityEvent event = AccessibilityEvent.obtain(type);
+            target.onInitializeAccessibilityEvent(event);
+            event.getText().add(text);
+            accessibilityManager.sendAccessibilityEvent(event);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 88eeac6..d5f1363 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -59,7 +59,7 @@
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
 import com.android.launcher3.UninstallDropTarget.DropTargetSource;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.AccessibileDragListenerAdapter;
 import com.android.launcher3.accessibility.OverviewAccessibilityDelegate;
 import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
 import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
@@ -69,6 +69,7 @@
 import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragScroller;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.SpringLoadedDragController;
@@ -100,7 +101,7 @@
 public class Workspace extends PagedView
         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
-        Insettable, DropTargetSource, AccessibilityDragSource, UserEventDispatcher.LaunchSourceProvider {
+        Insettable, DropTargetSource {
     private static final String TAG = "Launcher.Workspace";
 
     private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -134,7 +135,6 @@
 
     @Thunk Runnable mRemoveEmptyScreenRunnable;
     @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
-    @Thunk boolean mAddNewPageOnDrag = true;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -409,7 +409,7 @@
     }
 
     @Override
-    public void onDragStart(final DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         if (ENFORCE_DRAG_EVENT_ORDER) {
             enfoceDragParity("onDragStart", 0, 0);
         }
@@ -426,11 +426,19 @@
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
         InstallShortcutReceiver.enableInstallQueue();
 
-        if (mAddNewPageOnDrag) {
+        // Do not add a new page if it is a accessible drag which was not started by the workspace.
+        // We do not support accessibility drag from other sources and instead provide a direct
+        // action for move/add to homescreen.
+        // When a accessible drag is started by the folder, we only allow rearranging withing the
+        // folder.
+        boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);
+
+        if (addNewPage) {
             mDeferRemoveExtraEmptyScreen = false;
             addExtraEmptyScreenOnDrag();
 
-            if (source != this && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
+            if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                    && dragObject.dragSource != this) {
                 // 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.
@@ -439,7 +447,7 @@
                 int currentPage = getPageNearestToCenterOfScreen();
                 for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) {
                     CellLayout page = (CellLayout) getPageAt(pageIndex);
-                    if (page.hasReorderSolution(info)) {
+                    if (page.hasReorderSolution(dragObject.dragInfo)) {
                         setCurrentPage(pageIndex);
                         break;
                     }
@@ -453,10 +461,6 @@
         }
     }
 
-    public void setAddNewPageOnDrag(boolean addPage) {
-        mAddNewPageOnDrag = addPage;
-    }
-
     public void deferRemoveExtraEmptyScreen() {
         mDeferRemoveExtraEmptyScreen = true;
     }
@@ -1722,26 +1726,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    @Override
-    public void enableAccessibleDrag(boolean enable) {
-        for (int i = 0; i < getChildCount(); i++) {
-            CellLayout child = (CellLayout) getChildAt(i);
-            child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
-        }
-
-        if (enable) {
-            // We need to allow our individual children to become click handlers in this case
-            setOnClickListener(null);
-        } else {
-            // Reset our click listener
-            setOnClickListener(mLauncher);
-        }
-        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
-        mLauncher.getHotseat().getLayout()
-            .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
-    }
-
     public boolean hasCustomContent() {
         return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);
     }
@@ -1874,19 +1858,6 @@
     }
 
     @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        if (!mLauncher.isAppsViewVisible()) {
-            final Folder openFolder = getOpenFolder();
-            if (openFolder != null) {
-                return openFolder.requestFocus(direction, previouslyFocusedRect);
-            } else {
-                return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
-            }
-        }
-        return false;
-    }
-
-    @Override
     public int getDescendantFocusability() {
         if (workspaceInModalState()) {
             return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
@@ -1894,18 +1865,6 @@
         return super.getDescendantFocusability();
     }
 
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (!mLauncher.isAppsViewVisible()) {
-            final Folder openFolder = getOpenFolder();
-            if (openFolder != null) {
-                openFolder.addFocusables(views, direction);
-            } else {
-                super.addFocusables(views, direction, focusableMode);
-            }
-        }
-    }
-
     public boolean workspaceInModalState() {
         return mState != State.NORMAL;
     }
@@ -2280,12 +2239,7 @@
         return null;
     }
 
-    public void startDrag(CellLayout.CellInfo cellInfo) {
-        startDrag(cellInfo, false);
-    }
-
-    @Override
-    public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) {
+    public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) {
         View child = cellInfo.cell;
 
         // Make sure the drag was started by a long press as opposed to a long click.
@@ -2298,10 +2252,25 @@
         CellLayout layout = (CellLayout) child.getParent().getParent();
         layout.prepareChildForDrag(child);
 
-        beginDragShared(child, this, accessible);
+        if (options.isAccessibleDrag) {
+            mDragController.addDragListener(new AccessibileDragListenerAdapter(
+                    this, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG) {
+                @Override
+                protected void enableAccessibleDrag(boolean enable) {
+                    super.enableAccessibleDrag(enable);
+                    setEnableForLayout(mLauncher.getHotseat().getLayout(),enable);
+
+                    // We need to allow our individual children to become click handlers in this
+                    // case, so temporarily unset the click handlers.
+                    setOnClickListener(enable ? null : mLauncher);
+                }
+            });
+        }
+
+        beginDragShared(child, this, options);
     }
 
-    public void beginDragShared(View child, DragSource source, boolean accessible) {
+    public void beginDragShared(View child, DragSource source, DragOptions options) {
         Object dragObject = child.getTag();
         if (!(dragObject instanceof ItemInfo)) {
             String msg = "Drag started with a view that has no tag set. This "
@@ -2309,13 +2278,13 @@
                     + "View: " + child + "  tag: " + child.getTag();
             throw new IllegalStateException(msg);
         }
-        beginDragShared(child, source, accessible, (ItemInfo) dragObject,
-                new DragPreviewProvider(child));
+        beginDragShared(child, source, (ItemInfo) dragObject,
+                new DragPreviewProvider(child), options);
     }
 
 
-    public DragView beginDragShared(View child, DragSource source, boolean accessible,
-            ItemInfo dragObject, DragPreviewProvider previewProvider) {
+    public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
+            DragPreviewProvider previewProvider, DragOptions dragOptions) {
         child.clearFocus();
         child.setPressed(false);
         mOutlineProvider = previewProvider;
@@ -2359,8 +2328,7 @@
         }
 
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
-                dragObject, DragController.DRAG_ACTION_MOVE, dragVisualizeOffset,
-                dragRect, scale, accessible);
+                dragObject, dragVisualizeOffset, dragRect, scale, dragOptions);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
         b.recycle();
         return dv;
@@ -3426,6 +3394,7 @@
                 if (info.container == NO_ID && info instanceof AppInfo) {
                     // Came from all apps -- make a copy
                     info = ((AppInfo) info).makeShortcut();
+                    d.dragInfo = info;
                 }
                 view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info);
                 break;
@@ -4295,6 +4264,12 @@
         target.gridY = info.cellY;
         target.pageIndex = getCurrentPage();
         targetParent.containerType = LauncherLogProto.WORKSPACE;
+        if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+            target.rank = info.rank;
+            targetParent.containerType = LauncherLogProto.HOTSEAT;
+        } else if (info.container >= 0) {
+            targetParent.containerType = LauncherLogProto.FOLDER;
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java b/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java
new file mode 100644
index 0000000..62a9a6d
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/AccessibileDragListenerAdapter.java
@@ -0,0 +1,66 @@
+/*
+ * 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.accessibility;
+
+import android.view.ViewGroup;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.dragndrop.DragController.DragListener;
+import com.android.launcher3.dragndrop.DragOptions;
+
+/**
+ * Utility listener to enable/disable accessibility drag flags for a ViewGroup
+ * containing CellLayouts
+ */
+public class AccessibileDragListenerAdapter implements DragListener {
+
+    private final ViewGroup mViewGroup;
+    private final int mDragType;
+
+    /**
+     * @param parent
+     * @param dragType either {@link CellLayout#WORKSPACE_ACCESSIBILITY_DRAG} or
+     *                 {@link CellLayout#FOLDER_ACCESSIBILITY_DRAG}
+     */
+    public AccessibileDragListenerAdapter(ViewGroup parent, int dragType) {
+        mViewGroup = parent;
+        mDragType = dragType;
+    }
+
+    @Override
+    public void onDragStart(DragObject dragObject, DragOptions options) {
+        enableAccessibleDrag(true);
+    }
+
+    @Override
+    public void onDragEnd() {
+        enableAccessibleDrag(false);
+        Launcher.getLauncher(mViewGroup.getContext()).getDragController().removeDragListener(this);
+    }
+
+    protected void enableAccessibleDrag(boolean enable) {
+        for (int i = 0; i < mViewGroup.getChildCount(); i++) {
+            setEnableForLayout((CellLayout) mViewGroup.getChildAt(i), enable);
+        }
+    }
+
+    protected final void setEnableForLayout(CellLayout layout, boolean enable) {
+        layout.enableAccessibleDrag(enable, mDragType);
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 0562cf5..173aad0 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -22,6 +22,8 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.InfoDropTarget;
@@ -73,7 +75,6 @@
     @Thunk final Launcher mLauncher;
 
     private DragInfo mDragInfo = null;
-    private AccessibilityDragSource mDragSource = null;
 
     public LauncherAccessibilityDelegate(Launcher launcher) {
         mLauncher = launcher;
@@ -372,26 +373,25 @@
 
         Folder folder = workspace.getOpenFolder();
         if (folder != null) {
-            if (folder.getItemsInReadingOrder().contains(item)) {
-                mDragSource = folder;
-            } else {
+            if (!folder.getItemsInReadingOrder().contains(item)) {
                 mLauncher.closeFolder();
+                folder = null;
             }
         }
-        if (mDragSource == null) {
-            mDragSource = workspace;
-        }
-        mDragSource.enableAccessibleDrag(true);
-        mDragSource.startDrag(cellInfo, true);
 
-        if (mLauncher.getDragController().isDragging()) {
-            mLauncher.getDragController().addDragListener(this);
+        mLauncher.getDragController().addDragListener(this);
+
+        DragOptions options = new DragOptions();
+        options.isAccessibleDrag = true;
+        if (folder != null) {
+            folder.startDrag(cellInfo.cell, options);
+        } else {
+            workspace.startDrag(cellInfo, options);
         }
     }
 
-
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DragObject dragObject, DragOptions options) {
         // No-op
     }
 
@@ -399,16 +399,6 @@
     public void onDragEnd() {
         mLauncher.getDragController().removeDragListener(this);
         mDragInfo = null;
-        if (mDragSource != null) {
-            mDragSource.enableAccessibleDrag(false);
-            mDragSource = null;
-        }
-    }
-
-    public static interface AccessibilityDragSource {
-        void startDrag(CellLayout.CellInfo cellInfo, boolean accessible);
-
-        void enableAccessibleDrag(boolean enable);
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index c7bc23b..a3786fa 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -48,9 +48,12 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.graphics.TintedDrawableSpan;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.ComponentKey;
 
 import java.nio.charset.Charset;
@@ -537,7 +540,7 @@
         if (!mLauncher.isDraggingEnabled()) return false;
 
         // Start the drag
-        mLauncher.getWorkspace().beginDragShared(v, this, false);
+        mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
         // Enter spring loaded mode
         mLauncher.enterSpringLoadedDragMode();
 
@@ -700,4 +703,9 @@
         mSearchQueryBuilder.clearSpans();
         Selection.setSelection(mSearchQueryBuilder, 0);
     }
+
+    @Override
+    public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
+        targetParent.containerType = mAppsRecyclerView.getContainerType(v);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 25ed3b8..0173847 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -27,20 +27,16 @@
 import com.android.launcher3.BaseRecyclerView;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.logging.UserEventDispatcher.LaunchSourceProvider;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 import java.util.List;
 
 /**
  * A RecyclerView with custom fast scroll support for the all apps view.
  */
-public class AllAppsRecyclerView extends BaseRecyclerView
-        implements LaunchSourceProvider {
+public class AllAppsRecyclerView extends BaseRecyclerView {
 
     private AlphabeticalAppsList mApps;
     private AllAppsFastScrollHelper mFastScrollHelper;
@@ -207,10 +203,9 @@
         updateEmptySearchBackgroundBounds();
     }
 
-    @Override
-    public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
+    public int getContainerType(View v) {
         if (mApps.hasFilter()) {
-            targetParent.containerType = LauncherLogProto.SEARCHRESULT;
+            return LauncherLogProto.SEARCHRESULT;
         } else {
             if (v instanceof BubbleTextView) {
                 BubbleTextView icon = (BubbleTextView) v;
@@ -219,12 +214,11 @@
                     List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
                     AlphabeticalAppsList.AdapterItem item = items.get(position);
                     if (item.viewType == AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON) {
-                        targetParent.containerType = LauncherLogProto.PREDICTION;
-                        return;
+                        return LauncherLogProto.PREDICTION;
                     }
                 }
             }
-            targetParent.containerType = LauncherLogProto.ALLAPPS;
+            return LauncherLogProto.ALLAPPS;
         }
     }
 
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 9da1cb3..b67d3b8 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -43,7 +43,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -51,7 +50,6 @@
 import com.android.launcher3.util.TouchController;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -59,12 +57,6 @@
 public class DragController implements DragDriver.EventListener, TouchController {
     private static final String TAG = "Launcher.DragController";
 
-    /** Indicates the drag is a move.  */
-    public static int DRAG_ACTION_MOVE = 0;
-
-    /** Indicates the drag is a copy.  */
-    public static int DRAG_ACTION_COPY = 1;
-
     public static final int SCROLL_DELAY = 500;
     public static final int RESCROLL_DELAY = PagedView.PAGE_SNAP_ANIMATION_DURATION + 150;
 
@@ -93,8 +85,8 @@
      */
     private DragDriver mDragDriver = null;
 
-    /** Whether or not an accessible drag operation is in progress. */
-    private boolean mIsAccessibleDrag;
+    /** Options controlling the drag behavior. */
+    private DragOptions mOptions;
 
     /** X coordinate of the down event. */
     private int mMotionDownX;
@@ -147,12 +139,10 @@
         /**
          * A drag has begun
          *
-         * @param source An object representing where the drag originated
-         * @param info The data associated with the object that is being dragged
-         * @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
-         *        or {@link DragController#DRAG_ACTION_COPY}
+         * @param dragObject The object being dragged
+         * @param options Options used to start the drag
          */
-        void onDragStart(DragSource source, ItemInfo info, int dragAction);
+        void onDragStart(DropTarget.DragObject dragObject, DragOptions options);
 
         /**
          * The drag has ended
@@ -162,8 +152,6 @@
 
     /**
      * Used to create a new DragLayer from XML.
-     *
-     * @param context The application's context.
      */
     public DragController(Launcher launcher) {
         Resources r = launcher.getResources();
@@ -185,11 +173,9 @@
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
      * @param viewImageBounds the position of the image inside the view
-     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
-     *        {@link #DRAG_ACTION_COPY}
      */
     public void startDrag(View v, Bitmap bmp, DragSource source, ItemInfo dragInfo,
-            Rect viewImageBounds, int dragAction, float initialDragViewScale) {
+            Rect viewImageBounds, float initialDragViewScale, DragOptions options) {
         int[] loc = mCoordinatesTemp;
         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
         int dragLayerX = loc[0] + viewImageBounds.left
@@ -197,12 +183,8 @@
         int dragLayerY = loc[1] + viewImageBounds.top
                 + (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
 
-        startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null,
-                null, initialDragViewScale, false);
-
-        if (dragAction == DRAG_ACTION_MOVE) {
-            v.setVisibility(View.GONE);
-        }
+        startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, null,
+                null, initialDragViewScale, options);
     }
 
     /**
@@ -214,15 +196,12 @@
      * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
-     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
-     *        {@link #DRAG_ACTION_COPY}
      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
-     * @param accessible whether this drag should occur in accessibility mode
      */
     public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
-            DragSource source, ItemInfo dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
-            float initialDragViewScale, boolean accessible) {
+            DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
+            float initialDragViewScale, DragOptions options) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
         }
@@ -234,19 +213,15 @@
         }
         mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
 
-        for (DragListener listener : mListeners) {
-            listener.onDragStart(source, dragInfo, dragAction);
-        }
-
         final int registrationX = mMotionDownX - dragLayerX;
         final int registrationY = mMotionDownY - dragLayerY;
 
         final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
 
-        mIsAccessibleDrag = accessible;
         mLastDropTarget = null;
 
+        mOptions = options;
         mDragObject = new DropTarget.DragObject();
 
         final Resources res = mLauncher.getResources();
@@ -256,7 +231,7 @@
                 registrationY, initialDragViewScale, scaleDps);
 
         mDragObject.dragComplete = false;
-        if (mIsAccessibleDrag) {
+        if (mOptions.isAccessibleDrag) {
             // For an accessible drag, we assume the view is being dragged from the center.
             mDragObject.xOffset = b.getWidth() / 2;
             mDragObject.yOffset = b.getHeight() / 2;
@@ -271,6 +246,8 @@
 
         mDragObject.dragSource = source;
         mDragObject.dragInfo = dragInfo;
+        mDragObject.originalDragInfo = new ItemInfo();
+        mDragObject.originalDragInfo.copyFrom(dragInfo);
 
         if (dragOffset != null) {
             dragView.setDragVisualizeOffset(new Point(dragOffset));
@@ -282,9 +259,15 @@
         mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         dragView.show(mMotionDownX, mMotionDownY);
         mDistanceSinceScroll = 0;
+
+        for (DragListener listener : mListeners) {
+            listener.onDragStart(mDragObject, mOptions);
+        }
+
         mLastTouch[0] = mMotionDownX;
         mLastTouch[1] = mMotionDownY;
         handleMoveEvent(mMotionDownX, mMotionDownY);
+        mLauncher.getUserEventDispatcher().resetActionDurationMillis();
         return dragView;
     }
 
@@ -307,7 +290,7 @@
     }
 
     public boolean isDragging() {
-        return mDragDriver != null || mIsAccessibleDrag;
+        return mDragDriver != null || (mOptions != null && mOptions.isAccessibleDrag);
     }
 
     /**
@@ -342,7 +325,7 @@
     private void endDrag() {
         if (isDragging()) {
             mDragDriver = null;
-            mIsAccessibleDrag = false;
+            mOptions = null;
             clearScrollRunnable();
             boolean isDeferred = false;
             if (mDragObject.dragView != null) {
@@ -421,10 +404,6 @@
 
     @Override
     public void onDriverDragEnd(float x, float y, DropTarget dropTargetOverride) {
-        final int[] dragLayerPos = getClampedDragLayerPos(x, y);
-        final int dragLayerX = dragLayerPos[0];
-        final int dragLayerY = dragLayerPos[1];
-
         DropTarget dropTarget;
         PointF vec = null;
 
@@ -453,14 +432,7 @@
      * Call this from a drag source view.
      */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        @SuppressWarnings("all") // suppress dead code warning
-        final boolean debug = false;
-        if (debug) {
-            Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " Dragging="
-                    + (mDragDriver != null));
-        }
-
-        if (mIsAccessibleDrag) {
+        if (mOptions != null && mOptions.isAccessibleDrag) {
             return false;
         }
 
@@ -507,7 +479,7 @@
      */
     public void setMoveTarget(View view) {
         mMoveTarget = view;
-    }    
+    }
 
     public boolean dispatchUnhandledMove(View focused, int direction) {
         return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
@@ -603,7 +575,7 @@
      * Call this from a drag source view.
      */
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mDragDriver == null || mIsAccessibleDrag) {
+        if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
             return false;
         }
 
@@ -734,6 +706,7 @@
         final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
         mDragObject.dragSource.onDropCompleted(
                 dropTargetAsView, mDragObject, flingVel != null, accepted);
+        mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
     }
 
     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index dcff89f..e5ec6ba 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -343,16 +343,9 @@
     }
 
     private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
-        AccessibilityManager accessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (accessibilityManager.isEnabled()) {
-            int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
-            AccessibilityEvent event = AccessibilityEvent.obtain(
-                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
-            onInitializeAccessibilityEvent(event);
-            event.getText().add(getContext().getString(stringId));
-            accessibilityManager.sendAccessibilityEvent(event);
-        }
+        int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
+        Utilities.sendCustomAccessibilityEvent(
+                this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
     }
 
     private boolean isInAccessibleDrag() {
@@ -362,37 +355,27 @@
     @Override
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         // Shortcuts can appear above folder
-        View topView = mLauncher.getOpenShortcutsContainer();
+        View topView = mLauncher.getTopFloatingView();
         if (topView != null) {
-            return handleTopViewSendAccessibilityEvent(topView, child, event);
-        }
-
-        topView = mLauncher.getWorkspace().getOpenFolder();
-        if (topView != null) {
-            return handleTopViewSendAccessibilityEvent(topView, child, event);
+            if (child == topView) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
+            if (isInAccessibleDrag() && child instanceof DropTargetBar) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
+            // Skip propagating onRequestSendAccessibilityEvent for all other children
+            // which are not topView
+            return false;
         }
         return super.onRequestSendAccessibilityEvent(child, event);
     }
 
-    private boolean handleTopViewSendAccessibilityEvent(
-            View topView, View child, AccessibilityEvent event) {
-        if (child == topView) {
-            return super.onRequestSendAccessibilityEvent(child, event);
-        }
-        if (isInAccessibleDrag() && child instanceof DropTargetBar) {
-            return super.onRequestSendAccessibilityEvent(child, event);
-        }
-        // Skip propagating onRequestSendAccessibilityEvent for all other children
-        // which are not topView
-        return false;
-    }
-
     @Override
     public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
-        Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
-        if (currentFolder != null) {
-            // Only add the folder as a child for accessibility when it is open
-            childrenForAccessibility.add(currentFolder);
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            // Only add the top view as a child for accessibility when it is open
+            childrenForAccessibility.add(topView);
 
             if (isInAccessibleDrag()) {
                 childrenForAccessibility.add(mLauncher.getDropTargetBar());
@@ -1037,6 +1020,26 @@
         return mBackgroundAlpha;
     }
 
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            return topView.requestFocus(direction, previouslyFocusedRect);
+        } else {
+            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+        }
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        View topView = mLauncher.getTopFloatingView();
+        if (topView != null) {
+            topView.addFocusables(views, direction);
+        } else {
+            super.addFocusables(views, direction, focusableMode);
+        }
+    }
+
     public void setTouchCompleteListener(TouchCompleteListener listener) {
         mTouchCompleteListener = listener;
     }
diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java
new file mode 100644
index 0000000..a7f2872
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/DragOptions.java
@@ -0,0 +1,26 @@
+/*
+ * 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.dragndrop;
+
+/**
+ * Set of options to control the drag and drop behavior.
+ */
+public class DragOptions {
+
+    /** Whether or not an accessible drag operation is in progress. */
+    public boolean isAccessibleDrag = false;
+}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 96da181..19956a9 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -42,7 +42,6 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
@@ -52,7 +51,6 @@
 
 import com.android.launcher3.Alarm;
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.CellLayout.CellInfo;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
@@ -71,12 +69,12 @@
 import com.android.launcher3.UninstallDropTarget.DropTargetSource;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace.ItemOperator;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.AccessibileDragListenerAdapter;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.logging.UserEventDispatcher.LaunchSourceProvider;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -92,8 +90,7 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener, DragListener, DropTargetSource, AccessibilityDragSource,
-        LaunchSourceProvider {
+        View.OnFocusChangeListener, DragListener, DropTargetSource {
     private static final String TAG = "Launcher.Folder";
 
     /**
@@ -283,10 +280,10 @@
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return true;
-        return beginDrag(v, false);
+        return startDrag(v, new DragOptions());
     }
 
-    private boolean beginDrag(View v, boolean accessible) {
+    public boolean startDrag(View v, DragOptions options) {
         Object tag = v.getTag();
         if (tag instanceof ShortcutInfo) {
             ShortcutInfo item = (ShortcutInfo) tag;
@@ -294,35 +291,48 @@
                 return false;
             }
 
-            mLauncher.getWorkspace().beginDragShared(v, this, accessible);
-
             mCurrentDragInfo = item;
             mEmptyCellRank = item.rank;
             mCurrentDragView = v;
 
-            mContent.removeItem(mCurrentDragView);
-            mInfo.remove(mCurrentDragInfo, true);
-            mDragInProgress = true;
-            mItemAddedBackToSelfViaIcon = false;
+            mDragController.addDragListener(this);
+            if (options.isAccessibleDrag) {
+                mDragController.addDragListener(new AccessibileDragListenerAdapter(
+                        mContent, CellLayout.FOLDER_ACCESSIBILITY_DRAG) {
+
+                    @Override
+                    protected void enableAccessibleDrag(boolean enable) {
+                        super.enableAccessibleDrag(enable);
+                        mFooter.setImportantForAccessibility(enable
+                                ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                                : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+                    }
+                });
+            }
+
+            mLauncher.getWorkspace().beginDragShared(v, this, options);
         }
         return true;
     }
 
     @Override
-    public void startDrag(CellInfo cellInfo, boolean accessible) {
-        beginDrag(cellInfo.cell, accessible);
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        if (dragObject.dragSource != this) {
+            return;
+        }
+
+        mContent.removeItem(mCurrentDragView);
+        mInfo.remove(mCurrentDragInfo, true);
+        mDragInProgress = true;
+        mItemAddedBackToSelfViaIcon = false;
     }
 
     @Override
-    public void enableAccessibleDrag(boolean enable) {
-        mLauncher.getDropTargetBar().enableAccessibleDrag(enable);
-        for (int i = 0; i < mContent.getChildCount(); i++) {
-            mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
+    public void onDragEnd() {
+        if (mIsExternalDrag && mDragInProgress) {
+            completeDragExit();
         }
-
-        mFooter.setImportantForAccessibility(enable ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS :
-                IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-        mLauncher.getWorkspace().setAddNewPageOnDrag(!enable);
+        mDragController.removeDragListener(this);
     }
 
     public boolean isEditingName() {
@@ -353,7 +363,8 @@
         LauncherModel.updateItemInDatabase(mLauncher, mInfo);
 
         if (commit) {
-            sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+            Utilities.sendCustomAccessibilityEvent(
+                    this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                     getContext().getString(R.string.folder_renamed, newTitle));
         }
 
@@ -592,7 +603,9 @@
         openFolderAnim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                Utilities.sendCustomAccessibilityEvent(
+                        Folder.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         mContent.getAccessibilityDescription());
                 mState = STATE_ANIMATING;
             }
@@ -662,28 +675,6 @@
         mDragController.addDragListener(this);
     }
 
-    @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) { }
-
-    @Override
-    public void onDragEnd() {
-        if (mIsExternalDrag && mDragInProgress) {
-            completeDragExit();
-        }
-        mDragController.removeDragListener(this);
-    }
-
-    @Thunk void sendCustomAccessibilityEvent(int type, String text) {
-        AccessibilityManager accessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (accessibilityManager.isEnabled()) {
-            AccessibilityEvent event = AccessibilityEvent.obtain(type);
-            onInitializeAccessibilityEvent(event);
-            event.getText().add(text);
-            accessibilityManager.sendAccessibilityEvent(event);
-        }
-    }
-
     public void animateClosed() {
         if (!(getParent() instanceof DragLayer)) return;
         final ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(this, 0, 0.9f, 0.9f);
@@ -695,7 +686,9 @@
             }
             @Override
             public void onAnimationStart(Animator animation) {
-                sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                Utilities.sendCustomAccessibilityEvent(
+                        Folder.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         getContext().getString(R.string.folder_closed));
                 mState = STATE_ANIMATING;
             }
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index dc04597..845dbc2 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -2,8 +2,12 @@
 
 import android.view.View;
 
+import com.android.launcher3.ButtonDropTarget;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.InfoDropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.UninstallDropTarget;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -164,14 +168,35 @@
         return event;
     }
 
-    private static Target initTarget(View v) {
+    /**
+     * Used for drag and drop interaction.
+     */
+    public static LauncherLogProto.LauncherEvent initLauncherEvent(
+            int actionType,
+            View v,
+            ItemInfo info,
+            int parentSrcTargetType,
+            View parentDestTargetType){
+        LauncherLogProto.LauncherEvent event = new LauncherLogProto.LauncherEvent();
+
+        event.srcTarget = new LauncherLogProto.Target[2];
+        event.srcTarget[0] = initTarget(v, info);
+        event.srcTarget[1] = new LauncherLogProto.Target();
+        event.srcTarget[1].type = parentSrcTargetType;
+
+        event.destTarget = new LauncherLogProto.Target[2];
+        event.destTarget[0] = initTarget(v, info);
+        event.destTarget[1] = initDropTarget(parentDestTargetType);
+
+        event.action = new LauncherLogProto.Action();
+        event.action.type = actionType;
+        return event;
+    }
+
+    private static Target initTarget(View v, ItemInfo info) {
         Target t = new LauncherLogProto.Target();
         t.type = Target.ITEM;
-        if (!(v.getTag() instanceof ItemInfo)) {
-            return t;
-        }
-        ItemInfo itemInfo = (ItemInfo) v.getTag();
-        switch (itemInfo.itemType) {
+        switch (info.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 t.itemType = LauncherLogProto.APP_ICON;
                 break;
@@ -190,4 +215,30 @@
         }
         return t;
     }
+
+    private static Target initDropTarget(View v) {
+        Target t = new LauncherLogProto.Target();
+        t.type = (v instanceof ButtonDropTarget)? Target.CONTROL : Target.CONTAINER;
+        if (t.type == Target.CONTAINER) {
+            return t;
+        }
+
+        if (v instanceof InfoDropTarget) {
+            t.controlType = LauncherLogProto.APPINFO_TARGET;
+        } else if (v instanceof UninstallDropTarget) {
+            t.controlType = LauncherLogProto.UNINSTALL_TARGET;
+        } else if (v instanceof DeleteDropTarget) {
+            t.controlType = LauncherLogProto.REMOVE_TARGET;
+        }
+        return t;
+    }
+
+    private static Target initTarget(View v) {
+        Target t = new LauncherLogProto.Target();
+        t.type = Target.ITEM;
+        if (!(v.getTag() instanceof ItemInfo)) {
+            return t;
+        }
+        return initTarget(v, (ItemInfo) v.getTag());
+    }
 }
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index e4cc182..0356a9c 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -18,12 +18,15 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
 
+import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.ProviderConfig;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -37,10 +40,15 @@
  */
 public class UserEventDispatcher {
 
-    private static final boolean DEBUG_LOGGING = false;
     private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
 
+    private final boolean mIsVerbose;
+
     /**
+     * TODO: change the name of this interface to LogContainerProvider
+     * and the method name to fillInLogContainerData. Not changed to minimize CL diff
+     * in this branch.
+     *
      * Implemented by containers to provide a launch source for a given child.
      */
     public interface LaunchSourceProvider {
@@ -61,6 +69,7 @@
      */
     public static LaunchSourceProvider getLaunchProviderRecursive(View v) {
         ViewParent parent = null;
+
         if (v != null) {
             parent = v.getParent();
         } else {
@@ -88,6 +97,14 @@
     // Used for filling in predictedRank on {@link Target}s.
     private List<ComponentKey> mPredictedApps;
 
+    public UserEventDispatcher() {
+        if (ProviderConfig.IS_DOGFOOD_BUILD) {
+            mIsVerbose = Utilities.isPropertyEnabled(TAG);
+        } else {
+            mIsVerbose = false;
+        }
+    }
+
     //                      APP_ICON    SHORTCUT    WIDGET
     // --------------------------------------------------------------
     // packageNameHash      required    optional    required
@@ -104,7 +121,7 @@
         // TODO: make this percolate up the view hierarchy if needed.
         int idx = 0;
         LaunchSourceProvider provider = getLaunchProviderRecursive(v);
-        if (!(v.getTag() instanceof ItemInfo)) {
+        if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
             return null;
         }
         ItemInfo itemInfo = (ItemInfo) v.getTag();
@@ -122,8 +139,8 @@
         }
 
         // Fill in the duration of time spent navigating in Launcher and the container.
-        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
-        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        event.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
         return event;
     }
 
@@ -139,8 +156,8 @@
         LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH, Target.CONTROL);
         event.action.touch = action;
         event.srcTarget[0].controlType = controlType;
-        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
-        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        event.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
         dispatchUserEvent(event, null);
     }
 
@@ -149,8 +166,8 @@
         event.action.touch = action;
         event.action.dir = dir;
         event.srcTarget[0].containerType = containerType;
-        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
-        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        event.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
         dispatchUserEvent(event, null);
     }
 
@@ -158,14 +175,14 @@
         LauncherEvent event = LoggerUtils.initLauncherEvent(
                 Action.TOUCH, icon, Target.CONTAINER);
         LaunchSourceProvider provider = getLaunchProviderRecursive(icon);
-        if (!(icon.getTag() instanceof ItemInfo)) {
+        if (icon == null && !(icon.getTag() instanceof ItemInfo)) {
             return;
         }
         ItemInfo info = (ItemInfo) icon.getTag();
         provider.fillInLaunchSourceData(icon, info, event.srcTarget[0], event.srcTarget[1]);
         event.action.touch = Action.LONGPRESS;
-        event.elapsedContainerMillis = System.currentTimeMillis() - mElapsedContainerMillis;
-        event.elapsedSessionMillis = System.currentTimeMillis() - mElapsedSessionMillis;
+        event.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
         dispatchUserEvent(event, null);
     }
 
@@ -173,39 +190,66 @@
         mPredictedApps = predictedApps;
     }
 
+    public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
+        LauncherEvent event = LoggerUtils.initLauncherEvent(Action.TOUCH,
+                dragObj.dragView,
+                dragObj.originalDragInfo,
+                Target.CONTAINER,
+                dropTargetAsView);
+        event.action.touch = Action.DRAGDROP;
+
+        dragObj.dragSource.fillInLaunchSourceData(null, dragObj.originalDragInfo,
+                event.srcTarget[0], event.srcTarget[1]);
+
+        if (dropTargetAsView instanceof LaunchSourceProvider) {
+            ((LaunchSourceProvider) dropTargetAsView).fillInLaunchSourceData(null,
+                    dragObj.dragInfo, event.destTarget[0], event.destTarget[1]);
+
+        }
+
+        event.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
+        event.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
+        event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis;
+        dispatchUserEvent(event, null);
+    }
+
     /**
      * Currently logs following containers: workspace, allapps, widget tray.
      */
     public final void resetElapsedContainerMillis() {
-        mElapsedContainerMillis = System.currentTimeMillis();
+        mElapsedContainerMillis = SystemClock.uptimeMillis();
     }
 
     public final void resetElapsedSessionMillis() {
-        mElapsedSessionMillis = System.currentTimeMillis();
-        mElapsedContainerMillis = System.currentTimeMillis();
+        mElapsedSessionMillis = SystemClock.uptimeMillis();
+        mElapsedContainerMillis = SystemClock.uptimeMillis();
     }
 
     public final void resetActionDurationMillis() {
-        mActionDurationMillis = System.currentTimeMillis();
+        mActionDurationMillis = SystemClock.uptimeMillis();
     }
 
     public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
-        if (DEBUG_LOGGING) {
-            Log.d(TAG, String.format(Locale.US,
-                    "\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)));
-            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));
+        if (!mIsVerbose) {
+            return;
         }
+        Log.d(TAG, String.format(Locale.US,
+                "\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 != null && 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 != null && ev.destTarget.length > 1 ?
+                            ev.destTarget[1] : null)));
+        }
+        Log.d(TAG, String.format(Locale.US,
+                " Elapsed container %d ms session %d ms action %d ms",
+                ev.elapsedContainerMillis,
+                ev.elapsedSessionMillis,
+                ev.actionDurationMillis));
     }
 }
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index ddc9cbf..c86ba86 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -46,17 +46,12 @@
      */
     public String titleSectionName;
 
-    int flags = 0;
-
     PackageItemInfo(String packageName) {
         this.packageName = packageName;
     }
 
     @Override
-    public String toString() {
-        return "PackageItemInfo(title=" + title + " id=" + this.id
-                + " type=" + this.itemType + " container=" + this.container
-                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
-                + " spanX=" + spanX + " spanY=" + spanY + " user=" + user + ")";
+    protected String dumpProperties() {
+        return super.dumpProperties() + " packageName=" + packageName;
     }
 }
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 4d10506..3c7ba32 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -31,7 +31,6 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -62,9 +61,9 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.graphics.TriangleShape;
-import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
@@ -76,8 +75,7 @@
  */
 @TargetApi(Build.VERSION_CODES.N)
 public class DeepShortcutsContainer extends LinearLayout implements View.OnLongClickListener,
-        View.OnTouchListener, DragSource, DragController.DragListener,
-        UserEventDispatcher.LaunchSourceProvider {
+        View.OnTouchListener, DragSource, DragController.DragListener {
     private static final String TAG = "ShortcutsContainer";
 
     private final Point mIconShift = new Point();
@@ -255,8 +253,10 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mOpenCloseAnimator = null;
-
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                Utilities.sendCustomAccessibilityEvent(
+                        DeepShortcutsContainer.this,
+                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                        getContext().getString(R.string.action_deep_shortcut));
             }
         });
 
@@ -516,8 +516,8 @@
         mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
 
         DragView dv = mLauncher.getWorkspace().beginDragShared(
-                sv.getBubbleText(), this, false, sv.getFinalInfo(),
-                new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift));
+                sv.getBubbleText(), this, sv.getFinalInfo(),
+                new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions());
         dv.animateShift(-mIconShift.x, -mIconShift.y);
 
         // TODO: support dragging from within folder without having to close it
@@ -561,7 +561,7 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) {
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         // Either the original icon or one of the shortcuts was dragged.
         // Hide the container, but don't remove it yet because that interferes with touch events.
         animateClose();
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index a569850..486b18e 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -35,10 +35,4 @@
         componentName = new ComponentName(activityInfo.packageName, activityInfo.name);
         itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
     }
-
-    @Override
-    public String toString() {
-        return String.format("PendingAddShortcutInfo package=%s, name=%s",
-                activityInfo.packageName, activityInfo.name);
-    }
 }
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index de06ab6..f800ac4 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -59,10 +59,4 @@
     public boolean isCustomWidget() {
         return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
     }
-
-    @Override
-    public String toString() {
-        return String.format("PendingAddWidgetInfo package=%s, name=%s",
-                componentName.getPackageName(), componentName.getShortClassName());
-    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index 297505b..049871f 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -11,6 +11,7 @@
 
 import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
@@ -18,6 +19,7 @@
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.util.Thunk;
 
 public class WidgetHostViewLoader implements DragController.DragListener {
@@ -47,7 +49,7 @@
     }
 
     @Override
-    public void onDragStart(DragSource source, ItemInfo info, int dragAction) { }
+    public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { }
 
     @Override
     public void onDragEnd() {
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 352cea4..70b2945 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.DeleteDropTarget;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.ItemInfo;
@@ -45,6 +46,8 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.Thunk;
 
 /**
@@ -249,7 +252,7 @@
 
         // Start the drag
         mDragController.startDrag(image, preview, this, createItemInfo,
-                bounds, DragController.DRAG_ACTION_COPY, scale);
+                bounds, scale, new DragOptions());
         return true;
     }
 
@@ -349,4 +352,9 @@
         }
         return mWidgetPreviewLoader;
     }
+
+    @Override
+    public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
+        targetParent.containerType = LauncherLogProto.WIDGETS;
+    }
 }
\ No newline at end of file