merge in jb-release history after reset to jb-dev
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index a701e69..a463d73 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -4,6 +4,9 @@
     <integer name="hotseat_cell_count">7</integer>
     <integer name="hotseat_all_apps_index">3</integer>
 
+<!-- DragController -->
+    <integer name="config_flingToDeleteMinVelocity">-1000</integer>
+
 <!-- Folders -->
     <!-- Folder max bounds and max number of items. Note: folder_max_count_x * folder_max_count_y
         >= folder_max_num_items. When these are set to -1, they are automatically determined. -->
diff --git a/res/values/config.xml b/res/values/config.xml
index bfd2bf5..a8d80fe 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -4,6 +4,9 @@
     <bool name="is_large_screen">false</bool>
     <bool name="allow_rotation">false</bool>
 
+<!-- DragController -->
+    <integer name="config_flingToDeleteMinVelocity">-1500</integer>
+
 <!-- AllApps/Customize/AppsCustomize -->
     <!-- The alpha of the AppsCustomize bg in spring loaded mode -->
     <integer name="config_appsCustomizeSpringLoadedBgAlpha">45</integer>
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index eea0dbb..71a4be2 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -299,8 +299,9 @@
     private Runnable mInflateWidgetRunnable = null;
     private Runnable mBindWidgetRunnable = null;
     static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
-    static final int WIDGET_BOUND = 0;
-    static final int WIDGET_INFLATED = 1;
+    static final int WIDGET_PRELOAD_PENDING = 0;
+    static final int WIDGET_BOUND = 1;
+    static final int WIDGET_INFLATED = 2;
     int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
     int mWidgetLoadingId = -1;
     PendingAddWidgetInfo mCreateWidgetInfo = null;
@@ -654,6 +655,7 @@
             return;
         }
 
+        mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
         mBindWidgetRunnable = new Runnable() {
             @Override
             public void run() {
@@ -716,17 +718,29 @@
             // If the widget was not added, we may need to do further cleanup.
             PendingAddWidgetInfo info = mCreateWidgetInfo;
             mCreateWidgetInfo = null;
-            // First step was to allocate a widget id, revert that.
-            if ((mWidgetCleanupState == WIDGET_BOUND || mWidgetCleanupState == WIDGET_INFLATED) &&
-                    mWidgetLoadingId != -1) {
-                Log.d(TAG, "    6557954 Cleaning up widget, delete widget id");
-                mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-            }
-            if (mWidgetCleanupState == WIDGET_BOUND) {
-                // We never actually inflated the widget, so remove the callback to do so.
+
+            if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
+                Log.d(TAG, "    6557954 Cleaning up widget, remove preload callbacks");
+                // We never did any preloading, so just remove pending callbacks to do so
+                removeCallbacks(mBindWidgetRunnable);
+                removeCallbacks(mInflateWidgetRunnable);
+            } else if (mWidgetCleanupState == WIDGET_BOUND) {
+                 // Delete the widget id which was allocated
+                if (mWidgetLoadingId != -1) {
+                    Log.d(TAG, "    6557954 Cleaning up widget, delete widget id");
+                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+                }
+
+                // We never got around to inflating the widget, so remove the callback to do so.
                 Log.d(TAG, "    6557954 Cleaning up widget, remove callbacks");
                 removeCallbacks(mInflateWidgetRunnable);
             } else if (mWidgetCleanupState == WIDGET_INFLATED) {
+                // Delete the widget id which was allocated
+                if (mWidgetLoadingId != -1) {
+                    Log.d(TAG, "    6557954 Cleaning up widget, delete widget id");
+                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+                }
+
                 // The widget was inflated and added to the DragLayer -- remove it.
                 Log.d(TAG, "    6557954 Cleaning up widget, remove inflated widget from draglayer");
                 AppWidgetHostView widget = info.boundWidget;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index a96b5b1..c028ff1 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -1704,6 +1704,102 @@
         markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
     }
 
+    // This method tries to find a reordering solution which satisfies the push mechanic by trying
+    // to push items in each of the cardinal directions, in an order based on the direction vector
+    // passed.
+    private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied,
+            int[] direction, View ignoreView, ItemConfiguration solution) {
+        if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) {
+            // If the direction vector has two non-zero components, we try pushing 
+            // separately in each of the components.
+            int temp = direction[1];
+            direction[1] = 0;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+            direction[1] = temp;
+            temp = direction[0];
+            direction[0] = 0;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+            // Revert the direction
+            direction[0] = temp;
+
+            // Now we try pushing in each component of the opposite direction
+            direction[0] *= -1;
+            direction[1] *= -1;
+            temp = direction[1];
+            direction[1] = 0;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+
+            direction[1] = temp;
+            temp = direction[0];
+            direction[0] = 0;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+            // revert the direction
+            direction[0] = temp;
+            direction[0] *= -1;
+            direction[1] *= -1;
+            
+        } else {
+            // If the direction vector has a single non-zero component, we push first in the
+            // direction of the vector
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+
+            // Then we try the opposite direction
+            direction[0] *= -1;
+            direction[1] *= -1;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+            // Switch the direction back
+            direction[0] *= -1;
+            direction[1] *= -1;
+            
+            // If we have failed to find a push solution with the above, then we try 
+            // to find a solution by pushing along the perpendicular axis.
+
+            // Swap the components
+            int temp = direction[1];
+            direction[1] = direction[0];
+            direction[0] = temp;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+
+            // Then we try the opposite direction
+            direction[0] *= -1;
+            direction[1] *= -1;
+            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
+                    ignoreView, solution)) {
+                return true;
+            }
+            // Switch the direction back
+            direction[0] *= -1;
+            direction[1] *= -1;
+
+            // Swap the components back
+            temp = direction[1];
+            direction[1] = direction[0];
+            direction[0] = temp;
+        }
+        return false;
+    }
+
     private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
             View ignoreView, ItemConfiguration solution) {
         // Return early if get invalid cell positions
@@ -1735,23 +1831,15 @@
             }
         }
 
