Merge "Making QSB alingment match with that of recents" into ub-launcher3-burnaby
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index e383d74..69f42bb 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -44,19 +44,6 @@
             style="@style/DropTargetButtonContainer"
             android:layout_weight="1" >
 
-            <!-- Uninstall target -->
-
-            <com.android.launcher3.UninstallDropTarget
-                android:id="@+id/uninstall_target_text"
-                style="@style/DropTargetButton"
-                android:drawableStart="@drawable/uninstall_target_selector"
-                android:text="@string/delete_target_uninstall_label" />
-        </FrameLayout>
-
-        <FrameLayout
-            style="@style/DropTargetButtonContainer"
-            android:layout_weight="1" >
-
             <!-- Info target -->
 
             <com.android.launcher3.InfoDropTarget
@@ -65,6 +52,19 @@
                 android:drawableStart="@drawable/info_target_selector"
                 android:text="@string/info_target_label" />
         </FrameLayout>
+
+        <FrameLayout
+            style="@style/DropTargetButtonContainer"
+            android:layout_weight="1" >
+
+            <!-- Uninstall target -->
+
+            <com.android.launcher3.UninstallDropTarget
+                android:id="@+id/uninstall_target_text"
+                style="@style/DropTargetButton"
+                android:drawableStart="@drawable/uninstall_target_selector"
+                android:text="@string/delete_target_uninstall_label" />
+        </FrameLayout>
     </LinearLayout>
 
 </com.android.launcher3.SearchDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 50294c0..64ddea1 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -47,7 +47,7 @@
             android:fadingEdge="horizontal"
 
             android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
+            android:textSize="16sp"
             android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
             android:shadowRadius="2.0"
@@ -64,7 +64,7 @@
             android:layout_weight="0"
             android:gravity="start"
             android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
+            android:textSize="16sp"
             android:textAlignment="viewStart"
             android:fontFamily="sans-serif-condensed"
             android:shadowRadius="2.0"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 52306e3..a68f53a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -77,7 +77,7 @@
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
     <string name="apps_view_search_bar_hint">Search Apps</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
-    <string name="loading_apps_message">Loading Apps...</string>
+    <string name="loading_apps_message">Loading Apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
     <string name="apps_view_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
 
@@ -91,8 +91,6 @@
     <string name="rename_action">OK</string>
     <!-- Buttons in Rename folder dialog box -->
     <string name="cancel_action">Cancel</string>
-    <!-- Label for button to sort folder contents. [CHAR_LIMIT=10] -->
-    <string name="sort_alphabetical">A-Z</string>
 
     <!-- Shortcuts -->
     <skip />
@@ -309,13 +307,13 @@
 
 <!-- Strings for accessibility actions -->
     <!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
-    <string name="action_add_to_workspace">Add To Workspace</string>
+    <string name="action_add_to_workspace">Add to workspace</string>
 
     <!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
     <string name="item_added_to_workspace">Item added to workspace</string>
 
     <!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
-    <string name="item_removed_from_workspace">Item removed from workspace</string>
+    <string name="item_removed">Item removed</string>
 
     <!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
     <string name="action_move">Move Item</string>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 2402507..3c698c0 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -349,7 +349,7 @@
                 mTmpRect.right, mTmpRect.bottom);
     }
 
-    static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
+    public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
         if (rect == null) {
             rect = new Rect();
         }
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index 16244ee..f889712 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -156,6 +156,10 @@
         handleTouchEvent(ev);
     }
 
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        // Do nothing
+    }
+
     /**
      * Handles the touch event and determines whether to show the fast scroller (or updates it if
      * it is already showing).
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 5b39908..fb49df5 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -26,18 +26,19 @@
 import android.graphics.drawable.TransitionDrawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.TextView;
 
-import com.android.launcher3.R;
 import com.android.launcher3.util.Thunk;
 
 /**
  * Implements a DropTarget.
  */
-public abstract class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
+public abstract class ButtonDropTarget extends TextView
+        implements DropTarget, DragController.DragListener, OnClickListener {
 
     private static int DRAG_VIEW_DROP_DURATION = 285;
 
@@ -256,4 +257,18 @@
     public void getLocationInDragLayer(int[] loc) {
         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
     }
+
+    public void enableAccessibleDrag(boolean enable) {
+        setOnClickListener(enable ? this : null);
+    }
+
+    protected String getAccessibilityDropConfirmation() {
+        return null;
+    }
+
+    @Override
+    public void onClick(View v) {
+        LauncherAppState.getInstance().getAccessibilityDelegate()
+            .handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
+    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f4afb95..85653be 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -48,9 +48,7 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
 
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
@@ -121,7 +119,6 @@
 
     // If we're actively dragging something over this screen, mIsDragOverlapping is true
     private boolean mIsDragOverlapping = false;
-    boolean mUseActiveGlowBackground = false;
 
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
@@ -557,7 +554,7 @@
             Resources res = getContext().getResources();
             View child = getChildAt(x, y);
             if (child == null || child == dragInfo.item) {
-                return res.getString(R.string.move_to_empty_cell, x, y);
+                return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
             } else {
                 ItemInfo info = (ItemInfo) child.getTag();
                 if (info instanceof AppInfo || info instanceof ShortcutInfo) {
@@ -684,10 +681,6 @@
         }
     }
 
-    void setUseActiveGlowBackground(boolean use) {
-        mUseActiveGlowBackground = use;
-    }
-
     void disableBackground() {
         mDrawBackground = false;
     }
@@ -703,7 +696,6 @@
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
-            setUseActiveGlowBackground(mIsDragOverlapping);
             invalidate();
         }
     }
@@ -722,7 +714,7 @@
         if (mDrawBackground && mBackgroundAlpha > 0.0f) {
             Drawable bg;
 
-            if (mUseActiveGlowBackground) {
+            if (mIsDragOverlapping) {
                 // In the mini case, we draw the active_glow bg *over* the active background
                 bg = mActiveGlowBackground;
             } else {
@@ -906,7 +898,7 @@
     }
 
     public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
-            boolean markCells, boolean inLayout) {
+            boolean markCells) {
         final LayoutParams lp = params;
 
         // Hotseat icons - remove text
@@ -927,7 +919,7 @@
             if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
 
             child.setId(childId);
-            mShortcutsAndWidgets.addView(child, index, lp, inLayout);
+            mShortcutsAndWidgets.addView(child, index, lp);
 
             if (markCells) markCellsAsOccupiedForView(child);
 
@@ -936,11 +928,6 @@
         return false;
     }
 
-    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
-            boolean markCells) {
-        return addViewToCellLayout(child, index, childId, params, markCells, false);
-    }
-
     @Override
     public void removeAllViews() {
         clearOccupiedCells();
@@ -955,10 +942,6 @@
         }
     }
 
-    public void removeViewWithoutMarkingCells(View view) {
-        mShortcutsAndWidgets.removeView(view);
-    }
-
     @Override
     public void removeView(View view) {
         markCellsAsUnoccupiedForView(view);
@@ -1088,9 +1071,7 @@
 
     public float getDistanceFromCell(float x, float y, int[] cell) {
         cellToCenterPoint(cell[0], cell[1], mTmpPoint);
-        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
-                Math.pow(y - mTmpPoint[1], 2));
-        return distance;
+        return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
     }
 
     int getCellWidth() {
@@ -1109,28 +1090,6 @@
         return mHeightGap;
     }
 
-    Rect getContentRect(Rect r) {
-        if (r == null) {
-            r = new Rect();
-        }
-        int left = getPaddingLeft();
-        int top = getPaddingTop();
-        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
-        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
-        r.set(left, top, right, bottom);
-        return r;
-    }
-
-    /** Return a rect that has the cellWidth/cellHeight (left, top), and
-     * widthGap/heightGap (right, bottom) */
-    static void getMetrics(Rect metrics, int paddedMeasureWidth,
-            int paddedMeasureHeight, int countX, int countY) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX),
-                grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0);
-    }
-
     public void setFixedSize(int width, int height) {
         mFixedWidth = width;
         mFixedHeight = height;
@@ -1246,7 +1205,6 @@
     }
 
     public void setBackgroundAlphaMultiplier(float multiplier) {
-
         if (mBackgroundAlphaMultiplier != multiplier) {
             mBackgroundAlphaMultiplier = multiplier;
             invalidate();
@@ -1360,36 +1318,6 @@
         return false;
     }
 
-    /**
-     * Estimate where the top left cell of the dragged item will land if it is dropped.
-     *
-     * @param originX The X value of the top left corner of the item
-     * @param originY The Y value of the top left corner of the item
-     * @param spanX The number of horizontal cells that the item spans
-     * @param spanY The number of vertical cells that the item spans
-     * @param result The estimated drop cell X and Y.
-     */
-    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
-        final int countX = mCountX;
-        final int countY = mCountY;
-
-        // pointToCellRounded takes the top left of a cell but will pad that with
-        // cellWidth/2 and cellHeight/2 when finding the matching cell
-        pointToCellRounded(originX, originY, result);
-
-        // If the item isn't fully on this screen, snap to the edges
-        int rightOverhang = result[0] + spanX - countX;
-        if (rightOverhang > 0) {
-            result[0] -= rightOverhang; // Snap to right
-        }
-        result[0] = Math.max(0, result[0]); // Snap to left
-        int bottomOverhang = result[1] + spanY - countY;
-        if (bottomOverhang > 0) {
-            result[1] -= bottomOverhang; // Snap to bottom
-        }
-        result[1] = Math.max(0, result[1]); // Snap to top
-    }
-
     void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
             int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
         final int oldDragCellX = mDragCell[0];
