merge in ics-release history after reset to master
diff --git a/src/com/android/launcher2/Alarm.java b/src/com/android/launcher2/Alarm.java
index 38ff367..7cd21c3 100644
--- a/src/com/android/launcher2/Alarm.java
+++ b/src/com/android/launcher2/Alarm.java
@@ -28,6 +28,7 @@
 
     private Handler mHandler;
     private OnAlarmListener mAlarmListener;
+    private boolean mAlarmPending = false;
 
     public Alarm() {
         mHandler = new Handler();
@@ -41,6 +42,7 @@
     // it's overwritten and only the new alarm setting is used
     public void setAlarm(long millisecondsInFuture) {
         long currentTime = System.currentTimeMillis();
+        mAlarmPending = true;
         mAlarmTriggerTime = currentTime + millisecondsInFuture;
         if (!mWaitingForCallback) {
             mHandler.postDelayed(this, mAlarmTriggerTime - currentTime);
@@ -50,6 +52,7 @@
 
     public void cancelAlarm() {
         mAlarmTriggerTime = 0;
+        mAlarmPending = false;
     }
 
     // this is called when our timer runs out
@@ -63,12 +66,17 @@
                 mHandler.postDelayed(this, Math.max(0, mAlarmTriggerTime - currentTime));
                 mWaitingForCallback = true;
             } else {
+                mAlarmPending = false;
                 if (mAlarmListener != null) {
                     mAlarmListener.onAlarm(this);
                 }
             }
         }
     }
+
+    public boolean alarmPending() {
+        return mAlarmPending;
+    }
 }
 
 interface OnAlarmListener {
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 555bef7..ac8c2ca 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -150,7 +150,7 @@
             final View view = getChildAt(i);
             view.setDrawingCacheEnabled(enabled);
             // Update the drawing caches
-            if (!view.isHardwareAccelerated()) {
+            if (!view.isHardwareAccelerated() && enabled) {
                 view.buildDrawingCache(true);
             }
         }
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 780d0ed..45730e0 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -91,7 +91,6 @@
     private int[] mTargetCell = new int[2];
     private int[] mPreviousTargetCell = new int[2];
     private int[] mEmptyCell = new int[2];
-    private int[] mTempXY = new int[2];
     private Alarm mReorderAlarm = new Alarm();
     private Alarm mOnExitAlarm = new Alarm();
     private TextView mFolderName;
@@ -99,10 +98,10 @@
     private Rect mHitRect = new Rect();
     private Rect mTempRect = new Rect();
     private boolean mFirstOpen = true;
-
-    // Internal variable to track whether the folder was destroyed due to only a single
-    // item remaining
-    private boolean mDestroyed = false;
+    private boolean mDragInProgress = false;
+    private boolean mDeleteFolderOnDropCompleted = false;
+    private boolean mSuppressFolderDeletion = false;
+    private boolean mItemAddedBackToSelfViaIcon = false;
 
     private boolean mIsEditingName = false;
     private InputMethodManager mInputMethodManager;
@@ -221,6 +220,8 @@
 
             mContent.removeView(mCurrentDragView);
             mInfo.remove(mCurrentDragInfo);
+            mDragInProgress = true;
+            mItemAddedBackToSelfViaIcon = false;
         }
         return true;
     }
@@ -296,12 +297,6 @@
         mContent.requestLayout();
     }
 
-    void onClose() {
-        DragLayer parent = (DragLayer) getParent();
-        parent.removeView(Folder.this);
-        clearFocus();
-    }
-
     void bind(FolderInfo info) {
         mInfo = info;
         ArrayList<ShortcutInfo> children = info.contents;
@@ -464,7 +459,6 @@
         oa.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                onClose();
                 onCloseComplete();
                 mState = STATE_SMALL;
             }
@@ -660,20 +654,38 @@
     }
 
     public void onDropCompleted(View target, DragObject d, boolean success) {
+        if (success) {
+            if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
+                replaceFolderWithFinalItem();
+            }
+        } else {
+            // The drag failed, we need to return the item to the folder
+            mFolderIcon.onDrop(d);
+
+            // We're going to trigger a "closeFolder" which may occur before this item has
+            // been added back to the folder -- this could cause the folder to be deleted
+            if (mOnExitAlarm.alarmPending()) {
+                mSuppressFolderDeletion = true;
+            }
+        }
+
+        if (target != this) {
+            if (mOnExitAlarm.alarmPending()) {
+                mOnExitAlarm.cancelAlarm();
+                completeDragExit();
+            }
+        }
+        mDeleteFolderOnDropCompleted = false;
+        mDragInProgress = false;
+        mItemAddedBackToSelfViaIcon = false;
         mCurrentDragInfo = null;
         mCurrentDragView = null;
         mSuppressOnAdd = false;