-        // We try to move the intersecting views as a block using the push mechanic
-        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
+        // First we try to find a solution which respects the push mechanic. That is, 
+        // we try to find a solution such that no displaced item travels through another item
+        // without also displacing that item.
+        if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView,
                 solution)) {
             return true;
         }
-        // Try the opposite direction
-        direction[0] *= -1;
-        direction[1] *= -1;
-        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
-                solution)) {
-            return true;
-        }
-        // Switch the direction back
-        direction[0] *= -1;
-        direction[1] *= -1;
 
-        // Next we try moving the views as a block , but without requiring the push mechanic
+        // Next we try moving the views as a block, but without requiring the push mechanic.
         if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
                 solution)) {
             return true;
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 1edc2ab..949c035 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -39,7 +39,8 @@
 
 public class DeleteDropTarget extends ButtonDropTarget {
     private static int DELETE_ANIMATION_DURATION = 285;
-    private static int FLIND_DELETE_ANIMATION_DURATION = 350;
+    private static int FLING_DELETE_ANIMATION_DURATION = 350;
+    private static float FLING_TO_DELETE_FRICTION = 0.035f;
     private static int MODE_FLING_DELETE_TO_TRASH = 0;
     private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
 
@@ -311,22 +312,22 @@
      * progressively.
      */
     private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private static float FRICTION = 0.93f;
-
         private DragLayer mDragLayer;
         private PointF mVelocity;
         private Rect mFrom;
         private long mPrevTime;
         private boolean mHasOffsetForScale;
+        private float mFriction;
 
         private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
 
         public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
-                long startTime) {
+                long startTime, float friction) {
             mDragLayer = dragLayer;
             mVelocity = vel;
             mFrom = from;
             mPrevTime = startTime;
+            mFriction = 1f - (dragLayer.getResources().getDisplayMetrics().density * friction);
         }
 
         @Override
@@ -352,8 +353,8 @@
             dragView.setTranslationY(mFrom.top);
             dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
 
-            mVelocity.x *= FRICTION;
-            mVelocity.y *= FRICTION;
+            mVelocity.x *= mFriction;
+            mVelocity.y *= mFriction;
             mPrevTime = curTime;
         }
     };
@@ -363,7 +364,8 @@
         final Rect from = new Rect();
         dragLayer.getViewRectRelativeToSelf(d.dragView, from);
 
-        return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime);
+        return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime,
+                FLING_TO_DELETE_FRICTION);
     }
 
     public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
@@ -385,7 +387,7 @@
 
         final ViewConfiguration config = ViewConfiguration.get(mLauncher);
         final DragLayer dragLayer = mLauncher.getDragLayer();
-        final int duration = FLIND_DELETE_ANIMATION_DURATION;
+        final int duration = FLING_DELETE_ANIMATION_DURATION;
         final long startTime = AnimationUtils.currentAnimationTimeMillis();
 
         // NOTE: Because it takes time for the first frame of animation to actually be
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 1b0ccf5..84f1515 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -17,6 +17,7 @@
 package com.android.launcher2;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -62,7 +63,6 @@
     static final int SCROLL_RIGHT = 1;
 
     private static final float MAX_FLING_DEGREES = 35f;
-    private static final int FLING_TO_DELETE_THRESHOLD_Y_VELOCITY = -1500;
 
     private Launcher mLauncher;
     private Handler mHandler;
@@ -146,14 +146,16 @@
      * @param context The application's context.
      */
     public DragController(Launcher launcher) {
+        Resources r = launcher.getResources();
         mLauncher = launcher;
         mHandler = new Handler();
-        mScrollZone = launcher.getResources().getDimensionPixelSize(R.dimen.scroll_zone);
+        mScrollZone = r.getDimensionPixelSize(R.dimen.scroll_zone);
         mVelocityTracker = VelocityTracker.obtain();
-        mVibrator = (Vibrator)launcher.getSystemService(Context.VIBRATOR_SERVICE);
+        mVibrator = (Vibrator) launcher.getSystemService(Context.VIBRATOR_SERVICE);
 
-        float density = launcher.getResources().getDisplayMetrics().density;
-        mFlingToDeleteThresholdVelocity = (int) (FLING_TO_DELETE_THRESHOLD_Y_VELOCITY * density);
+        float density = r.getDisplayMetrics().density;
+        mFlingToDeleteThresholdVelocity =
+                (int) (r.getInteger(R.integer.config_flingToDeleteMinVelocity) * density);
     }
 
     public boolean dragging() {