@@ -1473,9 +1401,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
-            int[] result) {
-        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
     }
 
     /**
@@ -1495,30 +1422,10 @@
      */
     int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
             int spanY, int[] result, int[] resultSpan) {
-        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
+        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
                 result, resultSpan);
     }
 
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreOccupied If true, the result can be an occupied cell
-     * @param result Array in which to place the result, or null (in which case a new array will
-     *        be allocated)
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
-            boolean ignoreOccupied, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY,
-                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
-    }
-
     private final Stack<Rect> mTempRectStack = new Stack<Rect>();
     private void lazyInitTempRectStack() {
         if (mTempRectStack.isEmpty()) {
@@ -1550,12 +1457,9 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
-            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
-            boolean[][] occupied) {
+    private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
+            int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
         lazyInitTempRectStack();
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
 
         // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
         // to the center of the item, but we are searching based on the top-left cell, so
@@ -1586,7 +1490,7 @@
                     // First, let's see if this thing fits anywhere
                     for (int i = 0; i < minSpanX; i++) {
                         for (int j = 0; j < minSpanY; j++) {
-                            if (occupied[x + i][y + j]) {
+                            if (mOccupied[x + i][y + j]) {
                                 continue inner;
                             }
                         }
@@ -1603,7 +1507,7 @@
                     while (!(hitMaxX && hitMaxY)) {
                         if (incX && !hitMaxX) {
                             for (int j = 0; j < ySize; j++) {
-                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
+                                if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
                                     // We can't move out horizontally
                                     hitMaxX = true;
                                 }
@@ -1613,7 +1517,7 @@
                             }
                         } else if (!hitMaxY) {
                             for (int i = 0; i < xSize; i++) {
-                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
+                                if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
                                     // We can't move out vertically
                                     hitMaxY = true;
                                 }
@@ -1646,8 +1550,7 @@
                     }
                 }
                 validRegions.push(currentRect);
-                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
-                        + Math.pow(cellXY[1] - pixelY, 2));
+                double distance = Math.hypot(cellXY[0] - pixelX,  cellXY[1] - pixelY);
 
                 if ((distance <= bestDistance && !contained) ||
                         currentRect.contains(bestRect)) {
@@ -1662,8 +1565,6 @@
                 }
             }
         }
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
 
         // Return -1, -1 if no suitable location found
         if (bestDistance == Double.MAX_VALUE) {
@@ -1717,8 +1618,7 @@
                     }
                 }
 
-                float distance = (float)
-                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
+                float distance = (float) Math.hypot(x - cellX, y - cellY);
                 int[] curDirection = mTmpPoint;
                 computeDirectionVector(x - cellX, y - cellY, curDirection);
                 // The direction score is just the dot product of the two candidate direction
@@ -2334,7 +2234,7 @@
         }
     }
 
-    ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, int[] direction, View dragView, boolean decX,
             ItemConfiguration solution) {
         // Copy the current state into the solution. This solution will be manipulated as necessary.
@@ -2623,7 +2523,7 @@
         mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
     }
 
-    public void setUseTempCoords(boolean useTempCoords) {
+    private void setUseTempCoords(boolean useTempCoords) {
         int childCount = mShortcutsAndWidgets.getChildCount();
         for (int i = 0; i < childCount; i++) {
             LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
@@ -2631,11 +2531,11 @@
         }
     }
 
-    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, View dragView, ItemConfiguration solution) {
         int[] result = new int[2];
         int[] resultSpan = new int[2];
-        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
+        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
                 resultSpan);
         if (result[0] >= 0 && result[1] >= 0) {
             copyCurrentStateToSolution(solution, false);
@@ -2952,45 +2852,6 @@
     }
 
     /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
-    }
-
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param minSpanX The minimum horizontal span required
-     * @param minSpanY The minimum vertical span required
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
-            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
-        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
-                result, resultSpan, mOccupied);
-    }
-
-    /**
      * Find a starting cell position that will fit the given bounds nearest the requested
      * cell location. Uses Euclidean distance to score multiple vacant areas.
      *
@@ -3003,9 +2864,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(
-            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
     }
 
     boolean existsEmptyCell() {
@@ -3026,103 +2886,32 @@
      * @return True if a vacant cell of the specified dimension was found, false otherwise.
      */
     public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
