merge in jb-mr1-release history after reset to jb-mr1-dev
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
index 2070eb6..eb60054 100644
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -57,6 +57,7 @@
     private int mBottomTouchRegionAdjustment = 0;
 
     int[] mDirectionVector = new int[2];
+    int[] mLastDirectionVector = new int[2];
 
     final int SNAP_DURATION = 150;
     final int BACKGROUND_PADDING = 24;
@@ -293,17 +294,31 @@
         if (mLeftBorderActive || mRightBorderActive) {
             spanX += hSpanInc;
             cellX += cellXInc;
-            mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
+            if (hSpanDelta != 0) {
+                mDirectionVector[0] = mLeftBorderActive ? -1 : 1;
+            }
         }
 
         if (mTopBorderActive || mBottomBorderActive) {
             spanY += vSpanInc;
             cellY += cellYInc;
-            mDirectionVector[1] = mTopBorderActive ? -1 : 1;
+            if (vSpanDelta != 0) {
+                mDirectionVector[1] = mTopBorderActive ? -1 : 1;
+            }
         }
 
         if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return;
 
+        // We always want the final commit to match the feedback, so we make sure to use the
+        // last used direction vector when committing the resize / reorder.
+        if (onDismiss) {
+            mDirectionVector[0] = mLastDirectionVector[0];
+            mDirectionVector[1] = mLastDirectionVector[1];
+        } else {
+            mLastDirectionVector[0] = mDirectionVector[0];
+            mLastDirectionVector[1] = mDirectionVector[1];
+        }
+
         if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
                 mDirectionVector, onDismiss)) {
             lp.tmpCellX = cellX;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 4f4ef4e..d83fcac 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -1616,7 +1616,7 @@
     }
 
     // This method looks in the specified direction to see if there are additional views adjacent
-    // to the current set of views in the. If there is, then these views are added to the current
+    // to the current set of views. If there are, then these views are added to the current
     // set of views. This is performed iteratively, giving a cascading push behaviour.
     private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
             boolean[][] occupied, View dragView, ItemConfiguration currentState) {
@@ -1664,7 +1664,7 @@
                         (direction[1] < 0 && c.y == r0.top) ||
                         (direction[1] > 0 && c.y == r0.bottom - 1)) {
                     boolean pushed = false;
-                    // Since the bounding rect is a course description of the region (there can
+                    // Since the bounding rect is a coarse description of the region (there can
                     // be holes at the edge of the block), we need to check to verify that a solid
                     // piece is intersecting. This ensures that interlocking is possible.
                     for (int x = c.x; x < c.x + c.spanX; x++) {
@@ -1687,6 +1687,38 @@
         return found;
     }
 
+    private void completeSetOfViewsToMove(ArrayList<View> views, Rect boundingRect, int[] direction,
+            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
+        Rect r0 = new Rect(boundingRect);
+        int minRuns = 0;
+
+        // The first thing we do is to reduce the bounding rect to first or last row or column,
+        // depending on the direction. Then, we add any necessary views that are already contained
+        // by the bounding rect, but aren't in the list of intersecting views, and will be pushed
+        // by something already in the intersecting views.
+        if (direction[1] < 0) {
+            r0.set(r0.left, r0.bottom - 1, r0.right, r0.bottom);
+        } else if (direction[1] > 0) {
+            r0.set(r0.left, r0.top, r0.right, r0.top + 1);
+        } else if (direction[0] < 0) {
+            r0.set(r0.right - 1, r0.top, r0.right, r0.bottom);
+        } else if (direction[0] > 0) {
+            r0.set(r0.left, r0.top, r0.left + 1, r0.bottom);
+        }
+
+        minRuns = Math.max(Math.abs(boundingRect.width() - r0.width()),
+                Math.abs(boundingRect.height() - r0.height())) + 1;
+
+        // Here the first number of runs (minRuns) accounts for the the comment above, and
+        // further runs execute based on whether the intersecting views / bounding rect need
+        // to be expanded to include other views that will be pushed.
+        while (addViewInDirection(views, r0, direction, mTmpOccupied,
+                dragView, currentState) || minRuns > 0) {
+            minRuns--;
+        }
+        boundingRect.union(r0);
+    }
+
     private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
             int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
         if (views.size() == 0) return true;
@@ -1705,10 +1737,9 @@
 
         @SuppressWarnings("unchecked")
         ArrayList<View> dup = (ArrayList<View>) views.clone();
-        // We try and expand the group of views in the direction vector passed, based on
-        // whether they are physically adjacent, ie. based on "push mechanics".
-        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
-                currentState)) {
+        if (push) {
+            completeSetOfViewsToMove(dup, boundingRect, direction, mTmpOccupied, dragView,
+                    currentState);
         }
 
         // Mark the occupied state as false for the group of views we want to move.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index d827531..1e138f7 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -451,7 +451,9 @@
         if (sAppMarketIcon[coi] != null) {
             updateAppMarketIcon(sAppMarketIcon[coi]);
         }
-        mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
+        if (mSearchDropTargetBar != null) {
+            mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
+        }
     }
 
     private void checkForLocaleChange() {
@@ -1527,7 +1529,10 @@
             appSearchData = new Bundle();
             appSearchData.putString(Search.SOURCE, "launcher-search");
         }