-        if (target != this) {
-            mOnExitAlarm.cancelAlarm();
-            completeDragExit();
-        }
+    }
 
-        if (!success) {
-            if (!mDestroyed) {
-                mFolderIcon.onDrop(d);
-            } else {
-                // TODO: if the folder was removed, recreate it
-            }
+    public void notifyDrop() {
+        if (mDragInProgress) {
+            mItemAddedBackToSelfViaIcon = true;
         }
     }
 
@@ -834,19 +846,27 @@
     }
 
     private void onCloseComplete() {
+        DragLayer parent = (DragLayer) getParent();
+        parent.removeView(Folder.this);
+        clearFocus();
+
         if (mRearrangeOnClose) {
             setupContentForNumItems(getItemCount());
             mRearrangeOnClose = false;
         }
         if (getItemCount() <= 1) {
-            replaceFolderWithFinalItem();
+            if (!mDragInProgress && !mSuppressFolderDeletion) {
+                replaceFolderWithFinalItem();
+            } else if (mDragInProgress) {
+                mDeleteFolderOnDropCompleted = true;
+            }
         }
+        mSuppressFolderDeletion = false;
     }
 
     private void replaceFolderWithFinalItem() {
         ItemInfo finalItem = null;
 
-        mDestroyed = true;
         if (getItemCount() == 1) {
             finalItem = mInfo.contents.get(0);
         }
@@ -885,7 +905,8 @@
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
-        // Dragged from self onto self
+        // Dragged from self onto self, currently this is the only path possible, however
+        // we keep this as a distinct code path.
         if (item == mCurrentDragInfo) {
             ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
@@ -906,6 +927,8 @@
 
     public void onAdd(ShortcutInfo item) {
         mItemsInvalidated = true;
+        // If the item was dropped onto this open folder, we have done the work associated
+        // with adding the item to the folder, as indicated by mSuppressOnAdd being set
         if (mSuppressOnAdd) return;
         if (!findAndSetEmptyCells(item)) {
             // The current layout is full, can we expand it?
@@ -919,6 +942,8 @@
 
     public void onRemove(ShortcutInfo item) {
         mItemsInvalidated = true;
+        // If this item is being dragged from this open folder, we have already handled
+        // the work associated with removing the item, so we don't have to do anything here.
         if (item == mCurrentDragInfo) return;
         View v = getViewForInfo(item);
         mContent.removeView(v);
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 8cf3fa7..b6b027a 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -329,8 +329,16 @@
         if (to == null) {
             to = new Rect();
             Workspace workspace = mLauncher.getWorkspace();
+            // Set cellLayout and this to it's final state to compute final animation locations
             workspace.setFinalTransitionTransform((CellLayout) getParent().getParent());
+            float scaleX = getScaleX();
+            float scaleY = getScaleY();
+            setScaleX(1.0f);
+            setScaleY(1.0f);
             scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to);
+            // Finished computing final animation locations, restore current state
+            setScaleX(scaleX);
+            setScaleY(scaleY);
             workspace.resetTransitionTransform((CellLayout) getParent().getParent());
         }
 
@@ -362,6 +370,7 @@
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
+        mFolder.notifyDrop();
         onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable);
     }
 
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 400c881..34cbf1a 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -1828,8 +1828,6 @@
             } else {
                 if (!(itemUnderLongClick instanceof Folder)) {
                     // User long pressed on an item
-                    mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
-                            HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     mWorkspace.startDrag(longClickCellInfo);
                 }
             }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index ecc5483..57d1760 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1289,6 +1289,10 @@
         for (int i = 0; i < screenCount; i++) {
             final CellLayout layout = (CellLayout) getChildAt(i);
             layout.setChildrenDrawnWithCacheEnabled(false);
+            // In software mode, we don't want the items to continue to be drawn into bitmaps
+            if (!isHardwareAccelerated()) {
+                layout.setChildrenDrawingCacheEnabled(false);
+            }
         }
     }