-    }
-
-    /**
-     * Like above, but ignores any cells occupied by the item "ignoreView"
-     *
-     * @param cellXY The array that will contain the position of a vacant cell if such a cell
-     *               can be found.
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @return
-     */
-    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
-                ignoreView, mOccupied);
-    }
-
-    /**
-     * Like above, but if intersectX and intersectY are not -1, then this method will try to
-     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
-     *
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @param intersectX The X coordinate of the cell that we should try to overlap
-     * @param intersectX The Y coordinate of the cell that we should try to overlap
-     *
-     * @return True if a vacant cell of the specified dimension was found, false otherwise.
-     */
-    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY) {
-        return findCellForSpanThatIntersectsIgnoring(
-                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
-    }
-
-    /**
-     * The superset of the above two methods
-     */
-    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
-
         boolean foundCell = false;
-        while (true) {
-            int startX = 0;
-            if (intersectX >= 0) {
-                startX = Math.max(startX, intersectX - (spanX - 1));
-            }
-            int endX = mCountX - (spanX - 1);
-            if (intersectX >= 0) {
-                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
-            }
-            int startY = 0;
-            if (intersectY >= 0) {
-                startY = Math.max(startY, intersectY - (spanY - 1));
-            }
-            int endY = mCountY - (spanY - 1);
-            if (intersectY >= 0) {
-                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
-            }
+        final int endX = mCountX - (spanX - 1);
+        final int endY = mCountY - (spanY - 1);
 
-            for (int y = startY; y < endY && !foundCell; y++) {
-                inner:
-                for (int x = startX; x < endX; x++) {
-                    for (int i = 0; i < spanX; i++) {
-                        for (int j = 0; j < spanY; j++) {
-                            if (occupied[x + i][y + j]) {
-                                // small optimization: we can skip to after the column we just found
-                                // an occupied cell
-                                x += i;
-                                continue inner;
-                            }
+        for (int y = 0; y < endY && !foundCell; y++) {
+            inner:
+            for (int x = 0; x < endX; x++) {
+                for (int i = 0; i < spanX; i++) {
+                    for (int j = 0; j < spanY; j++) {
+                        if (mOccupied[x + i][y + j]) {
+                            // small optimization: we can skip to after the column we just found
+                            // an occupied cell
+                            x += i;
+                            continue inner;
                         }
                     }
-                    if (cellXY != null) {
-                        cellXY[0] = x;
-                        cellXY[1] = y;
-                    }
-                    foundCell = true;
-                    break;
                 }
-            }
-            if (intersectX == -1 && intersectY == -1) {
+                if (cellXY != null) {
+                    cellXY[0] = x;
+                    cellXY[1] = y;
+                }
+                foundCell = true;
                 break;
-            } else {
-                // if we failed to find anything, try again but without any requirements of
-                // intersecting
-                intersectX = -1;
-                intersectY = -1;
-                continue;
             }
         }
 
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
         return foundCell;
     }
 
@@ -3232,13 +3021,6 @@
         return result;
     }
 
-    public int[] cellSpansToSize(int hSpans, int vSpans) {
-        int[] size = new int[2];
-        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
-        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
-        return size;
-    }
-
     /**
      * Calculate the grid spans needed to fit given item
      */
@@ -3262,44 +3044,6 @@
         info.spanY = spans[1];
     }
 
-    /**
-     * Find the first vacant cell, if there is one.
-     *
-     * @param vacant Holds the x and y coordinate of the vacant cell
-     * @param spanX Horizontal cell span.
-     * @param spanY Vertical cell span.
-     *
-     * @return True if a vacant cell was found
-     */
-    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
-
-        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
-    }
-
-    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
-            int xCount, int yCount, boolean[][] occupied) {
-
-        for (int y = 0; (y + spanY) <= yCount; y++) {
-            for (int x = 0; (x + spanX) <= xCount; x++) {
-                boolean available = !occupied[x][y];
-out:            for (int i = x; i < x + spanX; i++) {
-                    for (int j = y; j < y + spanY; j++) {
-                        available = available && !occupied[i][j];
-                        if (!available) break out;
-                    }
-                }
-
-                if (available) {
-                    vacant[0] = x;
-                    vacant[1] = y;
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
     private void clearOccupiedCells() {
         for (int x = 0; x < mCountX; x++) {
             for (int y = 0; y < mCountY; y++) {
@@ -3308,27 +3052,16 @@
         }
     }
 
-    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
-        markCellsAsUnoccupiedForView(view);
-        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
-    }
-
     public void markCellsAsOccupiedForView(View view) {
-        markCellsAsOccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
     }
 
     public void markCellsAsUnoccupiedForView(View view) {
-        markCellsAsUnoccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
     }
 
     private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
@@ -3374,17 +3107,6 @@
         return new CellLayout.LayoutParams(p);
     }
 
-    public static class CellLayoutAnimationController extends LayoutAnimationController {
-        public CellLayoutAnimationController(Animation animation, float delay) {
-            super(animation, delay);
-        }
-
-        @Override
-        protected long getDelayForView(View view) {
-            return (int) (Math.random() * 150);
-        }
-    }
-
     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
         /**
          * Horizontal location of the item in the grid.
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
index eb7c26a..a43ab67 100644
--- a/src/com/android/launcher3/DeferredHandler.java
+++ b/src/com/android/launcher3/DeferredHandler.java
@@ -20,12 +20,10 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
-import android.util.Pair;
 
 import com.android.launcher3.util.Thunk;
 
 import java.util.LinkedList;
-import java.util.ListIterator;
 
 /**
  * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
@@ -35,20 +33,18 @@
  * This class is fifo.
  */
 public class DeferredHandler {
-    @Thunk LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
+    @Thunk LinkedList<Runnable> mQueue = new LinkedList<>();
     private MessageQueue mMessageQueue = Looper.myQueue();
     private Impl mHandler = new Impl();
 
     @Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
         public void handleMessage(Message msg) {
-            Pair<Runnable, Integer> p;
             Runnable r;
             synchronized (mQueue) {
                 if (mQueue.size() == 0) {
                     return;
                 }
-                p = mQueue.removeFirst();
-                r = p.first;
+                r = mQueue.removeFirst();
             }
             r.run();
             synchronized (mQueue) {
@@ -79,11 +75,8 @@
 
     /** Schedule runnable to run after everything that's on the queue right now. */
     public void post(Runnable runnable) {
-        post(runnable, 0);
-    }
-    public void post(Runnable runnable, int type) {
         synchronized (mQueue) {
-            mQueue.add(new Pair<Runnable, Integer>(runnable, type));
+            mQueue.add(runnable);
             if (mQueue.size() == 1) {
                 scheduleNextLocked();
             }
@@ -92,31 +85,10 @@
 
     /** Schedule runnable to run when the queue goes idle. */
     public void postIdle(final Runnable runnable) {
-        postIdle(runnable, 0);
-    }
-    public void postIdle(final Runnable runnable, int type) {
-        post(new IdleRunnable(runnable), type);
+        post(new IdleRunnable(runnable));
     }
 
-    public void cancelRunnable(Runnable runnable) {
-        synchronized (mQueue) {
-            while (mQueue.remove(runnable)) { }
-        }
-    }
-    public void cancelAllRunnablesOfType(int type) {
-        synchronized (mQueue) {
-            ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
-            Pair<Runnable, Integer> p;
-            while (iter.hasNext()) {
-                p = iter.next();
-                if (p.second == type) {
-                    iter.remove();
-                }
-            }
-        }
-    }
-
-    public void cancel() {
+    public void cancelAll() {
         synchronized (mQueue) {
             mQueue.clear();
         }
@@ -124,20 +96,19 @@
 
     /** Runs all queued Runnables from the calling thread. */
     public void flush() {
-        LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
+        LinkedList<Runnable> queue = new LinkedList<>();
         synchronized (mQueue) {
             queue.addAll(mQueue);
             mQueue.clear();
         }
-        for (Pair<Runnable, Integer> p : queue) {
-            p.first.run();
+        for (Runnable r : queue) {
+            r.run();
         }
     }
 
     void scheduleNextLocked() {
         if (mQueue.size() > 0) {
-            Pair<Runnable, Integer> p = mQueue.getFirst();
-            Runnable peek = p.first;
+            Runnable peek = mQueue.getFirst();
             if (peek instanceof IdleRunnable) {
                 mMessageQueue.addIdleHandler(mHandler);
             } else {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index aa3e66c..e741b97 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -29,7 +29,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 
-import com.android.launcher3.R;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.WidgetsContainerView;
 
@@ -59,13 +58,15 @@
         setDrawable(R.drawable.remove_target_selector);
     }
 
-    public static boolean willAcceptDrop(DragSource source, Object info) {
-        return (info instanceof ItemInfo) && source.supportsDeleteDropTarget();
+    public static boolean supportsDrop(Object info) {
+        return (info instanceof ShortcutInfo)
+                || (info instanceof LauncherAppWidgetInfo)
+                || (info instanceof FolderInfo);
     }
 
     @Override
     protected boolean supportsDrop(DragSource source, Object info) {
-        return willAcceptDrop(source, info);
+        return source.supportsDeleteDropTarget() && supportsDrop(info);
     }
 
     @Override
@@ -304,4 +305,9 @@
         dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
+
+    @Override
+    protected String getAccessibilityDropConfirmation() {
+        return getResources().getString(R.string.item_removed);
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 40998a5..deb8075 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -460,8 +460,7 @@
     }
 
     @Thunk float dist(PointF p0, PointF p1) {
-        return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
-                (p1.y-p0.y)*(p1.y-p0.y));
+        return (float) Math.hypot(p1.x - p0.x, p1.y - p0.y);
     }
 
     private float weight(PointF a, PointF b,
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index b24608c..3b21c2b 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -462,8 +462,7 @@
                 mLastTouchUpTime = System.currentTimeMillis();
                 if (mDragging) {
                     PointF vec = isFlingingToDelete(mDragObject.dragSource);
-                    if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource,
-                            mDragObject.dragInfo)) {
+                    if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
                         vec = null;
                     }
                     if (vec != null) {
@@ -514,8 +513,7 @@
         checkTouchMove(dropTarget);
 
         // Check if we are hovering over the scroll areas
-        mDistanceSinceScroll +=
-            Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+        mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
         mLastTouch[0] = x;
         mLastTouch[1] = y;
         checkScrollState(x, y);
@@ -617,7 +615,7 @@
 
             if (mDragging) {
                 PointF vec = isFlingingToDelete(mDragObject.dragSource);
-                if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, mDragObject.dragInfo)) {
+                if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
                     vec = null;
                 }
                 if (vec != null) {
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index ab2e094..91f97fa 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -657,8 +657,7 @@
             final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
 
         // Calculate the duration of the animation based on the object's distance
-        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
-                Math.pow(to.top - from.top, 2));
+        final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
         final Resources res = getResources();
         final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
 
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index c35ce94..03a9019 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -83,12 +83,6 @@
     public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
 
     /**
-     * Time in milliseconds for which an icon sticks to the target position
-     * in case of a sorted folder.
-     */
-    private static final int SORTED_STICKY_REORDER_DELAY = 1500;
-
-    /**
      * Fraction of icon width which behave as scroll region.
      */
     private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
@@ -417,7 +411,7 @@
         if (!(getParent() instanceof DragLayer)) return;
 
         mContent.completePendingPageChanges();
-        if (!(mDragInProgress && mContent.mIsSorted)) {
+        if (!mDragInProgress) {
             // Open on the first page.
             mContent.snapToPageImmediately(0);
         }
@@ -459,7 +453,7 @@
 
             int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
             int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
-            float radius = (float) Math.sqrt(rx * rx + ry * ry);
+            float radius = (float) Math.hypot(rx, ry);
             AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
             Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
                     (int) getPivotY(), 0, radius);
@@ -533,12 +527,6 @@
         mIsExternalDrag = true;
         mDragInProgress = true;
 
-        if (mContent.mIsSorted) {
-            mScrollPauseAlarm.setOnAlarmListener(null);
-            mScrollPauseAlarm.cancelAlarm();
-            mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
-        }
-
         // Since this folder opened by another controller, it might not get onDrop or
         // onDropComplete. Perform cleanup once drag-n-drop ends.
         mDragController.addDragListener(this);
@@ -745,9 +733,18 @@
                 replaceFolderWithFinalItem();
             }
         } else {
-            rearrangeChildren();
             // The drag failed, we need to return the item to the folder
+            ShortcutInfo info = (ShortcutInfo) d.dragInfo;
+            View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
+                    ? mCurrentDragView : mContent.createNewView(info);
+            ArrayList<View> views = getItemsInReadingOrder();
+            views.add(info.rank, icon);
+            mContent.arrangeChildren(views, views.size());
+            mItemsInvalidated = true;
+
+            mSuppressOnAdd = true;
             mFolderIcon.onDrop(d);
+            mSuppressOnAdd = false;
         }
 
         if (target != this) {
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 80b1564..69b2ae7 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -33,6 +33,7 @@
 
     /**
      * The folder is locked in sorted mode
+     * @deprecated
      */
     public static final int FLAG_ITEMS_SORTED = 0x00000001;
 
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 6174892..c68ef72 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -20,23 +20,16 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.Switch;
 
 import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
 import com.android.launcher3.PageIndicator.PageMarkerResources;
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.util.Thunk;
 
-import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -47,17 +40,10 @@
 
     private static final boolean ALLOW_FOLDER_SCROLL = true;
 
-    // To enable this flag, user_folder.xml needs to be modified to add sort button.
-    private static final boolean ALLOW_ITEM_SORTING = false;
-
     private static final int REORDER_ANIMATION_DURATION = 230;
     private static final int START_VIEW_REORDER_DELAY = 30;
     private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
 
-    private static final int SPAN_TO_PAGE_DURATION = 350;
-    private static final int SORT_ANIM_HIDE_DURATION = 130;
-    private static final int SORT_ANIM_SHOW_DURATION = 160;
-
     /**
      * Fraction of the width to scroll when showing the next page hint.
      */
@@ -87,13 +73,8 @@
     private FocusIndicatorView mFocusIndicatorView;
     private PagedFolderKeyEventListener mKeyListener;
 
-    private View mSortButton;
-    private Switch mSortSwitch;
     private View mPageIndicator;
 
-    private boolean mSortOperationPending;
-    boolean mIsSorted;
-
     public FolderPagedView(Context context, AttributeSet attrs) {
         super(context, attrs);
         LauncherAppState app = LauncherAppState.getInstance();
@@ -121,132 +102,6 @@
         mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
         mKeyListener = new PagedFolderKeyEventListener(folder);
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
-
-        if (ALLOW_ITEM_SORTING) {
-            // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
-        }
-    }
-
-    /**
-     * Called when sort button is clicked.
-     */
-    private void onSortClicked() {
-        if (mSortOperationPending) {
-            return;
-        }
-        if (mIsSorted) {
-            setIsSorted(false, true);
-        } else {
-            mSortOperationPending = true;
-            doSort();
-        }
-    }
-
-    private void setIsSorted(boolean isSorted, boolean saveChanges) {
-        mIsSorted = isSorted;
-        if (ALLOW_ITEM_SORTING) {
-            mSortSwitch.setChecked(isSorted);
-            mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
-                    saveChanges ? mFolder.mLauncher : null);
-        }
-    }
-
-    /**
-     * Sorts the contents of the folder and animates the icons on the first page to reflect
-     * the changes.
-     * Steps:
-     *      1. Scroll to first page
-     *      2. Sort all icons in one go
-     *      3. Re-apply the old IconInfos on the first page (so that there is no instant change)
-     *      4. Animate each view individually to reflect the new icon.
-     */
-    private void doSort() {
-        if (!mSortOperationPending) {
-            return;
-        }
-        if (getNextPage() != 0) {
-            snapToPage(0, SPAN_TO_PAGE_DURATION, new DecelerateInterpolator());
-            return;
-        }
-
-        mSortOperationPending = false;
-        ShortcutInfo[][] oldItems = new ShortcutInfo[mGridCountX][mGridCountY];
-        CellLayout currentPage = getCurrentCellLayout();
-        for (int x = 0; x < mGridCountX; x++) {
-            for (int y = 0; y < mGridCountY; y++) {
-                View v = currentPage.getChildAt(x, y);
-                if (v != null) {
-                    oldItems[x][y] = (ShortcutInfo) v.getTag();
-                }
-            }
-        }
-
-        ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
-        Collections.sort(views, new ViewComparator());
-        arrangeChildren(views, views.size());
-
-        int delay = 0;
-        float delayAmount = START_VIEW_REORDER_DELAY;
-        final Interpolator hideInterpolator = new DecelerateInterpolator(2);
-        final Interpolator showInterpolator = new OvershootInterpolator(0.8f);
-
-        currentPage = getCurrentCellLayout();
-        for (int x = 0; x < mGridCountX; x++) {
-            for (int y = 0; y < mGridCountY; y++) {
-                final BubbleTextView v = (BubbleTextView) currentPage.getChildAt(x, y);
-                if (v != null) {
-                    final ShortcutInfo info = (ShortcutInfo) v.getTag();
-                    final Runnable clearPending = new Runnable() {
-
-                        @Override
-                        public void run() {
-                            mPendingAnimations.remove(v);
-                            v.setScaleX(1);
-                            v.setScaleY(1);
-                        }
-                    };
-                    if (oldItems[x][y] == null) {
-                        v.setScaleX(0);
-                        v.setScaleY(0);
-                        v.animate().setDuration(SORT_ANIM_SHOW_DURATION)
-                            .setStartDelay(SORT_ANIM_HIDE_DURATION + delay)
-                            .scaleX(1).scaleY(1).setInterpolator(showInterpolator)
-                            .withEndAction(clearPending);
-                        mPendingAnimations.put(v, clearPending);
-                    } else {
-                        // Apply the old iconInfo so that there is no sudden change.
-                        v.applyFromShortcutInfo(oldItems[x][y], mIconCache, false);
-                        v.animate().setStartDelay(delay).setDuration(SORT_ANIM_HIDE_DURATION)
-                            .scaleX(0).scaleY(0)
-                            .setInterpolator(hideInterpolator)
-                            .withEndAction(new Runnable() {
-
-                                @Override
-                                public void run() {
-                                    // Apply the new iconInfo as part of the animation.
-                                    v.applyFromShortcutInfo(info, mIconCache, false);
-                                    v.animate().scaleX(1).scaleY(1)
-                                        .setDuration(SORT_ANIM_SHOW_DURATION).setStartDelay(0)
-                                        .setInterpolator(showInterpolator)
-                                        .withEndAction(clearPending);
-                                }
-                       });
-                       mPendingAnimations.put(v, new Runnable() {
-
-                           @Override
-                           public void run() {
-                               clearPending.run();
-                               v.applyFromShortcutInfo(info, mIconCache, false);
-                           }
-                        });
-                    }
-                    delay += delayAmount;
-                    delayAmount *= VIEW_REORDER_DELAY_FACTOR;
-                }
-            }
-        }
-
-        setIsSorted(true, true);
     }
 
     /**
@@ -295,7 +150,6 @@
      * @return list of items that could not be bound, probably because we hit the max size limit.
      */
     public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
-        mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
         ArrayList<View> icons = new ArrayList<View>();
         ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
 
@@ -317,20 +171,6 @@
     public int allocateRankForNewItem(ShortcutInfo info) {
         int rank = getItemCount();
         ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
-        if (ALLOW_ITEM_SORTING && mIsSorted) {
-            View tmp = new View(getContext());
-            tmp.setTag(info);
-            int index = Collections.binarySearch(views, tmp, new ViewComparator());
-            if (index < 0) {
-                rank = -index - 1;
-            } else {
-                // Item with same name already exists.
-                // We will just insert it before that item.
-                rank = index;
-            }
-
-        }
-
         views.add(rank, null);
         arrangeChildren(views, views.size(), false);
         setCurrentPage(rank / mMaxItemsPerPage);
@@ -363,7 +203,7 @@
     }
 
     @SuppressLint("InflateParams")
-    private View createNewView(ShortcutInfo item) {
+    public View createNewView(ShortcutInfo item) {
         final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
                 R.layout.folder_application, null, false);
         textView.applyFromShortcutInfo(item, mIconCache, false);
@@ -447,10 +287,6 @@
         int position = 0;
         int newX, newY, rank;
 
-        boolean isSorted = mIsSorted;
-
-        ViewComparator comparator = new ViewComparator();
-        View lastView = null;
         rank = 0;
         for (int i = 0; i < itemCount; i++) {
             View v = list.size() > i ? list.get(i) : null;
@@ -465,10 +301,6 @@
             }
 
             if (v != null) {
-                if (lastView != null) {
-                    isSorted &= comparator.compare(lastView, v) <= 0;
-                }
-
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
                 newX = position % mGridCountX;
                 newY = position / mGridCountX;
@@ -488,7 +320,6 @@
                         v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
             }
 
-            lastView = v;
             rank ++;
             position++;
         }
@@ -506,23 +337,10 @@
         setEnableOverscroll(getPageCount() > 1);
 
         // Update footer
-        if (ALLOW_ITEM_SORTING) {
-            setIsSorted(isSorted, saveChanges);
-            if (getPageCount() > 1) {
-                mPageIndicator.setVisibility(View.VISIBLE);
-                mSortButton.setVisibility(View.VISIBLE);
-                mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
-            } else {
-                mPageIndicator.setVisibility(View.GONE);
-                mSortButton.setVisibility(View.GONE);
-                mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
-            }
-        } else {
-            int indicatorVisibility = mPageIndicator.getVisibility();
-            mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
-            if (indicatorVisibility != mPageIndicator.getVisibility()) {
-                mFolder.updateFooterHeight();
-            }
+        int indicatorVisibility = mPageIndicator.getVisibility();
+        mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+        if (indicatorVisibility != mPageIndicator.getVisibility()) {
+            mFolder.updateFooterHeight();
         }
     }
 
@@ -559,7 +377,7 @@
     public int findNearestArea(int pixelX, int pixelY) {
         int pageIndex = getNextPage();
         CellLayout page = getPageAt(pageIndex);
-        page.findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
+        page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
         if (mFolder.isLayoutRtl()) {
             sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
         }
@@ -630,17 +448,6 @@
         if (mFolder != null) {
             mFolder.updateTextViewFocus();
         }
-        if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
-            post(new Runnable() {
-
-                @Override
-                public void run() {
-                    if (mSortOperationPending) {
-                        doSort();
-                    }
-                }
-            });
-        }
     }
 
     /**
@@ -829,14 +636,4 @@
             }
         }
     }
-
-    private static class ViewComparator implements Comparator<View> {
-        private final Collator mCollator = Collator.getInstance();
-
-        @Override
-        public int compare(View lhs, View rhs) {
-            return mCollator.compare( ((ShortcutInfo) lhs.getTag()).title.toString(),
-                    ((ShortcutInfo) rhs.getTag()).title.toString());
-        }
-    }
 }
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index e48640c..f1ff48d 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -21,7 +21,6 @@
 import android.provider.Settings;
 import android.util.AttributeSet;
 
-import com.android.launcher3.R;
 import com.android.launcher3.compat.UserHandleCompat;
 
 public class InfoDropTarget extends ButtonDropTarget {
@@ -66,9 +65,13 @@
 
     @Override
     protected boolean supportsDrop(DragSource source, Object info) {
-        return source.supportsAppInfoDropTarget() &&
-                Settings.Global.getInt(getContext().getContentResolver(),
-                        Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
+        return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
+    }
+
+    public static boolean supportsDrop(Context context, Object info) {
+        return (Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) &&
+                (info instanceof AppInfo || info instanceof PendingAddItemInfo);
     }
 
     @Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2084477..8c920f0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,8 +100,10 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetsContainerView;
 
 import java.io.DataInputStream;
@@ -302,7 +304,7 @@
 
     @Thunk static LocaleConfiguration sLocaleConfiguration = null;
 
-    private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+    private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
 
     private View.OnTouchListener mHapticFeedbackTouchListener;
 
@@ -2047,12 +2049,6 @@
 
         TextKeyListener.getInstance().release();
 
-        // Disconnect any of the callbacks and drawables associated with ItemInfos on the workspace
-        // to prevent leaking Launcher activities on orientation change.
-        if (mModel != null) {
-            mModel.unbindItemInfosAndClearQueuedBindRunnables();
-        }
-
         getContentResolver().unregisterContentObserver(mWidgetObserver);
         unregisterReceiver(mCloseSystemDialogsReceiver);
 
@@ -3892,7 +3888,7 @@
     /**
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindFolders(final HashMap<Long, FolderInfo> folders) {
+    public void bindFolders(final LongArrayMap<FolderInfo> folders) {
         Runnable r = new Runnable() {
             public void run() {
                 bindFolders(folders);
@@ -3901,8 +3897,7 @@
         if (waitUntilResume(r)) {
             return;
         }
-        sFolders.clear();
-        sFolders.putAll(folders);
+        sFolders = folders.clone();
     }
 
     /**
@@ -3950,7 +3945,7 @@
             pendingInfo.minSpanX = item.minSpanX;
             pendingInfo.minSpanY = item.minSpanY;
             Bundle options = null;
-            //        AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+                    WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
 
             int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
             boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index 8ba02ea..a60e160 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -1,16 +1,13 @@
 package com.android.launcher3;
 
 import android.annotation.TargetApi;
-import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.text.TextUtils;
 import android.util.SparseArray;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
@@ -68,18 +65,21 @@
         if (!(host.getTag() instanceof ItemInfo)) return;
         ItemInfo item = (ItemInfo) host.getTag();
 
+        if (DeleteDropTarget.supportsDrop(item)) {
+            info.addAction(mActions.get(REMOVE));
+        }
+        if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
+            info.addAction(mActions.get(UNINSTALL));
+        }
+        if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
+            info.addAction(mActions.get(INFO));
+        }
+
         if ((item instanceof ShortcutInfo)
                 || (item instanceof LauncherAppWidgetInfo)
                 || (item instanceof FolderInfo)) {
-            // Workspace shortcut / widget
-            info.addAction(mActions.get(REMOVE));
             info.addAction(mActions.get(MOVE));
-        } else if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
-            // App or Widget from customization tray
-            if (item instanceof AppInfo) {
-                info.addAction(mActions.get(UNINSTALL));
-            }
-            info.addAction(mActions.get(INFO));
+        } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
             info.addAction(mActions.get(ADD_TO_WORKSPACE));
         }
     }
@@ -94,10 +94,9 @@
     }
 
     public boolean performAction(View host, ItemInfo item, int action) {
-        Resources res = mLauncher.getResources();
         if (action == REMOVE) {
             if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
-                announceConfirmation(R.string.item_removed_from_workspace);
+                announceConfirmation(R.string.item_removed);
                 return true;
             }
             return false;
@@ -105,9 +104,7 @@
             InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
             return true;
         } else if (action == UNINSTALL) {
-            AppInfo info = (AppInfo) item;
-            mLauncher.startApplicationUninstallActivity(info.componentName, info.flags, info.user);
-            return true;
+            return UninstallDropTarget.startUninstallActivity(mLauncher, item);
         } else if (action == MOVE) {
             beginAccessibleDrag(host, item);
         } else if (action == ADD_TO_WORKSPACE) {
@@ -158,19 +155,31 @@
         return mDragInfo;
     }
 
-    public void handleAccessibleDrop(CellLayout targetContainer, Rect dropLocation,
+    /**
+     * @param clickedTarget the actual view that was clicked
+     * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
+     * as the actual drop location otherwise the views center is used.
+     */
+    public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
             String confirmation) {
         if (!isInAccessibleDrag()) return;
 
         int[] loc = new int[2];
-        loc[0] = dropLocation.centerX();
-        loc[1] = dropLocation.centerY();
+        if (dropLocation == null) {
+            loc[0] = clickedTarget.getWidth() / 2;
+            loc[1] = clickedTarget.getHeight() / 2;
+        } else {
+            loc[0] = dropLocation.centerX();
+            loc[1] = dropLocation.centerY();
+        }
 
-        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(targetContainer, loc);
+        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
         mLauncher.getDragController().completeAccessibleDrag(loc);
 
         endAccessibleDrag();
-        announceConfirmation(confirmation);
+        if (!TextUtils.isEmpty(confirmation)) {
+            announceConfirmation(confirmation);
+        }
     }
 
     public void beginAccessibleDrag(View item, ItemInfo info) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5a65cab..00afd98 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -28,7 +28,6 @@
 import android.content.Intent;
 import android.content.Intent.ShortcutIconResource;
 import android.content.IntentFilter;
-import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
@@ -61,6 +60,7 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.Thunk;
 
@@ -109,11 +109,6 @@
     @Thunk LoaderTask mLoaderTask;
     @Thunk boolean mIsLoaderTaskRunning;
 
-    // Specific runnable types that are run on the main thread deferred handler, this allows us to
-    // clear all queued binding runnables when the Launcher activity is destroyed.
-    private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
-    private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;
-
     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
 
     @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@@ -147,7 +142,7 @@
 
     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
     // LauncherModel to their ids
-    static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
+    static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();
 
     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
     //       created by LauncherModel that are directly on the home screen (however, no widgets or
@@ -159,7 +154,7 @@
         new ArrayList<LauncherAppWidgetInfo>();
 
     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
-    static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
+    static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();
 
     // sBgWorkspaceScreens is the ordered set of workspace screens.
     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
@@ -188,7 +183,7 @@
                               boolean forceAnimateIcons);
         public void bindScreens(ArrayList<Long> orderedScreenIds);
         public void bindAddScreens(ArrayList<Long> orderedScreenIds);
-        public void bindFolders(HashMap<Long,FolderInfo> folders);
+        public void bindFolders(LongArrayMap<FolderInfo> folders);
         public void finishBindingItems();
         public void bindAppWidget(LauncherAppWidgetInfo info);
         public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -256,9 +251,6 @@
     /** Runs the specified runnable immediately if called from the main thread, otherwise it is
      * posted on the main thread handler. */
     @Thunk void runOnMainThread(Runnable r) {
-        runOnMainThread(r, 0);
-    }
-    @Thunk void runOnMainThread(Runnable r, int type) {
         if (sWorkerThread.getThreadId() == Process.myTid()) {
             // If we are on the worker thread, post onto the main handler
             mHandler.post(r);
@@ -295,7 +287,7 @@
                         return;
                     }
 
-                    for (ItemInfo info : sBgItemsIdMap.values()) {
+                    for (ItemInfo info : sBgItemsIdMap) {
                         if (info instanceof ShortcutInfo) {
                             ShortcutInfo si = (ShortcutInfo) info;
                             ComponentName cn = si.getTargetComponent();
@@ -349,7 +341,7 @@
                     final ArrayList<ShortcutInfo> updates = new ArrayList<>();
                     final UserHandleCompat user = UserHandleCompat.myUserHandle();
 
-                    for (ItemInfo info : sBgItemsIdMap.values()) {
+                    for (ItemInfo info : sBgItemsIdMap) {
                         if (info instanceof ShortcutInfo) {
                             ShortcutInfo si = (ShortcutInfo) info;
                             ComponentName cn = si.getTargetComponent();
@@ -442,7 +434,7 @@
                 }
             }
         }
-        return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
+        return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
     }
 
     /**
@@ -679,7 +671,7 @@
         runOnWorkerThread(r);
     }
 
-    public void unbindItemInfosAndClearQueuedBindRunnables() {
+    private void unbindItemInfosAndClearQueuedBindRunnables() {
         if (sWorkerThread.getThreadId() == Process.myTid()) {
             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
                     "main thread");
@@ -689,8 +681,9 @@
         synchronized (mDeferredBindRunnables) {
             mDeferredBindRunnables.clear();
         }
-        // Remove any queued bind runnables
-        mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);
+
+        // Remove any queued UI runnables
+        mHandler.cancelAll();
         // Unbind all the workspace items
         unbindWorkspaceItemsOnMainThread();
     }
@@ -699,19 +692,15 @@
     void unbindWorkspaceItemsOnMainThread() {
         // Ensure that we don't use the same workspace items data structure on the main thread
         // by making a copy of workspace items first.
-        final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();
-        final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();
+        final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();
         synchronized (sBgLock) {
-            tmpWorkspaceItems.addAll(sBgWorkspaceItems);
-            tmpAppWidgets.addAll(sBgAppWidgets);
+            tmpItems.addAll(sBgWorkspaceItems);
+            tmpItems.addAll(sBgAppWidgets);
         }
         Runnable r = new Runnable() {
                 @Override
                 public void run() {
-                   for (ItemInfo item : tmpWorkspaceItems) {
-                       item.unbind();
-                   }
-                   for (ItemInfo item : tmpAppWidgets) {
+                   for (ItemInfo item : tmpItems) {
                        item.unbind();
                    }
                 }
@@ -1008,7 +997,7 @@
         }
 
         synchronized (sBgLock) {
-            for (ItemInfo item : sBgItemsIdMap.values()) {
+            for (ItemInfo item : sBgItemsIdMap) {
                 if (item instanceof ShortcutInfo) {
                     ShortcutInfo info = (ShortcutInfo) item;
                     if (intentWithPkg.equals(info.getIntent())
@@ -1024,7 +1013,7 @@
     /**
      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
      */
-    FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
+    FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {
         final ContentResolver cr = context.getContentResolver();
         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
                 "_id=? and (itemType=? or itemType=?)",
@@ -1144,7 +1133,7 @@
                 return cn.getPackageName().equals(pn) && info.user.equals(user);
             }
         };
-        return filterItemInfos(sBgItemsIdMap.values(), filter);
+        return filterItemInfos(sBgItemsIdMap, filter);
     }
 
     /**
@@ -1184,7 +1173,7 @@
                         switch (item.itemType) {
                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                                 sBgFolders.remove(item.id);
-                                for (ItemInfo info: sBgItemsIdMap.values()) {
+                                for (ItemInfo info: sBgItemsIdMap) {
                                     if (info.container == item.id) {
                                         // We are deleting a folder which still contains items that
                                         // think they are contained by that folder.
@@ -1297,6 +1286,9 @@
      */
     public void initialize(Callbacks callbacks) {
         synchronized (mLock) {
+            // Disconnect any of the callbacks and drawables associated with ItemInfos on the
+            // workspace to prevent leaking Launcher activities on orientation change.
+            unbindItemInfosAndClearQueuedBindRunnables();
             mCallbacks = new WeakReference<Callbacks>(callbacks);
         }
     }
@@ -1486,7 +1478,7 @@
                 mDeferredBindRunnables.clear();
             }
             for (final Runnable r : deferredBindRunnables) {
-                mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);
+                mHandler.post(r);
             }
         }
     }
@@ -1758,7 +1750,7 @@
         }
 
         // check & update map of what's occupied; used to discard overlapping/invalid items
-        private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {
+        private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {
             LauncherAppState app = LauncherAppState.getInstance();
             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
             final int countX = (int) grid.numColumns;
@@ -1906,7 +1898,7 @@
                 // +1 for the hotseat (it can be larger than the workspace)
                 // Load workspace in reverse order to ensure that latest items are loaded first (and
                 // before any earlier duplicates)
-                final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();
+                final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();
 
                 try {
                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -2445,7 +2437,7 @@
 
                 // Remove any empty screens
                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
-                for (ItemInfo item: sBgItemsIdMap.values()) {
+                for (ItemInfo item: sBgItemsIdMap) {
                     long screenId = item.screenId;
                     if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
                             unusedScreens.contains(screenId)) {
@@ -2470,14 +2462,13 @@
                     for (int y = 0; y < countY; y++) {
                         String line = "";
 
-                        Iterator<Long> iter = occupied.keySet().iterator();
-                        while (iter.hasNext()) {
-                            long screenId = iter.next();
+                        for (int i = 0; i < nScreens; i++) {
+                            long screenId = occupied.keyAt(i);
                             if (screenId > 0) {
                                 line += " | ";
                             }
+                            ItemInfo[][] screen = occupied.valueAt(i);
                             for (int x = 0; x < countX; x++) {
-                                ItemInfo[][] screen = occupied.get(screenId);
                                 if (x < screen.length && y < screen[x].length) {
                                     line += (screen[x][y] != null) ? "#" : ".";
                                 } else {
@@ -2568,14 +2559,17 @@
 
         /** Filters the set of folders which are on the specified screen. */
         private void filterCurrentFolders(long currentScreenId,
-                HashMap<Long, ItemInfo> itemsIdMap,
-                HashMap<Long, FolderInfo> folders,
-                HashMap<Long, FolderInfo> currentScreenFolders,
-                HashMap<Long, FolderInfo> otherScreenFolders) {
+                LongArrayMap<ItemInfo> itemsIdMap,
+                LongArrayMap<FolderInfo> folders,
+                LongArrayMap<FolderInfo> currentScreenFolders,
+                LongArrayMap<FolderInfo> otherScreenFolders) {
 
-            for (long id : folders.keySet()) {
+            int total = folders.size();
+            for (int i = 0; i < total; i++) {
+                long id = folders.keyAt(i);
+                FolderInfo folder = folders.valueAt(i);
+
                 ItemInfo info = itemsIdMap.get(id);
-                FolderInfo folder = folders.get(id);
                 if (info == null || folder == null) continue;
                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
                         info.screenId == currentScreenId) {
@@ -2619,13 +2613,13 @@
                     }
                 }
             };
-            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+            runOnMainThread(r);
         }
 
         private void bindWorkspaceItems(final Callbacks oldCallbacks,
                 final ArrayList<ItemInfo> workspaceItems,
                 final ArrayList<LauncherAppWidgetInfo> appWidgets,
-                final HashMap<Long, FolderInfo> folders,
+                final LongArrayMap<FolderInfo> folders,
                 ArrayList<Runnable> deferredBindRunnables) {
 
             final boolean postOnMainThread = (deferredBindRunnables != null);
@@ -2650,7 +2644,7 @@
                         deferredBindRunnables.add(r);
                     }
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
 
@@ -2669,7 +2663,7 @@
                         deferredBindRunnables.add(r);
                     }
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
 
@@ -2688,7 +2682,7 @@
                 if (postOnMainThread) {
                     deferredBindRunnables.add(r);
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
         }
@@ -2713,15 +2707,18 @@
             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
             ArrayList<LauncherAppWidgetInfo> appWidgets =
                     new ArrayList<LauncherAppWidgetInfo>();
-            HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();
-            HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();
             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();
+
+            final LongArrayMap<FolderInfo> folders;
+            final LongArrayMap<ItemInfo> itemsIdMap;
+
             synchronized (sBgLock) {
                 workspaceItems.addAll(sBgWorkspaceItems);
                 appWidgets.addAll(sBgAppWidgets);
-                folders.putAll(sBgFolders);
-                itemsIdMap.putAll(sBgItemsIdMap);
                 orderedScreenIds.addAll(sBgWorkspaceScreens);
+
+                folders = sBgFolders.clone();
+                itemsIdMap = sBgItemsIdMap.clone();
             }
 
             final boolean isLoadingSynchronously =
@@ -2747,8 +2744,8 @@
                     new ArrayList<LauncherAppWidgetInfo>();
             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
                     new ArrayList<LauncherAppWidgetInfo>();
-            HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();
-            HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();
+            LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();
+            LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();
 
             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
                     otherWorkspaceItems);
@@ -2768,7 +2765,7 @@
                     }
                 }
             };
-            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+            runOnMainThread(r);
 
             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
 
@@ -2784,7 +2781,7 @@
                         }
                     }
                 };
-                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                runOnMainThread(r);
             }
 
             // Load all the remaining pages (if we are loading synchronously, we want to defer this
@@ -2817,7 +2814,7 @@
                     mDeferredBindRunnables.add(r);
                 }
             } else {
-                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                runOnMainThread(r);
             }
         }
 
@@ -2888,8 +2885,6 @@
 
             // Clear the list of apps
             mBgAllAppsList.clear();
-            SharedPreferences prefs = mContext.getSharedPreferences(
-                    LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
             for (UserHandleCompat user : profiles) {
                 // Query for the set of apps
                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
@@ -2913,7 +2908,7 @@
                 if (!updatedPackages.isEmpty()) {
                     final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();
                     synchronized (sBgLock) {
-                        for (ItemInfo info : sBgItemsIdMap.values()) {
+                        for (ItemInfo info : sBgItemsIdMap) {
                             if (info instanceof ShortcutInfo && user.equals(info.user)
                                     && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                                 ShortcutInfo si = (ShortcutInfo) info;
@@ -3162,7 +3157,7 @@
 
                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));
                 synchronized (sBgLock) {
-                    for (ItemInfo info : sBgItemsIdMap.values()) {
+                    for (ItemInfo info : sBgItemsIdMap) {
                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
                             ShortcutInfo si = (ShortcutInfo) info;
                             boolean infoUpdated = false;
@@ -3538,7 +3533,7 @@
         return info;
     }
 
-    static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,
+    static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,
             ItemInfoFilter f) {
         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
         for (ItemInfo i : infos) {
@@ -3579,7 +3574,7 @@
                 }
             }
         };
-        return filterItemInfos(sBgItemsIdMap.values(), filter);
+        return filterItemInfos(sBgItemsIdMap, filter);
     }
 
     /**
@@ -3689,7 +3684,7 @@
      * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    @Thunk static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
+    @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {
         // See if a placeholder was created for us already
         FolderInfo folderInfo = folders.get(id);
         if (folderInfo == null) {
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index f91cfa0..9e005f2 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -258,7 +258,7 @@
             // Setup the reveal view animation
             int width = revealView.getMeasuredWidth();
             int height = revealView.getMeasuredHeight();
-            float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+            float revealRadius = (float) Math.hypot(width / 2, height / 2);
             revealView.setVisibility(View.VISIBLE);
             revealView.setAlpha(0f);
             revealView.setTranslationY(0f);
@@ -563,7 +563,7 @@
             if (fromView.getVisibility() == View.VISIBLE) {
                 int width = revealView.getMeasuredWidth();
                 int height = revealView.getMeasuredHeight();
-                float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+                float revealRadius = (float) Math.hypot(width / 2, height / 2);
                 revealView.setVisibility(View.VISIBLE);
                 revealView.setAlpha(1f);
                 revealView.setTranslationY(0);
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index af8bc75..44a76b7 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -180,6 +180,9 @@
         prepareStartAnimation(mDropTargetBar);
         mShowDropTargetBarAnim.start();
         hideSearchBar(true);
+        if (mQSBSearchBar != null) {
+            mQSBSearchBar.setVisibility(View.GONE);
+        }
     }
 
     /**
@@ -190,6 +193,9 @@
         prepareStartAnimation(mDropTargetBar);
         mShowDropTargetBarAnim.reverse();
         showSearchBar(true);
+        if (mQSBSearchBar != null) {
+            mQSBSearchBar.setVisibility(View.VISIBLE);
+        }
     }
 
     /*
@@ -228,4 +234,13 @@
             return null;
         }
     }
+
+    public void enableAccessibleDrag(boolean enable) {
+        if (mQSBSearchBar != null) {
+            mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
+        }
+        mInfoDropTarget.enableAccessibleDrag(enable);
+        mDeleteDropTarget.enableAccessibleDrag(enable);
+        mUninstallDropTarget.enableAccessibleDrag(enable);
+    }
 }
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 15b6176..56c8b39 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -76,14 +76,6 @@
         return null;
     }
 
-    public void addView(View child, int index, LayoutParams params, boolean inLayout) {
-        if (!inLayout) {
-            addView(child, index, params);
-        } else {
-            addViewInLayout(child, index, params, false);
-        }
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
         @SuppressWarnings("all") // suppress dead code warning
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4a7fffe..4c52d7e 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -33,9 +33,12 @@
 
     @Override
     protected boolean supportsDrop(DragSource source, Object info) {
+        return supportsDrop(getContext(), info);
+    }
+
+    public static boolean supportsDrop(Context context, Object info) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            UserManager userManager = (UserManager)
-                    getContext().getSystemService(Context.USER_SERVICE);
+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
             Bundle restrictions = userManager.getUserRestrictions();
             if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
                     || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
@@ -78,8 +81,7 @@
     void completeDrop(final DragObject d) {
         final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
         final UserHandleCompat user = ((ItemInfo) d.dragInfo).user;
-        if (mLauncher.startApplicationUninstallActivity(
-                componentInfo.first, componentInfo.second, user)) {
+        if (startUninstallActivity(mLauncher, d.dragInfo)) {
 
             final Runnable checkIfUninstallWasSuccess = new Runnable() {
                 @Override
@@ -96,6 +98,13 @@
         }
     }
 
+    public static boolean startUninstallActivity(Launcher launcher, Object info) {
+        final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
+        final UserHandleCompat user = ((ItemInfo) info).user;
+        return launcher.startApplicationUninstallActivity(
+                componentInfo.first, componentInfo.second, user);
+    }
+
     @Thunk void sendUninstallResult(DragSource target, boolean result) {
         if (target instanceof UninstallSource) {
             ((UninstallSource) target).onUninstallActivityReturned(result);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 22677c8..2dbf078 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -583,4 +583,37 @@
             return lhs.rank - rhs.rank;
         }
     };
+
+    /**
+     * Find the first vacant cell, if there is one.
+     *
+     * @param vacant Holds the x and y coordinate of the vacant cell
+     * @param spanX Horizontal cell span.
+     * @param spanY Vertical cell span.
+     *
+     * @return true if a vacant cell was found
+     */
+    public static boolean findVacantCell(int[] vacant, int spanX, int spanY,
+            int xCount, int yCount, boolean[][] occupied) {
+
+        for (int y = 0; (y + spanY) <= yCount; y++) {
+            for (int x = 0; (x + spanX) <= xCount; x++) {
+                boolean available = !occupied[x][y];
+                out:            for (int i = x; i < x + spanX; i++) {
+                    for (int j = y; j < y + spanY; j++) {
+                        available = available && !occupied[i][j];
+                        if (!available) break out;
+                    }
+                }
+
+                if (available) {
+                    vacant[0] = x;
+                    vacant[1] = y;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index abb8489..2efd207 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -63,6 +63,7 @@
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.UninstallDropTarget.UninstallSource;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperUtils;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -71,7 +72,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -120,7 +120,7 @@
     final static long EXTRA_EMPTY_SCREEN_ID = -201;
     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
 
-    @Thunk HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
+    @Thunk LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>();
     @Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>();
 
     @Thunk Runnable mRemoveEmptyScreenRunnable;
@@ -834,12 +834,9 @@
     }
 
     public long getIdForScreen(CellLayout layout) {
-        Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
-        while (iter.hasNext()) {
-            long id = iter.next();
-            if (mWorkspaceScreens.get(id) == layout) {
-                return id;
-            }
+        int index = mWorkspaceScreens.indexOfValue(layout);
+        if (index != -1) {
+            return mWorkspaceScreens.keyAt(index);
         }
         return -1;
     }
@@ -874,8 +871,10 @@
 
         int currentPage = getNextPage();
         ArrayList<Long> removeScreens = new ArrayList<Long>();
-        for (Long id: mWorkspaceScreens.keySet()) {
-            CellLayout cl = mWorkspaceScreens.get(id);
+        int total = mWorkspaceScreens.size();
+        for (int i = 0; i < total; i++) {
+            long id = mWorkspaceScreens.keyAt(i);
+            CellLayout cl = mWorkspaceScreens.valueAt(i);
             if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
                 removeScreens.add(id);
             }
@@ -1615,6 +1614,7 @@
             // Reset our click listener
             setOnClickListener(mLauncher);
         }
+        mLauncher.getSearchBar().enableAccessibleDrag(enable);
         mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
     }
 
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/LongArrayMap.java
new file mode 100644
index 0000000..e3c96cd
--- /dev/null
+++ b/src/com/android/launcher3/util/LongArrayMap.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.util;
+
+import android.util.LongSparseArray;
+
+import java.util.Iterator;
+
+/**
+ * Extension of {@link LongSparseArray} with some utility methods.
+ */
+public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
+
+    public boolean containsKey(long key) {
+        return indexOfKey(key) >= 0;
+    }
+
+    public boolean isEmpty() {
+        return size() <= 0;
+    }
+
+    @Override
+    public LongArrayMap<E> clone() {
+        return (LongArrayMap<E>) super.clone();
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return new ValueIterator();
+    }
+
+    private class ValueIterator implements Iterator<E> {
+
+        private int mNextIndex = 0;
+
+        @Override
+        public boolean hasNext() {
+            return mNextIndex < size();
+        }
+
+        @Override
+        public E next() {
+            return valueAt(mNextIndex ++);
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 1ae75c3..0bc7333 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -24,8 +24,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
 import android.widget.ImageView;
@@ -43,7 +41,7 @@
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 
 /**
- * The linear layout used strictly for the widget tray.
+ * Represents the individual cell of the widget inside the widget tray.
  */
 public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
 
@@ -53,14 +51,12 @@
     private static final int FADE_IN_DURATION_MS = 70;
     private int mPresetPreviewSize;
 
-    private static WidgetCell sShortpressTarget = null;
-
+    private ImageView mWidgetImage;
+    private TextView mWidgetName;
+    private TextView mWidgetDims;
     private final Rect mOriginalImagePadding = new Rect();
 
     private String mDimensionsFormatString;
-    private CheckForShortPress mPendingCheckForShortPress = null;
-    private ShortPressListener mShortPressListener = null;
-    private boolean mShortPressTriggered = false;
     private boolean mIsAppWidget;
     private Object mInfo;
 
@@ -92,57 +88,27 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-        mOriginalImagePadding.left = image.getPaddingLeft();
-        mOriginalImagePadding.top = image.getPaddingTop();
-        mOriginalImagePadding.right = image.getPaddingRight();
-        mOriginalImagePadding.bottom = image.getPaddingBottom();
+        mWidgetImage = (ImageView) findViewById(R.id.widget_preview);
+        mOriginalImagePadding.left = mWidgetImage.getPaddingLeft();
+        mOriginalImagePadding.top = mWidgetImage.getPaddingTop();
+        mOriginalImagePadding.right = mWidgetImage.getPaddingRight();
+        mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom();
 
         // Ensure we are using the right text size
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        TextView name = (TextView) findViewById(R.id.widget_name);
-        if (name != null) {
-            name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
-        }
-        TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (DEBUG) {
-            Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
-        }
-        super.onDetachedFromWindow();
-        deletePreview(false);
+        DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+        mWidgetName = ((TextView) findViewById(R.id.widget_name));
+        mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
     }
 
     public void reset() {
-        ImageView image = (ImageView) findViewById(R.id.widget_preview);
-        final TextView name = (TextView) findViewById(R.id.widget_name);
-        final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        image.setImageDrawable(null);
-        name.setText(null);
-        dims.setText(null);
+        mWidgetImage.setImageDrawable(null);
+        mWidgetName.setText(null);
+        mWidgetDims.setText(null);
     }
 
-    public void deletePreview(boolean recycleImage) {
-        if (recycleImage) {
-            final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-            if (image != null) {
-                image.setImageDrawable(null);
-            }
-        }
-
-        if (mActiveRequest != null) {
-            mActiveRequest.cancel(recycleImage);
-            mActiveRequest = null;
-        }
-    }
-
+    /**
+     * Apply the widget provider info to the view.
+     */
     public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info,
             int maxWidth, WidgetPreviewLoader loader) {
         LauncherAppState app = LauncherAppState.getInstance();
@@ -150,37 +116,41 @@
 
         mIsAppWidget = true;
         mInfo = info;
-        final ImageView image = (ImageView) findViewById(R.id.widget_preview);
         if (maxWidth > -1) {
-            image.setMaxWidth(maxWidth);
+            mWidgetImage.setMaxWidth(maxWidth);
         }
-        final TextView name = (TextView) findViewById(R.id.widget_name);
-        name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
-        final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            int hSpan = Math.min(info.spanX, (int) grid.numColumns);
-            int vSpan = Math.min(info.spanY, (int) grid.numRows);
-            dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
-        }
+        // TODO(hyunyoungs): setup a cache for these labels.
+        mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
+        int hSpan = Math.min(info.spanX, (int) grid.numColumns);
+        int vSpan = Math.min(info.spanY, (int) grid.numRows);
+        mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
         mWidgetPreviewLoader = loader;
     }
 
+    /**
+     * Apply the resolve info to the view.
+     */
     public void applyFromResolveInfo(
             PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
         mIsAppWidget = false;
         mInfo = info;
         CharSequence label = info.loadLabel(pm);
-        final TextView name = (TextView) findViewById(R.id.widget_name);
-        name.setText(label);
-        final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            dims.setText(String.format(mDimensionsFormatString, 1, 1));
-        }
+        mWidgetName.setText(label);
+        mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1));
         mWidgetPreviewLoader = loader;
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        deletePreview(false);
+
+        if (DEBUG) {
+            Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
+        }
+    }
+
     public int[] getPreviewSize() {
-        final ImageView i = (ImageView) findViewById(R.id.widget_preview);
         int[] maxSize = new int[2];
         maxSize[0] = mPresetPreviewSize;
         maxSize[1] = mPresetPreviewSize;
@@ -189,110 +159,28 @@
 
     public void applyPreview(Bitmap bitmap) {
         FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
-        final WidgetImageView image =
-            (WidgetImageView) findViewById(R.id.widget_preview);
         if (DEBUG) {
             Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s",
                     getTagToString(), preview));
         }
         if (preview != null) {
-            image.mAllowRequestLayout = false;
-            image.setImageDrawable(preview);
+            mWidgetImage.setImageDrawable(preview);
             if (mIsAppWidget) {
                 // center horizontally
                 int[] imageSize = getPreviewSize();
                 int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
-                image.setPadding(mOriginalImagePadding.left + centerAmount,
+                mWidgetImage.setPadding(mOriginalImagePadding.left + centerAmount,
                         mOriginalImagePadding.top,
                         mOriginalImagePadding.right,
                         mOriginalImagePadding.bottom);
             }
-            image.setAlpha(0f);
-            image.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
-            image.mAllowRequestLayout = true;
-            image.requestLayout();
+            mWidgetImage.setAlpha(0f);
+            mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+            // TODO(hyunyoungs): figure out why this has to be called explicitly.
+            mWidgetImage.requestLayout();
         }
     }
 
-    void setShortPressListener(ShortPressListener listener) {
-        mShortPressListener = listener;
-    }
-
-    interface ShortPressListener {
-        void onShortPress(View v);
-        void cleanUpShortPress(View v);
-    }
-
-    class CheckForShortPress implements Runnable {
-        public void run() {
-            if (sShortpressTarget != null) return;
-            if (mShortPressListener != null) {
-                mShortPressListener.onShortPress(WidgetCell.this);
-                sShortpressTarget = WidgetCell.this;
-            }
-            mShortPressTriggered = true;
-        }
-    }
-
-    private void checkForShortPress() {
-        if (sShortpressTarget != null) return;
-        if (mPendingCheckForShortPress == null) {
-            mPendingCheckForShortPress = new CheckForShortPress();
-        }
-        postDelayed(mPendingCheckForShortPress, 120);
-    }
-
-    /**
-     * Remove the longpress detection timer.
-     */
-    private void removeShortPressCallback() {
-        if (mPendingCheckForShortPress != null) {
-          removeCallbacks(mPendingCheckForShortPress);
-        }
-    }
-
-    private void cleanUpShortPress() {
-        removeShortPressCallback();
-        if (mShortPressTriggered) {
-            if (mShortPressListener != null) {
-                mShortPressListener.cleanUpShortPress(WidgetCell.this);
-            }
-            mShortPressTriggered = false;
-        }
-    }
-
-    static void resetShortPressTarget() {
-        sShortpressTarget = null;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        super.onTouchEvent(event);
-
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_UP:
-                cleanUpShortPress();
-                break;
-            case MotionEvent.ACTION_DOWN:
-                checkForShortPress();
-                break;
-            case MotionEvent.ACTION_CANCEL:
-                cleanUpShortPress();
-                break;
-            case MotionEvent.ACTION_MOVE:
-                break;
-        }
-
-        // We eat up the touch events here, since the PagedView (which uses the same swiping
-        // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
-        // the user is scrolling between pages.  This means that if the pages themselves don't
-        // handle touch events, it gets forwarded up to PagedView itself, and it's own
-        // onTouchEvent() handling will prevent further intercept touch events from being called
-        // (it's the same view in that case).  This is not ideal, but to prevent more changes,
-        // we just always mark the touch event as handled.
-        return true;
-    }
-
     public void ensurePreview() {
         if (mActiveRequest != null) {
             return;
@@ -331,6 +219,16 @@
         return Math.min(size[0], info.spanX * cellWidth);
     }
 
+
+    private void deletePreview(boolean recycleImage) {
+        mWidgetImage.setImageDrawable(null);
+
+        if (mActiveRequest != null) {
+            mActiveRequest.cancel(recycleImage);
+            mActiveRequest = null;
+        }
+    }
+
     /**
      * Helper method to get the string info of the tag.
      */
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
new file mode 100644
index 0000000..d654550
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -0,0 +1,197 @@
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+public class WidgetHostViewLoader {
+
+    private static final boolean DEBUG = false;
+    private static final String TAG = "WidgetHostViewLoader";
+
+    /* constants used for widget loading state. */
+    private static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
+    private static final int WIDGET_PRELOAD_PENDING = 0;
+    private static final int WIDGET_BOUND = 1;
+    private static final int WIDGET_INFLATED = 2;
+
+    int mState = WIDGET_NO_CLEANUP_REQUIRED;
+
+    /* Runnables to handle inflation and binding. */
+    private Runnable mInflateWidgetRunnable = null;
+    private Runnable mBindWidgetRunnable = null;
+
+    /* Id of the widget being handled. */
+    int mWidgetLoadingId = -1;
+    PendingAddWidgetInfo mCreateWidgetInfo = null;
+
+    // TODO: technically, this class should not have to know the existence of the launcher.
+    private Launcher mLauncher;
+    private Handler mHandler;
+
+    public WidgetHostViewLoader(Launcher launcher) {
+        mLauncher = launcher;
+        mHandler = new Handler();
+    }
+
+    /**
+     * Start loading the widget.
+     */
+    public void load(View v) {
+        if (mCreateWidgetInfo != null) {
+            // Just in case the cleanup process wasn't properly executed.
+            finish(false);
+        }
+        boolean status = false;
+        if (v.getTag() instanceof PendingAddWidgetInfo) {
+            mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
+            status = preloadWidget(v, mCreateWidgetInfo);
+        }
+        if (DEBUG) {
+            Log.d(TAG, String.format("load started on [state=%d, status=%s]", mState, status));
+        }
+    }
+
+
+    /**
+     * Clean up according to what the last known state was.
+     * @param widgetIdUsed   {@code true} if the widgetId was consumed which can happen only
+     *                       when view is fully inflated
+     */
+    public void finish(boolean widgetIdUsed) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("cancel on state [%d] widgetId=[%d]",
+                    mState, mWidgetLoadingId));
+        }
+
+        // If the widget was not added, we may need to do further cleanup.
+        PendingAddWidgetInfo info = mCreateWidgetInfo;
+        mCreateWidgetInfo = null;
+
+        if (mState == WIDGET_PRELOAD_PENDING) {
+            // We never did any preloading, so just remove pending callbacks to do so
+            mHandler.removeCallbacks(mBindWidgetRunnable);
+            mHandler.removeCallbacks(mInflateWidgetRunnable);
+        } else if (mState == WIDGET_BOUND) {
+             // Delete the widget id which was allocated
+            if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+                mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+            }
+
+            // We never got around to inflating the widget, so remove the callback to do so.
+            mHandler.removeCallbacks(mInflateWidgetRunnable);
+        } else if (mState == WIDGET_INFLATED && !widgetIdUsed) {
+            // Delete the widget id which was allocated
+            if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+                mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+            }
+
+            // The widget was inflated and added to the DragLayer -- remove it.
+            AppWidgetHostView widget = info.boundWidget;
+            mLauncher.getDragLayer().removeView(widget);
+        }
+        setState(WIDGET_NO_CLEANUP_REQUIRED);
+        mWidgetLoadingId = -1;
+    }
+
+    private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) {
+        final LauncherAppWidgetProviderInfo pInfo = info.info;
+
+        final Bundle options = pInfo.isCustomWidget ? null :
+                getDefaultOptionsForWidget(mLauncher, info);
+
+        // If there is a configuration activity, do not follow thru bound and inflate.
+        if (pInfo.configure != null) {
+            info.bindOptions = options;
+            return false;
+        }
+        setState(WIDGET_PRELOAD_PENDING);
+        mBindWidgetRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (pInfo.isCustomWidget) {
+                    setState(WIDGET_BOUND);
+                    return;
+                }
+
+                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+                if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
+                        mWidgetLoadingId, pInfo, options)) {
+                    setState(WIDGET_BOUND);
+                }
+            }
+        };
+        mHandler.post(mBindWidgetRunnable);
+
+        mInflateWidgetRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mState != WIDGET_BOUND) {
+                    return;
+                }
+                AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+                        (Context) mLauncher, mWidgetLoadingId, pInfo);
+                info.boundWidget = hostView;
+                setState(WIDGET_INFLATED);
+                hostView.setVisibility(View.INVISIBLE);
+                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
+
+                // We want the first widget layout to be the correct size. This will be important
+                // for width size reporting to the AppWidgetManager.
+                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
+                        unScaledSize[1]);
+                lp.x = lp.y = 0;
+                lp.customPosition = true;
+                hostView.setLayoutParams(lp);
+                mLauncher.getDragLayer().addView(hostView);
+                v.setTag(info);
+            }
+        };
+        mHandler.post(mInflateWidgetRunnable);
+        return true;
+    }
+
+    public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
+        Bundle options = null;
+        Rect rect = new Rect();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
+            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
+                    info.componentName, null);
+
+            float density = launcher.getResources().getDisplayMetrics().density;
+            int xPaddingDips = (int) ((padding.left + padding.right) / density);
+            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+
+            options = new Bundle();
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+                    rect.left - xPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+                    rect.top - yPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+                    rect.right - xPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+                    rect.bottom - yPaddingDips);
+        }
+        return options;
+    }
+
+    private void setState(int state) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("     state [%d -> %d]", mState, state));
+        }
+        mState = state;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 292a5de..27a3ea1 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -30,6 +30,7 @@
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.Toast;
 
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeleteDropTarget;
@@ -54,15 +55,17 @@
 /**
  * The widgets list view container.
  */