-        Rect sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
+        Rect sourceBounds = new Rect();
+        if (mSearchDropTargetBar != null) {
+            sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
+        }
 
         startGlobalSearch(initialQuery, selectInitialQuery,
             appSearchData, sourceBounds);
@@ -2515,7 +2520,9 @@
                     }
 
                     // Hide the search bar
-                    mSearchDropTargetBar.hideSearchBar(false);
+                    if (mSearchDropTargetBar != null) {
+                        mSearchDropTargetBar.hideSearchBar(false);
+                    }
                 }
 
                 @Override
@@ -2591,7 +2598,9 @@
                 hideDockDivider();
 
                 // Hide the search bar
-                mSearchDropTargetBar.hideSearchBar(false);
+                if (mSearchDropTargetBar != null) {
+                    mSearchDropTargetBar.hideSearchBar(false);
+                }
             }
             dispatchOnLauncherTransitionPrepare(fromView, animated, false);
             dispatchOnLauncherTransitionStart(fromView, animated, false);
@@ -2743,7 +2752,9 @@
 
             // Show the search bar (only animate if we were showing the drop target bar in spring
             // loaded mode)
-            mSearchDropTargetBar.showSearchBar(wasInSpringLoadedMode);
+            if (mSearchDropTargetBar != null) {
+                mSearchDropTargetBar.showSearchBar(wasInSpringLoadedMode);
+            }
 
             // We only need to animate in the dock divider if we're going from spring loaded mode
             showDockDivider(animated && wasInSpringLoadedMode);
@@ -2846,7 +2857,11 @@
                 mDividerAnimator = LauncherAnimUtils.createAnimatorSet();
                 mDividerAnimator.playTogether(LauncherAnimUtils.ofFloat(mQsbDivider, "alpha", 1f),
                         LauncherAnimUtils.ofFloat(mDockDivider, "alpha", 1f));
-                mDividerAnimator.setDuration(mSearchDropTargetBar.getTransitionInDuration());
+                int duration = 0;
+                if (mSearchDropTargetBar != null) {
+                    duration = mSearchDropTargetBar.getTransitionInDuration();
+                }
+                mDividerAnimator.setDuration(duration);
                 mDividerAnimator.start();
             }
         }
@@ -2867,7 +2882,10 @@
         if (!LauncherApplication.isScreenLarge()) {
             if (animated) {
                 if (mHotseat.getAlpha() != 1f) {
-                    int duration = mSearchDropTargetBar.getTransitionInDuration();
+                    int duration = 0;
+                    if (mSearchDropTargetBar != null) {
+                        duration = mSearchDropTargetBar.getTransitionInDuration();
+                    }
                     mHotseat.animate().alpha(1f).setDuration(duration);
                 }
             } else {
@@ -2883,7 +2901,10 @@
         if (!LauncherApplication.isScreenLarge()) {
             if (animated) {
                 if (mHotseat.getAlpha() != 0f) {
-                    int duration = mSearchDropTargetBar.getTransitionOutDuration();
+                    int duration = 0;
+                    if (mSearchDropTargetBar != null) {
+                        duration = mSearchDropTargetBar.getTransitionOutDuration();
+                    }
                     mHotseat.animate().alpha(0f).setDuration(duration);
                 }
             } else {
@@ -3474,7 +3495,9 @@
     public void bindSearchablesChanged() {
         boolean searchVisible = updateGlobalSearchIcon();
         boolean voiceVisible = updateVoiceSearchIcon(searchVisible);
-        mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
+        if (mSearchDropTargetBar != null) {
+            mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
+        }
     }
 
     /**