-public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
-        View.OnLongClickListener, DragSource{
+public class WidgetsContainerView extends FrameLayout implements Insettable,
+        View.OnLongClickListener, View.OnClickListener, DragSource{
 
-    private static final String TAG = "WidgetContainerView";
+    private static final String TAG = "WidgetsContainerView";
     private static final boolean DEBUG = false;
 
     /* {@link RecyclerView} will keep following # of views in cache, before recycling. */
     private static final int WIDGET_CACHE_SIZE = 2;
 
+    private static final int SPRING_MODE_DELAY_MS = 150;
+
     /* Global instances that are used inside this container. */
     private Launcher mLauncher;
     private DragController mDragController;
@@ -75,12 +78,13 @@
     private RecyclerView mView;
     private WidgetsListAdapter mAdapter;
 
-    /* Dragging related. */
-    private boolean mDraggingWidget = false;    // TODO(hyunyoungs): seems not needed? check!
-    private Point mLastTouchDownPos = new Point();
+    /* Touch handling related member variables. */
+    private Toast mWidgetInstructionToast;
 
     /* Rendering related. */
     private WidgetPreviewLoader mWidgetPreviewLoader;
+    private WidgetHostViewLoader mWidgetHostViewLoader;
+
     private Rect mPadding = new Rect();
 
     public WidgetsContainerView(Context context) {
@@ -95,8 +99,8 @@
         super(context, attrs, defStyleAttr);
         mLauncher = (Launcher) context;
         mDragController = mLauncher.getDragController();
-
-        mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
+        mWidgetHostViewLoader = new WidgetHostViewLoader(mLauncher);
+        mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
         mWidgets = new WidgetsModel(context, mAdapter);
         mAdapter.setWidgetsModel(mWidgets);
         mIconCache = (LauncherAppState.getInstance()).getIconCache();
@@ -147,11 +151,26 @@
     //
 
     @Override
+    public void onClick(View v) {
+        // When we have exited widget tray or are in transition, disregard clicks
+        if (!mLauncher.isWidgetsViewVisible()
+                || mLauncher.getWorkspace().isSwitchingState()
+                || !(v instanceof WidgetCell)) return;
+
+        // Let the user know that they have to long press to add a widget
+        if (mWidgetInstructionToast != null) {
+            mWidgetInstructionToast.cancel();
+        }
+        mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
+                Toast.LENGTH_SHORT);
+        mWidgetInstructionToast.show();
+    }
+
+    @Override
     public boolean onLongClick(View v) {
         if (DEBUG) {
             Log.d(TAG, String.format("onLonglick [v=%s]", v));
         }
-
         // Return early if this is not initiated from a touch
         if (!v.isInTouchMode()) return false;
         // When we have exited all apps or are in transition, disregard long clicks
@@ -161,7 +180,11 @@
         Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
         if (!mLauncher.isDraggingEnabled()) return false;
 
-        return beginDragging(v);
+        boolean status = beginDragging(v);
+        if (status) {
+            mWidgetHostViewLoader.load(v);
+        }
+        return status;
     }
 
     private boolean beginDragging(View v) {
@@ -174,7 +197,7 @@
         }
 
         // We delay entering spring-loaded mode slightly to make sure the UI
-        // thready is free of any work.
+        // thread is free of any work.
         postDelayed(new Runnable() {
             @Override
             public void run() {
@@ -184,13 +207,12 @@
                     mLauncher.enterSpringLoadedDragMode();
                 }
             }
-        }, 150);
+        }, SPRING_MODE_DELAY_MS);
 
         return true;
     }
 
     private boolean beginDraggingWidget(WidgetCell v) {
-        mDraggingWidget = true;
         // Get the widget preview as the drag representation
         ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
         PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
@@ -198,7 +220,6 @@
         // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
         // we abort the drag.
         if (image.getDrawable() == null) {
-            mDraggingWidget = false;
             return false;
         }
 
@@ -259,19 +280,6 @@
         return true;
     }
 
-    /*
-     * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
-     */
-    @Override
-    public boolean onTouch(View v, MotionEvent ev) {
-        Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
-        if (ev.getAction() == MotionEvent.ACTION_DOWN ||
-                ev.getAction() == MotionEvent.ACTION_MOVE) {
-            mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
-        }
-        return false;
-    }
-
     //
     // Drag related handling methods that implement {@link DragSource} interface.
     //
@@ -340,6 +348,10 @@
             }
             d.deferDragViewCleanupPostAnimation = false;
         }
+        //TODO(hyunyoungs): if drop fails, this call cleans up correctly.
+        // However, in rare corner case where drop succeeds but doesn't end up using the widget
+        // id created by the loader, this finish will leave dangling widget id.
+        mWidgetHostViewLoader.finish(success);
     }
 
     //
@@ -368,5 +380,4 @@
         }
         return mWidgetPreviewLoader;
     }
-
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index afeb2d3..f6ab21e 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -56,20 +56,16 @@
     private WidgetsModel mWidgetsModel;
     private WidgetPreviewLoader mWidgetPreviewLoader;
 
-    private View.OnTouchListener mTouchListener;
     private View.OnClickListener mIconClickListener;
     private View.OnLongClickListener mIconLongClickListener;
 
-
     public WidgetsListAdapter(Context context,
-            View.OnTouchListener touchListener,
             View.OnClickListener iconClickListener,
             View.OnLongClickListener iconLongClickListener,
             Launcher launcher) {
         mLayoutInflater = LayoutInflater.from(context);
         mContext = context;
 
-        mTouchListener = touchListener;
         mIconClickListener = iconClickListener;
         mIconLongClickListener = iconLongClickListener;
 
@@ -109,7 +105,6 @@
                 // set up touch.
                 widget.setOnClickListener(mIconClickListener);
                 widget.setOnLongClickListener(mIconLongClickListener);
-                widget.setOnTouchListener(mTouchListener);
                 row.addView(widget);
             }
         } else if (diff < 0) {