Allow for NxM layout and in-place rotation of items on homescreen.

Currently, rotation is disabled as designs are still in flux, but the NxM grid is enabled (8x4).

Change-Id: I0026f88c674719e3d67de6d6d481d2d4cd606362
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 7ad5e49..b18fc1a 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+import java.util.Collections;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -25,20 +28,16 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.ViewGroup;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
-import android.view.ViewConfiguration;
 import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.TextView;
 import android.widget.ArrayAdapter;
 import android.widget.GridView;
+import android.widget.ImageButton;
 import android.widget.RelativeLayout;
-
-import java.util.ArrayList;
-import java.util.Collections;
+import android.widget.TextView;
 
 import com.android.launcher.R;
 
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 4a2dc49..9ef98fd 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -16,6 +16,10 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -29,11 +33,9 @@
 import android.renderscript.ProgramStore;
 import android.renderscript.ProgramVertex;
 import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
 import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
 import android.renderscript.Sampler;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
 import android.renderscript.SimpleMesh;
 import android.renderscript.Type;
 import android.util.AttributeSet;
@@ -48,10 +50,6 @@
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
 import com.android.launcher.R;
 
 public class AllApps3D extends RSSurfaceView
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 41aa6ca..3bacd87 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -16,17 +16,16 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import android.content.ComponentName;
-import android.content.Intent;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 
 /**
  * Stores the list of all applications for the all apps view.
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 5bb5037..7b00f4f 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -16,17 +16,14 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
 import android.util.Log;
 
-import java.util.ArrayList;
-
 /**
  * Represents an app in AllAppsView.
  */
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 73481c2..d69c56f 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,36 +16,44 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
+import android.app.WallpaperManager;
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.view.ContextMenu;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.app.WallpaperManager;
-
-import java.util.ArrayList;
+import android.view.animation.Animation;
+import android.view.animation.LayoutAnimationController;
 
 import com.android.launcher.R;
 
 public class CellLayout extends ViewGroup {
+    static final String TAG = "CellLayout";
+
     private boolean mPortrait;
 
     private int mCellWidth;
     private int mCellHeight;
-    
+
     private int mLongAxisStartPadding;
     private int mLongAxisEndPadding;
-
     private int mShortAxisStartPadding;
     private int mShortAxisEndPadding;
 
+    private int mLeftPadding;
+    private int mRightPadding;
+    private int mTopPadding;
+    private int mBottomPadding;
+
     private int mShortAxisCells;
     private int mLongAxisCells;
 
@@ -54,7 +62,7 @@
 
     private final Rect mRect = new Rect();
     private final CellInfo mCellInfo = new CellInfo();
-    
+
     int[] mCellXY = new int[2];
     boolean[][] mOccupied;
 
@@ -62,8 +70,8 @@
 
     private boolean mDirtyTag;
     private boolean mLastDownOnOccupiedCell = false;
-    
-    private final WallpaperManager mWallpaperManager;     
+
+    private final WallpaperManager mWallpaperManager;
 
     public CellLayout(Context context) {
         this(context, null);
@@ -79,16 +87,16 @@
 
         mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
         mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
-        
-        mLongAxisStartPadding = 
+
+        mLongAxisStartPadding =
             a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10);
-        mLongAxisEndPadding = 
+        mLongAxisEndPadding =
             a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10);
         mShortAxisStartPadding =
             a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10);
-        mShortAxisEndPadding = 
+        mShortAxisEndPadding =
             a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10);
-        
+
         mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);
         mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4);
 
@@ -96,14 +104,6 @@
 
         setAlwaysDrawnWithCacheEnabled(false);
 
-        if (mOccupied == null) {
-            if (mPortrait) {
-                mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
-            } else {
-                mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
-            }
-        }
-        
         mWallpaperManager = WallpaperManager.getInstance(getContext());
     }
 
@@ -132,14 +132,24 @@
         return mPortrait ? mLongAxisCells : mShortAxisCells;
     }
 
-    @Override
-    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+    // Takes canonical layout parameters
+    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
+        final LayoutParams lp = params;
+
         // Generate an id for each view, this assumes we have at most 256x256 cells
         // per workspace screen
-        final LayoutParams lp = (LayoutParams) params;
-        child.setId(((getId() & 0xFF) << 16) | (lp.cellX & 0xFF) << 8 | (lp.cellY & 0xFF));
+        if (lp.cellX >= 0 && lp.cellX <= getCountX() - 1 && lp.cellY >= 0 && lp.cellY <= getCountY() - 1) {
+            // If the horizontal or vertical span is set to -1, it is taken to
+            // mean that it spans the extent of the CellLayout
+            if (lp.cellHSpan < 0) lp.cellHSpan = getCountX();
+            if (lp.cellVSpan < 0) lp.cellVSpan = getCountY();
 
-        super.addView(child, index, params);
+            child.setId(childId);
+
+            addView(child, index, lp);
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -185,7 +195,7 @@
                 }
             }
         }
-            
+
         mLastDownOnOccupiedCell = found;
 
         if (!found) {
@@ -217,6 +227,7 @@
         setTag(cellInfo);
     }
 
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
@@ -256,8 +267,8 @@
         return info;
     }
 
-    private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y,
-            int xCount, int yCount, boolean[][] occupied) {
+    private static void findIntersectingVacantCells(CellInfo cellInfo, int x,
+            int y, int xCount, int yCount, boolean[][] occupied) {
 
         cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
         cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
@@ -392,21 +403,21 @@
 
         // Assume the caller will perform their own cell searching, otherwise we
         // risk causing an unnecessary rebuild after findCellForSpan()
-        
+
         return cellInfo;
     }
 
     /**
-     * Given a point, return the cell that strictly encloses that point 
+     * Given a point, return the cell that strictly encloses that point
      * @param x X coordinate of the point
      * @param y Y coordinate of the point
      * @param result Array of 2 ints to hold the x and y coordinate of the cell
      */
     void pointToCellExact(int x, int y, int[] result) {
         final boolean portrait = mPortrait;
-        
-        final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
-        final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
+
+        final int hStartPadding = getLeftPadding();
+        final int vStartPadding = getTopPadding();
 
         result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
         result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
@@ -419,7 +430,7 @@
         if (result[1] < 0) result[1] = 0;
         if (result[1] >= yAxis) result[1] = yAxis - 1;
     }
-    
+
     /**
      * Given a point, return the cell that most closely encloses that point
      * @param x X coordinate of the point
@@ -432,18 +443,15 @@
 
     /**
      * Given a cell coordinate, return the point that represents the upper left corner of that cell
-     * 
-     * @param cellX X coordinate of the cell 
+     *
+     * @param cellX X coordinate of the cell
      * @param cellY Y coordinate of the cell
-     * 
+     *
      * @param result Array of 2 ints to hold the x and y coordinate of the point
      */
     void cellToPoint(int cellX, int cellY, int[] result) {
-        final boolean portrait = mPortrait;
-        
-        final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
-        final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
+        final int hStartPadding = getLeftPadding();
+        final int vStartPadding = getTopPadding();
 
         result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
         result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
@@ -458,92 +466,117 @@
     }
 
     int getLeftPadding() {
-        return mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding;
+        return mLeftPadding;
     }
 
     int getTopPadding() {
-        return mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding;        
+        return mTopPadding;
     }
 
     int getRightPadding() {
-        return mPortrait ? mShortAxisEndPadding : mLongAxisEndPadding;
+        return mRightPadding;
     }
 
     int getBottomPadding() {
-        return mPortrait ? mLongAxisEndPadding : mShortAxisEndPadding;        
+        return mBottomPadding;
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // TODO: currently ignoring padding
-        
+
         int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
-        
+        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+
         int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
         int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
-        
+
         if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
             throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
         }
 
         final int shortAxisCells = mShortAxisCells;
         final int longAxisCells = mLongAxisCells;
-        final int longAxisStartPadding = mLongAxisStartPadding;
-        final int longAxisEndPadding = mLongAxisEndPadding;
-        final int shortAxisStartPadding = mShortAxisStartPadding;
-        final int shortAxisEndPadding = mShortAxisEndPadding;
         final int cellWidth = mCellWidth;
         final int cellHeight = mCellHeight;
 
-        mPortrait = heightSpecSize > widthSpecSize;
+        boolean portrait = heightSpecSize > widthSpecSize;
+        if (portrait != mPortrait || mOccupied == null) {
+            if (portrait) {
+                mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
+            } else {
+                mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
+            }
+        }
+        mPortrait = portrait;
 
         int numShortGaps = shortAxisCells - 1;
         int numLongGaps = longAxisCells - 1;
 
         if (mPortrait) {
-            int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding
-                    - (cellHeight * longAxisCells);
+            int vSpaceLeft = heightSpecSize - mLongAxisStartPadding
+                    - mLongAxisEndPadding - (cellHeight * longAxisCells);
             mHeightGap = vSpaceLeft / numLongGaps;
 
-            int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding
-                    - (cellWidth * shortAxisCells);
+            int hSpaceLeft = widthSpecSize - mShortAxisStartPadding
+                    - mShortAxisEndPadding - (cellWidth * shortAxisCells);
             if (numShortGaps > 0) {
                 mWidthGap = hSpaceLeft / numShortGaps;
             } else {
                 mWidthGap = 0;
             }
+
+            if (LauncherApplication.isInPlaceRotationEnabled()) {
+                mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap);
+                mLeftPadding = mRightPadding = (widthSpecSize - cellWidth
+                        * shortAxisCells - (shortAxisCells - 1) * mWidthGap) / 2;
+                mTopPadding = mBottomPadding = (heightSpecSize - cellHeight
+                        * longAxisCells - (longAxisCells - 1) * mHeightGap) / 2;
+            } else {
+                mLeftPadding = mShortAxisStartPadding;
+                mRightPadding = mShortAxisEndPadding;
+                mTopPadding = mLongAxisStartPadding;
+                mBottomPadding = mLongAxisEndPadding;
+            }
         } else {
-            int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding
-                    - (cellWidth * longAxisCells);
+            int hSpaceLeft = widthSpecSize - mLongAxisStartPadding
+                    - mLongAxisEndPadding - (cellWidth * longAxisCells);
             mWidthGap = hSpaceLeft / numLongGaps;
 
-            int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding
-                    - (cellHeight * shortAxisCells);
+            int vSpaceLeft = heightSpecSize - mShortAxisStartPadding
+                    - mShortAxisEndPadding - (cellHeight * shortAxisCells);
             if (numShortGaps > 0) {
                 mHeightGap = vSpaceLeft / numShortGaps;
             } else {
                 mHeightGap = 0;
             }
+
+            if (LauncherApplication.isScreenXLarge()) {
+                mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap);
+                mLeftPadding = mRightPadding = (widthSpecSize - cellWidth
+                        * longAxisCells - (longAxisCells - 1) * mWidthGap) / 2 ;
+                mTopPadding = mBottomPadding = (heightSpecSize - cellHeight
+                        * shortAxisCells - (shortAxisCells - 1) * mHeightGap) / 2;
+            } else {
+                mLeftPadding = mLongAxisStartPadding;
+                mRightPadding = mLongAxisEndPadding;
+                mTopPadding = mShortAxisStartPadding;
+                mBottomPadding = mShortAxisEndPadding;
+            }
         }
-        
         int count = getChildCount();
 
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
+                    mLeftPadding, mTopPadding);
 
-            if (mPortrait) {
-                lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding,
-                        longAxisStartPadding);
-            } else {
-                lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding,
-                        shortAxisStartPadding);
-            }
-            
-            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-            int childheightMeasureSpec =
-                    MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
+            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
+                    MeasureSpec.EXACTLY);
+            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+                    MeasureSpec.EXACTLY);
+
             child.measure(childWidthMeasureSpec, childheightMeasureSpec);
         }
 
@@ -596,7 +629,7 @@
     /**
      * 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.
@@ -608,12 +641,12 @@
      */
     int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
             CellInfo vacantCells, int[] recycle) {
-        
+
         // Keep track of best-scoring drop area
         final int[] bestXY = recycle != null ? recycle : new int[2];
         final int[] cellXY = mCellXY;
         double bestDistance = Double.MAX_VALUE;
-        
+
         // Bail early if vacant cells aren't valid
         if (!vacantCells.valid) {
             return null;
@@ -623,17 +656,17 @@
         final int size = vacantCells.vacantCells.size();
         for (int i = 0; i < size; i++) {
             final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i);
-            
+
             // Reject if vacant cell isn't our exact size
             if (cell.spanX != spanX || cell.spanY != spanY) {
                 continue;
             }
-            
+
             // Score is center distance from requested pixel
             cellToPoint(cell.cellX, cell.cellY, cellXY);
-            
-            double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) +
-                    Math.pow(cellXY[1] - pixelY, 2));
+
+            double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
+                    + Math.pow(cellXY[1] - pixelY, 2));
             if (distance <= bestDistance) {
                 bestDistance = distance;
                 bestXY[0] = cell.cellX;
@@ -641,25 +674,22 @@
             }
         }
 
-        // Return null if no suitable location found 
+        // Return null if no suitable location found
         if (bestDistance < Double.MAX_VALUE) {
             return bestXY;
         } else {
             return null;
         }
     }
-    
+
     /**
-     * Drop a child at the specified position
+     * Mark a child as having been dropped.
      *
      * @param child The child that is being dropped
-     * @param targetXY Destination area to move to
      */
-    void onDropChild(View child, int[] targetXY) {
+    void onDropChild(View child) {
         if (child != null) {
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            lp.cellX = targetXY[0];
-            lp.cellY = targetXY[1];
             lp.isDragging = false;
             lp.dropped = true;
             mDragRect.setEmpty();
@@ -678,7 +708,7 @@
 
     /**
      * Start dragging the specified child
-     * 
+     *
      * @param child The child that is being dragged
      */
     void onDragChild(View child) {
@@ -686,13 +716,13 @@
         lp.isDragging = true;
         mDragRect.setEmpty();
     }
-    
+
     /**
      * Drag a child over the specified position
-     * 
+     *
      * @param child The child that is being dropped
      * @param cellX The child's new x cell location
-     * @param cellY The child's new y cell location 
+     * @param cellY The child's new y cell location
      */
     void onDragOverChild(View child, int cellX, int cellY) {
         int[] cellXY = mCellXY;
@@ -701,39 +731,38 @@
         cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect);
         invalidate();
     }
-    
+
     /**
      * Computes a bounding rectangle for a range of cells
-     *  
+     *
      * @param cellX X coordinate of upper left corner expressed as a cell position
      * @param cellY Y coordinate of upper left corner expressed as a cell position
-     * @param cellHSpan Width in cells 
+     * @param cellHSpan Width in cells
      * @param cellVSpan Height in cells
      * @param dragRect Rectnagle into which to put the results
      */
     public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) {
-        final boolean portrait = mPortrait;
         final int cellWidth = mCellWidth;
         final int cellHeight = mCellHeight;
         final int widthGap = mWidthGap;
         final int heightGap = mHeightGap;
-        
-        final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
-        final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-        
+
+        final int hStartPadding = getLeftPadding();
+        final int vStartPadding = getTopPadding();
+
         int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
         int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
 
         int x = hStartPadding + cellX * (cellWidth + widthGap);
         int y = vStartPadding + cellY * (cellHeight + heightGap);
-        
+
         dragRect.set(x, y, x + width, y + height);
     }
-    
+
     /**
-     * Computes the required horizontal and vertical cell spans to always 
+     * Computes the required horizontal and vertical cell spans to always
      * fit the given rectangle.
-     *  
+     *
      * @param width Width in pixels
      * @param height Height in pixels
      */
@@ -758,7 +787,7 @@
      * @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) {
@@ -852,6 +881,17 @@
         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.
@@ -876,7 +916,7 @@
          */
         @ViewDebug.ExportedProperty
         public int cellVSpan;
-        
+
         /**
          * Is this item currently being dragged
          */
@@ -902,7 +942,15 @@
             cellHSpan = 1;
             cellVSpan = 1;
         }
-        
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+            this.cellX = source.cellX;
+            this.cellY = source.cellY;
+            this.cellHSpan = source.cellHSpan;
+            this.cellVSpan = source.cellVSpan;
+        }
+
         public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             this.cellX = cellX;
@@ -913,12 +961,12 @@
 
         public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
                 int hStartPadding, int vStartPadding) {
-            
+
             final int myCellHSpan = cellHSpan;
             final int myCellVSpan = cellVSpan;
             final int myCellX = cellX;
             final int myCellY = cellY;
-            
+
             width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
                     leftMargin - rightMargin;
             height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
@@ -927,14 +975,18 @@
             x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
             y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
         }
+
+        public String toString() {
+            return "(" + this.cellX + ", " + this.cellY + ")";
+        }
     }
 
     static final class CellInfo implements ContextMenu.ContextMenuInfo {
         /**
-         * See View.AttachInfo.InvalidateInfo for futher explanations about
-         * the recycling mechanism. In this case, we recycle the vacant cells
-         * instances because up to several hundreds can be instanciated when
-         * the user long presses an empty cell.
+         * See View.AttachInfo.InvalidateInfo for futher explanations about the
+         * recycling mechanism. In this case, we recycle the vacant cells
+         * instances because up to several hundreds can be instanciated when the
+         * user long presses an empty cell.
          */
         static final class VacantCell {
             int cellX;
@@ -945,7 +997,7 @@
             // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
             // like a reasonable compromise given the size of a VacantCell and
             // the fact that the user is not likely to touch an empty 4x4 grid
-            // very often 
+            // very often
             private static final int POOL_LIMIT = 100;
             private static final Object sLock = new Object();
 
@@ -980,8 +1032,8 @@
 
             @Override
             public String toString() {
-                return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
-                        ", spanY=" + spanY + "]";
+                return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX="
+                        + spanX + ", spanY=" + spanY + "]";
             }
         }
 
@@ -1004,7 +1056,9 @@
             final ArrayList<VacantCell> list = vacantCells;
             final int count = list.size();
 
-            for (int i = 0; i < count; i++) list.get(i).release();
+            for (int i = 0; i < count; i++) {
+                list.get(i).release();
+            }
 
             list.clear();
         }
@@ -1078,15 +1132,17 @@
                 }
             }
 
-            if (clear) clearVacantCells();
+            if (clear) {
+                clearVacantCells();
+            }
 
             return found;
         }
 
         @Override
         public String toString() {
-            return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX +
-                    ", y=" + cellY + "]";
+            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
+                    + ", x=" + cellX + ", y=" + cellY + "]";
         }
     }
 
@@ -1094,5 +1150,3 @@
         return mLastDownOnOccupiedCell;
     }
 }
-
-
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
index 7801642..0323c7f 100644
--- a/src/com/android/launcher2/DeferredHandler.java
+++ b/src/com/android/launcher2/DeferredHandler.java
@@ -16,13 +16,12 @@
 
 package com.android.launcher2;
 
+import java.util.LinkedList;
+
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
-import android.util.Log;
-
-import java.util.LinkedList;
 
 /**
  * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 248712e..bae592c 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -18,20 +18,15 @@
 package com.android.launcher2;
 
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.os.IBinder;
-import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.KeyEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 7ff8328..4d7c666 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -21,11 +21,11 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
-import android.widget.AbsListView;
-import android.widget.BaseAdapter;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 
diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 3fc568b..3638054 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -16,11 +16,11 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ContentResolver;
-import android.database.Cursor;
 import android.widget.Toast;
 
 import com.android.launcher.R;
@@ -86,38 +86,24 @@
     private static boolean findEmptyCell(Context context, int[] xy, int screen) {
         final int xCount = Launcher.NUMBER_CELLS_X;
         final int yCount = Launcher.NUMBER_CELLS_Y;
-
         boolean[][] occupied = new boolean[xCount][yCount];
 
-        final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
-            new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
-                    LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY },
-            LauncherSettings.Favorites.SCREEN + "=?",
-            new String[] { String.valueOf(screen) }, null);
-
-        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
-        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
-        try {
-            while (c.moveToNext()) {
-                int cellX = c.getInt(cellXIndex);
-                int cellY = c.getInt(cellYIndex);
-                int spanX = c.getInt(spanXIndex);
-                int spanY = c.getInt(spanYIndex);
-
+        ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
+        ItemInfo item = null;
+        int cellX, cellY, spanX, spanY;
+        for (int i = 0; i < items.size(); ++i) {
+            item = items.get(i);
+            if (item.screen == screen) {
+                cellX = item.cellX;
+                cellY = item.cellY;
+                spanX = item.spanX;
+                spanY = item.spanY;
                 for (int x = cellX; x < cellX + spanX && x < xCount; x++) {
                     for (int y = cellY; y < cellY + spanY && y < yCount; y++) {
                         occupied[x][y] = true;
                     }
                 }
             }
-        } catch (Exception e) {
-            return false;
-        } finally {
-            c.close();
         }
 
         return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index a96d9ae..dc45750 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -112,6 +112,11 @@
         }
     }
 
+    void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
+        values.put(LauncherSettings.Favorites.CELLX, cellX);
+        values.put(LauncherSettings.Favorites.CELLY, cellY);
+    }
+
     static byte[] flattenBitmap(Bitmap bitmap) {
         // Try go guesstimate how much space the icon will take when serialized
         // to avoid unnecessary allocations/copies during the write.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 07e8834..69911a7 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -16,8 +16,13 @@
 
 package com.android.launcher2;
 
-import com.android.common.Search;
-import com.android.launcher.R;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -36,6 +41,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -67,6 +73,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.view.View.OnLongClickListener;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.InputMethodManager;
@@ -77,13 +84,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import com.android.common.Search;
+import com.android.launcher.R;
 
 /**
  * Default launcher application.
@@ -211,10 +213,17 @@
     private Drawable[] mHotseatIcons = null;
     private CharSequence[] mHotseatLabels = null;
 
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        if (LauncherApplication.isInPlaceRotationEnabled()) {
+            // hide the status bar (temporary until we get the status bar design figured out)
+            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+        }
+
         LauncherApplication app = ((LauncherApplication)getApplication());
         mModel = app.setLauncher(this);
         mIconCache = app.getIconCache();
@@ -232,8 +241,8 @@
         loadHotseats();
         checkForLocaleChange();
         setWallpaperDimension();
-
         setContentView(R.layout.launcher);
+
         setupViews();
 
         registerContentObservers();
@@ -259,6 +268,19 @@
         registerReceiver(mCloseSystemDialogsReceiver, filter);
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // TODO Auto-generated method stub
+        super.onConfigurationChanged(newConfig);
+
+        if (LauncherApplication.isInPlaceRotationEnabled()) {
+            mModel.updateOrientation();
+            mWorkspace.refreshWorkspaceChildren();
+            mWorkspace.rotateCurrentScreensChildren();
+        }
+    }
+
+
     private void checkForLocaleChange() {
         final LocaleConfiguration localeConfiguration = new LocaleConfiguration();
         readConfiguration(this, localeConfiguration);
@@ -419,7 +441,7 @@
                 // note: if the user launches this without a default set, she
                 // will always be taken to the default URL above; this is
                 // unavoidable as we must specify a valid URL in order for the
-                // chooser to appear, and once the user selects something, that 
+                // chooser to appear, and once the user selects something, that
                 // URL is unavoidably sent to the chosen app.
             } else {
                 try {
@@ -429,7 +451,7 @@
                     // bogus; leave intent=null
                 }
             }
-            
+
             if (intent == null) {
                 mHotseats[i] = null;
                 mHotseatLabels[i] = getText(R.string.activity_not_found);
@@ -437,15 +459,15 @@
             }
 
             if (LOGD) {
-                Log.d(TAG, "loadHotseats: hotseat " + i 
-                    + " initial intent=[" 
+                Log.d(TAG, "loadHotseats: hotseat " + i
+                    + " initial intent=["
                     + intent.toUri(Intent.URI_INTENT_SCHEME)
                     + "]");
             }
 
             ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
             List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
-            if (LOGD) { 
+            if (LOGD) {
                 Log.d(TAG, "Best match for intent: " + bestMatch);
                 Log.d(TAG, "All matches: ");
                 for (ResolveInfo ri : allMatches) {
@@ -454,8 +476,8 @@
             }
             // did this resolve to a single app, or the resolver?
             if (allMatches.size() == 0 || bestMatch == null) {
-                // can't find any activity to handle this. let's leave the 
-                // intent as-is and let Launcher show a toast when it fails 
+                // can't find any activity to handle this. let's leave the
+                // intent as-is and let Launcher show a toast when it fails
                 // to launch.
                 mHotseats[i] = intent;
 
@@ -471,7 +493,7 @@
                         break;
                     }
                 }
-                
+
                 if (!found) {
                     if (LOGD) Log.d(TAG, "Multiple options, no default yet");
                     // the bestMatch is probably the ResolveActivity, meaning the
@@ -496,8 +518,8 @@
             }
 
             if (LOGD) {
-                Log.d(TAG, "loadHotseats: hotseat " + i 
-                    + " final intent=[" 
+                Log.d(TAG, "loadHotseats: hotseat " + i
+                    + " final intent=["
                     + ((mHotseats[i] == null)
                         ? "null"
                         : mHotseats[i].toUri(Intent.URI_INTENT_SCHEME))
@@ -712,7 +734,7 @@
         mAllAppsGrid.setDragController(dragController);
         ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window.
         // Manage focusability manually since this thing is always visible
-        ((View) mAllAppsGrid).setFocusable(false); 
+        ((View) mAllAppsGrid).setFocusable(false);
 
         mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
         final Workspace workspace = mWorkspace;
@@ -757,7 +779,7 @@
 
         deleteZone.setLauncher(this);
         deleteZone.setDragController(dragController);
-        int deleteZoneHandleId = isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster;
+        int deleteZoneHandleId = LauncherApplication.isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster;
         deleteZone.setHandle(findViewById(deleteZoneHandleId));
 
         dragController.setDragScoller(workspace);
@@ -805,7 +827,7 @@
             );
         }
     }
-    
+
     /**
      * Creates a view representing a shortcut.
      *
@@ -1048,7 +1070,7 @@
         unbindDesktopItems();
 
         getContentResolver().unregisterContentObserver(mWidgetObserver);
-        
+
         dismissPreview(mPreviousView);
         dismissPreview(mNextView);
 
@@ -1179,11 +1201,6 @@
         showAddDialog(mMenuAddInfo);
     }
 
-    boolean isScreenXLarge() {
-        int screenLayout = getResources().getConfiguration().screenLayout;
-        return (screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
-    }
-
     void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) {
         mAddItemCellInfo = cellInfo;
         int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
@@ -1518,7 +1535,7 @@
                     + "tag="+ tag + " intent=" + intent, e);
         }
     }
-    
+
     void startActivityForResultSafely(Intent intent, int requestCode) {
         try {
             startActivityForResult(intent, requestCode);
@@ -1563,7 +1580,7 @@
      *
      * @param folderInfo The FolderInfo describing the folder to open.
      */
-    private void openFolder(FolderInfo folderInfo) {
+    public void openFolder(FolderInfo folderInfo) {
         Folder openFolder;
 
         if (folderInfo instanceof UserFolderInfo) {
@@ -1580,7 +1597,8 @@
         openFolder.bind(folderInfo);
         folderInfo.opened = true;
 
-        mWorkspace.addInScreen(openFolder, folderInfo.screen, 0, 0, 4, 4);
+        mWorkspace.addInFullScreen(openFolder, folderInfo.screen);
+
         openFolder.onOpen();
     }
 
@@ -1678,9 +1696,9 @@
         final Workspace workspace = mWorkspace;
 
         CellLayout cell = ((CellLayout) workspace.getChildAt(start));
-        
+
         float max = workspace.getChildCount();
-        
+
         final Rect r = new Rect();
         resources.getDrawable(R.drawable.preview_background).getPadding(r);
         int extraW = (int) ((r.left + r.right) * max);
@@ -1731,7 +1749,7 @@
             preview.addView(image,
                     LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
 
-            bitmaps.add(bitmap);            
+            bitmaps.add(bitmap);
         }
 
         final PopupWindow p = new PopupWindow(this);
@@ -1752,7 +1770,7 @@
 
         anchor.setTag(p);
         anchor.setTag(R.id.workspace, preview);
-        anchor.setTag(R.id.icon, bitmaps);        
+        anchor.setTag(R.id.icon, bitmaps);
     }
 
     class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener {
@@ -1768,7 +1786,7 @@
         }
 
         public void run() {
-            dismissPreview(mAnchor);            
+            dismissPreview(mAnchor);
         }
 
         public void onFocusChange(View v, boolean hasFocus) {
@@ -1939,7 +1957,7 @@
 
         ((View) mAllAppsGrid).setFocusable(true);
         ((View) mAllAppsGrid).requestFocus();
-        
+
         // TODO: fade these two too
         mDeleteZone.setVisibility(View.GONE);
     }
@@ -2100,7 +2118,7 @@
         }
 
         public void onShow(DialogInterface dialog) {
-            mWaitingForResult = true;            
+            mWaitingForResult = true;
         }
     }
 
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index eda92d9..ca08378 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -20,6 +20,7 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.os.Handler;
 import dalvik.system.VMRuntime;
@@ -27,6 +28,8 @@
 public class LauncherApplication extends Application {
     public LauncherModel mModel;
     public IconCache mIconCache;
+    private static boolean sIsScreenXLarge;
+    private static final boolean ENABLE_ROTATION = false;
 
     @Override
     public void onCreate() {
@@ -36,6 +39,7 @@
 
         mIconCache = new IconCache(this);
         mModel = new LauncherModel(this, mIconCache);
+        sIsScreenXLarge = (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
 
         // Register intent receivers
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -89,4 +93,12 @@
     LauncherModel getModel() {
         return mModel;
     }
+
+    public static boolean isInPlaceRotationEnabled() {
+        return sIsScreenXLarge && ENABLE_ROTATION;
+    }
+
+    public static boolean isScreenXLarge() {
+        return sIsScreenXLarge;
+    }
 }
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index eb341f6..238fbdf 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -16,6 +16,15 @@
 
 package com.android.launcher2;
 
+import java.lang.ref.WeakReference;
+import java.net.URISyntaxException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
@@ -23,9 +32,9 @@
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.Intent;
 import android.content.Intent.ShortcutIconResource;
-import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
@@ -38,20 +47,10 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
-
-import java.lang.ref.WeakReference;
-import java.net.URISyntaxException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
+import android.util.Log;
 
 import com.android.launcher.R;
 
@@ -91,6 +90,8 @@
 
     private Bitmap mDefaultIcon;
 
+    private static LauncherModelOrientationHelper mModelOrientationHelper;
+
     public interface Callbacks {
         public int getCurrentWorkspaceScreen();
         public void startBinding();
@@ -109,6 +110,7 @@
         mApp = app;
         mAllAppsList = new AllAppsList(iconCache);
         mIconCache = iconCache;
+        mModelOrientationHelper = new LauncherModelOrientationHelper(mApp);
 
         mDefaultIcon = Utilities.createIconBitmap(
                 app.getPackageManager().getDefaultActivityIcon(), app);
@@ -141,11 +143,20 @@
         }
     }
 
+    static int getCurrentOrientation() {
+        return mModelOrientationHelper.getCurrentOrientation();
+    }
+
+    static int getPreviousOrientationRelativeToCurrent() {
+        return mModelOrientationHelper.getPreviousOrientationRelativeToCurrent();
+    }
+
     /**
      * Move an item in the DB to a new <container, screen, cellX, cellY>
      */
     static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
             int cellX, int cellY) {
+
         item.container = container;
         item.screen = screen;
         item.cellX = cellX;
@@ -153,10 +164,11 @@
 
         final ContentValues values = new ContentValues();
         final ContentResolver cr = context.getContentResolver();
+        final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
 
         values.put(LauncherSettings.Favorites.CONTAINER, item.container);
-        values.put(LauncherSettings.Favorites.CELLX, item.cellX);
-        values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+        values.put(LauncherSettings.Favorites.CELLX, coord.x);
+        values.put(LauncherSettings.Favorites.CELLY, coord.y);
         values.put(LauncherSettings.Favorites.SCREEN, item.screen);
 
         cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
@@ -181,6 +193,48 @@
     }
 
     /**
+     * Returns an ItemInfo array containing all the items in the LauncherModel.
+     * The ItemInfo.id is not set through this function.
+     */
+    static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
+        ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
+        final ContentResolver cr = context.getContentResolver();
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
+                LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
+                LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+                LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
+
+        final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+        final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+        final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
+        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
+
+        try {
+            while (c.moveToNext()) {
+                ItemInfo item = new ItemInfo();
+                item.cellX = c.getInt(cellXIndex);
+                item.cellY = c.getInt(cellYIndex);
+                item.spanX = c.getInt(spanXIndex);
+                item.spanY = c.getInt(spanYIndex);
+                item.container = c.getInt(containerIndex);
+                item.itemType = c.getInt(itemTypeIndex);
+                item.screen = c.getInt(screenIndex);
+
+                items.add(item);
+            }
+        } catch (Exception e) {
+            items.clear();
+        } finally {
+            c.close();
+        }
+
+        return items;
+    }
+
+    /**
      * 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) {
@@ -210,12 +264,13 @@
                         break;
                 }
 
+                final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getLocalCoordinates(c.getInt(cellXIndex), c.getInt(cellYIndex), 1, 1);
                 folderInfo.title = c.getString(titleIndex);
                 folderInfo.id = id;
                 folderInfo.container = c.getInt(containerIndex);
                 folderInfo.screen = c.getInt(screenIndex);
-                folderInfo.cellX = c.getInt(cellXIndex);
-                folderInfo.cellY = c.getInt(cellYIndex);
+                folderInfo.cellX = coord.x;
+                folderInfo.cellY = coord.y;
 
                 return folderInfo;
             }
@@ -239,9 +294,12 @@
 
         final ContentValues values = new ContentValues();
         final ContentResolver cr = context.getContentResolver();
-
         item.onAddToDatabase(values);
 
+        // update the values to be written with their canonical counterparts
+        final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
+        item.updateValuesWithCoordinates(values, coord.x, coord.y);
+
         Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
                 LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
 
@@ -251,6 +309,44 @@
     }
 
     /**
+     * Creates a new unique child id, for a given cell span across all layouts.
+     */
+    static int getCanonicalCellLayoutChildId(int cellId, int screen, int localCellX, int localCellY, int spanX, int spanY) {
+        if (LauncherApplication.isInPlaceRotationEnabled()) {
+            LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(localCellX, localCellY, spanX, spanY);
+            return ((screen & 0xFF) << 16) | (coord.x & 0xFF) << 8 | (coord.y & 0xFF);
+        } else {
+            return ((cellId & 0xFF) << 16) | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
+        }
+    }
+
+    /*
+     * Convenience functions to help return the local device width and height.
+     */
+    static int getLocalDeviceWidth() {
+        return mModelOrientationHelper.getLocalDeviceWidth();
+    }
+
+    static int getLocalDeviceHeight() {
+        return mModelOrientationHelper.getLocalDeviceHeight();
+    }
+
+    /**
+     * Return the new local coordinates given the local coordinates from the previous orientation.
+     */
+    static LauncherModelOrientationHelper.Coordinates getLocalCoordinatesFromPreviousLocalCoordinates(CellLayout.LayoutParams lp) {
+        return mModelOrientationHelper.getLocalCoordinatesFromPreviousLocalCoordinates(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
+    }
+
+    /**
+     * Updates the model orientation helper to take into account the current layout dimensions
+     * when performing local/canonical coordinate transformations.
+     */
+    static void updateWorkspaceLayoutCells(int shortAxisCellCount, int longAxisCellCount) {
+        mModelOrientationHelper.updateDeviceDimensions(shortAxisCellCount, longAxisCellCount);
+    }
+
+    /**
      * Update an item to the database in a specified container.
      */
     static void updateItemInDatabase(Context context, ItemInfo item) {
@@ -259,6 +355,10 @@
 
         item.onAddToDatabase(values);
 
+        // update the values to be written with their canonical counterparts
+        final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item);
+        item.updateValuesWithCoordinates(values, coord.x, coord.y);
+
         cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
     }
 
@@ -293,13 +393,18 @@
         }
     }
 
+    public void updateOrientation() {
+        // we update the LauncherModelOrientationHelper orientation whenever we re-initialize
+        mModelOrientationHelper.updateOrientation(mApp);
+    }
+
     /**
      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
      * ACTION_PACKAGE_CHANGED.
      */
     public void onReceive(Context context, Intent intent) {
         if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
-        
+
         final String action = intent.getAction();
 
         if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -343,7 +448,6 @@
             String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             enqueuePackageUpdated(new PackageUpdatedTask(
                         PackageUpdatedTask.OP_UNAVAILABLE, packages));
-
         }
     }
 
@@ -449,7 +553,7 @@
                 }
                 if (DEBUG_LOADERS) {
                     Log.d(TAG, "waited "
-                            + (SystemClock.uptimeMillis()-workspaceWaitTime) 
+                            + (SystemClock.uptimeMillis()-workspaceWaitTime)
                             + "ms for previous step to finish binding");
                 }
             }
@@ -469,7 +573,6 @@
                     android.os.Process.setThreadPriority(mIsLaunching
                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
                 }
-
                 if (loadWorkspaceFirst) {
                     if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
                     loadAndBindWorkspace();
@@ -571,14 +674,13 @@
             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
                 return true;
             }
-
             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
                     if (occupied[item.screen][x][y] != null) {
                         Log.e(TAG, "Error loading shortcut " + item
-                            + " into cell (" + item.screen + ":" 
+                            + " into cell (" + item.screen + ":"
                             + x + "," + y
-                            + ") occupied by " 
+                            + ") occupied by "
                             + occupied[item.screen][x][y]);
                         return false;
                     }
@@ -645,6 +747,11 @@
                 final int displayModeIndex = c.getColumnIndexOrThrow(
                         LauncherSettings.Favorites.DISPLAY_MODE);
 
+
+                LauncherModelOrientationHelper.Coordinates localCoords;
+                int cellX;
+                int cellY;
+
                 ShortcutInfo info;
                 String intentDescription;
                 LauncherAppWidgetInfo appWidgetInfo;
@@ -678,13 +785,17 @@
                             if (info != null) {
                                 updateSavedIcon(context, info, c, iconIndex);
 
+                                cellX = c.getInt(cellXIndex);
+                                cellY = c.getInt(cellYIndex);
+                                localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
+
                                 info.intent = intent;
                                 info.id = c.getLong(idIndex);
                                 container = c.getInt(containerIndex);
                                 info.container = container;
                                 info.screen = c.getInt(screenIndex);
-                                info.cellX = c.getInt(cellXIndex);
-                                info.cellY = c.getInt(cellYIndex);
+                                info.cellX = localCoords.x;
+                                info.cellY = localCoords.y;
 
                                 // check & update map of what's occupied
                                 if (!checkItemPlacement(occupied, info)) {
@@ -718,20 +829,22 @@
                             id = c.getLong(idIndex);
                             UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id);
 
-                            folderInfo.title = c.getString(titleIndex);
+                            cellX = c.getInt(cellXIndex);
+                            cellY = c.getInt(cellYIndex);
+                            localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
 
+                            folderInfo.title = c.getString(titleIndex);
                             folderInfo.id = id;
                             container = c.getInt(containerIndex);
                             folderInfo.container = container;
                             folderInfo.screen = c.getInt(screenIndex);
-                            folderInfo.cellX = c.getInt(cellXIndex);
-                            folderInfo.cellY = c.getInt(cellYIndex);
+                            folderInfo.cellX = localCoords.x;
+                            folderInfo.cellY = localCoords.y;
 
                             // check & update map of what's occupied
                             if (!checkItemPlacement(occupied, folderInfo)) {
                                 break;
                             }
-
                             switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
                                     mItems.add(folderInfo);
@@ -754,7 +867,6 @@
                                 itemsToRemove.add(id);
                             } else {
                                 LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id);
-
                                 intentDescription = c.getString(intentIndex);
                                 intent = null;
                                 if (intentDescription != null) {
@@ -765,14 +877,18 @@
                                     }
                                 }
 
+                                cellX = c.getInt(cellXIndex);
+                                cellY = c.getInt(cellYIndex);
+                                localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1);
+
                                 liveFolderInfo.title = c.getString(titleIndex);
                                 liveFolderInfo.id = id;
                                 liveFolderInfo.uri = uri;
                                 container = c.getInt(containerIndex);
                                 liveFolderInfo.container = container;
                                 liveFolderInfo.screen = c.getInt(screenIndex);
-                                liveFolderInfo.cellX = c.getInt(cellXIndex);
-                                liveFolderInfo.cellY = c.getInt(cellYIndex);
+                                liveFolderInfo.cellX = localCoords.x;
+                                liveFolderInfo.cellY = localCoords.y;
                                 liveFolderInfo.baseIntent = intent;
                                 liveFolderInfo.displayMode = c.getInt(displayModeIndex);
 
@@ -800,20 +916,26 @@
 
                             final AppWidgetProviderInfo provider =
                                     widgets.getAppWidgetInfo(appWidgetId);
-                            
+
                             if (!isSafeMode && (provider == null || provider.provider == null ||
                                     provider.provider.getPackageName() == null)) {
                                 Log.e(TAG, "Deleting widget that isn't installed anymore: id="
                                         + id + " appWidgetId=" + appWidgetId);
                                 itemsToRemove.add(id);
                             } else {
+                                cellX = c.getInt(cellXIndex);
+                                cellY = c.getInt(cellYIndex);
+                                int spanX = c.getInt(spanXIndex);
+                                int spanY = c.getInt(spanYIndex);
+                                localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, spanX, spanY);
+
                                 appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
                                 appWidgetInfo.id = id;
                                 appWidgetInfo.screen = c.getInt(screenIndex);
-                                appWidgetInfo.cellX = c.getInt(cellXIndex);
-                                appWidgetInfo.cellY = c.getInt(cellYIndex);
-                                appWidgetInfo.spanX = c.getInt(spanXIndex);
-                                appWidgetInfo.spanY = c.getInt(spanYIndex);
+                                appWidgetInfo.cellX = localCoords.x;
+                                appWidgetInfo.cellY = localCoords.y;
+                                appWidgetInfo.spanX = spanX;
+                                appWidgetInfo.spanY = spanY;
 
                                 container = c.getInt(containerIndex);
                                 if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
diff --git a/src/com/android/launcher2/LauncherModelOrientationHelper.java b/src/com/android/launcher2/LauncherModelOrientationHelper.java
new file mode 100644
index 0000000..6a9473d
--- /dev/null
+++ b/src/com/android/launcher2/LauncherModelOrientationHelper.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 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.launcher2;
+
+import android.content.Context;
+import android.view.Display;
+import android.view.Surface;
+import android.view.WindowManager;
+
+public class LauncherModelOrientationHelper {
+
+    static final String TAG = "LauncherModelOrientationHelper";
+
+    public class Coordinates {
+        public Coordinates(int newX, int newY) {
+            x = newX;
+            y = newY;
+        }
+
+        public int x;
+        public int y;
+    }
+
+    private int mOrientation;
+    private int mLocalDeviceWidth;
+    private int mLocalDeviceHeight;
+    private int mPreviousOrientation;
+    private int mPreviousLocalDeviceWidth;
+    private int mPreviousLocalDeviceHeight;
+    private int mCanonicalDeviceWidth;
+    private int mCanonicalDeviceHeight;
+
+    protected LauncherModelOrientationHelper(Context ctx) {
+        updateOrientation(ctx);
+    }
+
+    public int getCurrentOrientation() {
+        return mOrientation;
+    }
+
+    public int getPreviousOrientationRelativeToCurrent() {
+        int orientationDifference = -(mOrientation - mPreviousOrientation);
+
+        if (Math.abs(orientationDifference) > 180) {
+            orientationDifference = (int) -Math.signum(orientationDifference)
+                    * (360 - Math.abs(orientationDifference));
+        }
+        return orientationDifference;
+    }
+
+    private void updateLocalDeviceDimensions() {
+        mPreviousLocalDeviceHeight = mLocalDeviceHeight;
+        mPreviousLocalDeviceWidth = mLocalDeviceWidth;
+
+        if (mOrientation % 180 != 0) {
+            mLocalDeviceWidth = mCanonicalDeviceHeight;
+            mLocalDeviceHeight = mCanonicalDeviceWidth;
+        } else {
+            mLocalDeviceWidth = mCanonicalDeviceWidth;
+            mLocalDeviceHeight = mCanonicalDeviceHeight;
+        }
+    }
+
+    public void updateOrientation(Context ctx) {
+        Display display = ((WindowManager) ctx
+                .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+        mPreviousOrientation = mOrientation;
+        switch (display.getRotation()) {
+        case Surface.ROTATION_0:
+            mOrientation = 0;
+            break;
+        case Surface.ROTATION_90:
+            mOrientation = 90;
+            break;
+        case Surface.ROTATION_180:
+            mOrientation = 180;
+            break;
+        case Surface.ROTATION_270:
+            mOrientation = 270;
+            break;
+        }
+        updateLocalDeviceDimensions();
+    }
+
+    public void updateDeviceDimensions(int deviceWidth, int deviceHeight) {
+        mCanonicalDeviceWidth = deviceWidth;
+        mCanonicalDeviceHeight = deviceHeight;
+
+        updateLocalDeviceDimensions();
+    }
+
+    public Coordinates getLocalCoordinatesFromPreviousLocalCoordinates(
+            int cellX, int cellY, int spanX, int spanY) {
+        return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+                getPreviousOrientationRelativeToCurrent(),
+                mPreviousLocalDeviceWidth, mPreviousLocalDeviceHeight);
+    }
+
+    public Coordinates getCanonicalCoordinates(ItemInfo localItem) {
+        return getTransformedLayoutParams(localItem.cellX, localItem.cellY,
+                localItem.spanX, localItem.spanY, mOrientation,
+                mLocalDeviceWidth, mLocalDeviceHeight);
+    }
+
+    public Coordinates getCanonicalCoordinates(int cellX, int cellY,
+            int spanX, int spanY) {
+        return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+                mOrientation, mLocalDeviceWidth, mLocalDeviceHeight);
+    }
+
+    public Coordinates getLocalCoordinates(int cellX, int cellY, int spanX,
+            int spanY) {
+        return getTransformedLayoutParams(cellX, cellY, spanX, spanY,
+                -mOrientation, mCanonicalDeviceWidth, mCanonicalDeviceHeight);
+    }
+
+    public int getLocalDeviceWidth() {
+        return mLocalDeviceWidth;
+    }
+
+    public int getLocalDeviceHeight() {
+        return mLocalDeviceHeight;
+    }
+
+    /**
+     * Transform the coordinates based on the current device rotation
+     */
+    private Coordinates getTransformedLayoutParams(int cellX, int cellY,
+            int spanX, int spanY, int deviceRotationClockwise,
+            int initialDeviceWidth, int initialDeviceHeight) {
+        if (LauncherApplication.isScreenXLarge()) {
+            int x = cellX;
+            int y = cellY;
+            int width = spanX;
+            int height = spanY;
+            int finalDeviceWidth = initialDeviceWidth;
+            int finalDeviceHeight = initialDeviceHeight;
+
+            // item rotation is opposite of device rotation to maintain an
+            // absolute
+            // spatial layout
+            double phi = Math.toRadians(-deviceRotationClockwise);
+
+            double x1 = x + width / 2.0f - initialDeviceWidth / 2.0f;
+            double y1 = y + height / 2.0f - initialDeviceHeight / 2.0f;
+
+            // multiply x and y by a clockwise rotation matrix
+            double x2 = x1 * Math.cos(phi) + y1 * Math.sin(phi);
+            double y2 = -x1 * Math.sin(phi) + y1 * Math.cos(phi);
+
+            // Get the rotated device dimensions
+            if (deviceRotationClockwise % 180 != 0) {
+                finalDeviceWidth = initialDeviceHeight;
+                finalDeviceHeight = initialDeviceWidth;
+            }
+
+            x2 = x2 + finalDeviceWidth / 2.0f - width / 2.0f;
+            y2 = y2 + finalDeviceHeight / 2.0f - height / 2.0f;
+
+            return new Coordinates((int) Math.round(x2), (int) Math.round(y2));
+        } else {
+            return new Coordinates(cellX, cellY);
+        }
+    }
+}
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
index 7d0a0f5..74b0217 100644
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ b/src/com/android/launcher2/LiveFolderInfo.java
@@ -18,7 +18,6 @@
 
 import android.content.ContentValues;
 import android.content.Intent;
-import android.graphics.drawable.Drawable;
 import android.graphics.Bitmap;
 import android.net.Uri;
 
diff --git a/src/com/android/launcher2/ScriptField_VpConsts.java b/src/com/android/launcher2/ScriptField_VpConsts.java
index b5e41b7..ff183f4 100644
--- a/src/com/android/launcher2/ScriptField_VpConsts.java
+++ b/src/com/android/launcher2/ScriptField_VpConsts.java
@@ -19,6 +19,11 @@
 import android.renderscript.*;
 import android.content.res.Resources;
 import android.util.Log;
+import android.renderscript.Element;
+import android.renderscript.FieldPacker;
+import android.renderscript.Float2;
+import android.renderscript.Float4;
+import android.renderscript.RenderScript;
 
 public class ScriptField_VpConsts extends android.renderscript.Script.FieldBase {
     static public class Item {
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 5c322ba..b0da3a5 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -16,16 +16,14 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.content.ComponentName;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
 import android.util.Log;
 
-import java.util.ArrayList;
-
 /**
  * Represents a launchable icon on the workspaces and in folders.
  */
diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
index 19c3af0..93c500a 100644
--- a/src/com/android/launcher2/ShortcutsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -16,16 +16,15 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-
 import com.android.launcher.R;
 
 /**
diff --git a/src/com/android/launcher2/SymmetricalLinearTween.java b/src/com/android/launcher2/SymmetricalLinearTween.java
index 2e0ed8f..da02242 100644
--- a/src/com/android/launcher2/SymmetricalLinearTween.java
+++ b/src/com/android/launcher2/SymmetricalLinearTween.java
@@ -17,9 +17,7 @@
 package com.android.launcher2;
 
 import android.os.Handler;
-import android.os.Message;
 import android.os.SystemClock;
-import android.util.Log;
 
 /**
  * Provides an animation between 0.0f and 1.0f over a given duration.
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index d49c27a..255099f 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -3,10 +3,8 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.ArrayAdapter;
 
 import com.android.launcher.R;
 
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 757e48e..c67ff99 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -16,9 +16,8 @@
 
 package com.android.launcher2;
 
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
@@ -26,19 +25,19 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.TableMaskFilter;
 import android.graphics.Typeface;
-import android.text.Layout.Alignment;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
 import android.text.StaticLayout;
 import android.text.TextPaint;
+import android.text.Layout.Alignment;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.content.res.Resources;
-import android.content.Context;
 
 import com.android.launcher.R;
 
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index c56a313..0f41cc9 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -42,7 +42,10 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.animation.Animation;
 import android.view.animation.Interpolator;
+import android.view.animation.RotateAnimation;
+import android.view.animation.Animation.AnimationListener;
 import android.widget.Scroller;
 import android.widget.TextView;
 
@@ -50,22 +53,23 @@
 import java.util.HashSet;
 
 /**
- * The workspace is a wide area with a wallpaper and a finite number of screens. Each
- * screen contains a number of icons, folders or widgets the user can interact with.
- * A workspace is meant to be used with a fixed width only.
+ * The workspace is a wide area with a wallpaper and a finite number of screens.
+ * Each screen contains a number of icons, folders or widgets the user can
+ * interact with. A workspace is meant to be used with a fixed width only.
  */
 public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller {
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
     private static final int INVALID_SCREEN = -1;
-    
+
     /**
-     * The velocity at which a fling gesture will cause us to snap to the next screen
+     * The velocity at which a fling gesture will cause us to snap to the next
+     * screen
      */
     private static final int SNAP_VELOCITY = 600;
 
     private final WallpaperManager mWallpaperManager;
-    
+
     private int mDefaultScreen;
 
     private boolean mFirstLayout = true;
@@ -79,7 +83,7 @@
      * CellInfo for the cell that is currently being dragged
      */
     private CellLayout.CellInfo mDragInfo;
-    
+
     /**
      * Target drop area calculated during last acceptDrop call.
      */
@@ -87,7 +91,7 @@
 
     private float mLastMotionX;
     private float mLastMotionY;
-    
+
     private final static int TOUCH_STATE_REST = 0;
     private final static int TOUCH_STATE_SCROLLING = 1;
 
@@ -98,12 +102,12 @@
     private Launcher mLauncher;
     private IconCache mIconCache;
     private DragController mDragController;
-    
+
     /**
      * Cache of vacant cells, used during drag events and invalidated as needed.
      */
     private CellLayout.CellInfo mVacantCache = null;
-    
+
     private int[] mTempCell = new int[2];
     private int[] mTempEstimate = new int[2];
 
@@ -111,14 +115,14 @@
 
     private int mTouchSlop;
     private int mMaximumVelocity;
-    
+
     private static final int INVALID_POINTER = -1;
 
     private int mActivePointerId = INVALID_POINTER;
-    
+
     private Drawable mPreviousIndicator;
     private Drawable mNextIndicator;
-    
+
     private static final float NANOTIME_DIV = 1000000000.0f;
     private static final float SMOOTHING_SPEED = 0.75f;
     private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
@@ -129,7 +133,7 @@
 
     private static final float BASELINE_FLING_VELOCITY = 2500.f;
     private static final float FLING_VELOCITY_INFLUENCE = 0.4f;
-    
+
     private static class WorkspaceOvershootInterpolator implements Interpolator {
         private static final float DEFAULT_TENSION = 1.3f;
         private float mTension;
@@ -137,7 +141,7 @@
         public WorkspaceOvershootInterpolator() {
             mTension = DEFAULT_TENSION;
         }
-        
+
         public void setDistance(int distance) {
             mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
         }
@@ -153,7 +157,7 @@
             return t * t * ((mTension + 1) * t + mTension) + 1.0f;
         }
     }
-    
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -175,11 +179,16 @@
         super(context, attrs, defStyle);
 
         mWallpaperManager = WallpaperManager.getInstance(context);
-        
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.Workspace, defStyle, 0);
+        int canonicalDeviceWidth = a.getInt(R.styleable.Workspace_canonicalDeviceWidth, 4);
+        int canonicalDeviceHeight = a.getInt(R.styleable.Workspace_canonicalDeviceHeight, 4);
         mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);
         a.recycle();
 
+        LauncherModel.updateWorkspaceLayoutCells(canonicalDeviceWidth,
+                canonicalDeviceHeight);
         setHapticFeedbackEnabled(false);
         initWorkspace();
     }
@@ -249,9 +258,10 @@
         int count = currentScreen.getChildCount();
         for (int i = 0; i < count; i++) {
             View child = currentScreen.getChildAt(i);
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-            if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
-                return (Folder) child;
+            if (child instanceof Folder) {
+                Folder folder = (Folder) child;
+                if (folder.getInfo().opened)
+                    return folder;
             }
         }
         return null;
@@ -266,9 +276,12 @@
             int count = currentScreen.getChildCount();
             for (int i = 0; i < count; i++) {
                 View child = currentScreen.getChildAt(i);
-                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-                if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
-                    folders.add((Folder) child);
+                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child
+                        .getLayoutParams();
+                if (child instanceof Folder) {
+                    Folder folder = (Folder) child;
+                    if (folder.getInfo().opened)
+                        folders.add(folder);
                     break;
                 }
             }
@@ -296,11 +309,15 @@
      * @param currentScreen
      */
     void setCurrentScreen(int currentScreen) {
-        if (!mScroller.isFinished()) mScroller.abortAnimation();
+        if (!mScroller.isFinished())
+            mScroller.abortAnimation();
         clearVacantCache();
         mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
-        mPreviousIndicator.setLevel(mCurrentScreen);
-        mNextIndicator.setLevel(mCurrentScreen);
+        if (mPreviousIndicator != null) {
+            mPreviousIndicator.setLevel(mCurrentScreen);
+            mNextIndicator.setLevel(mCurrentScreen);
+        }
+
         scrollTo(mCurrentScreen * getWidth(), 0);
         updateWallpaperOffset();
         invalidate();
@@ -350,6 +367,85 @@
         addInScreen(child, screen, x, y, spanX, spanY, false);
     }
 
+    void addInFullScreen(View child, int screen) {
+        addInScreen(child, screen, 0, 0, -1, -1);
+    }
+
+    public void rotateCurrentScreensChildren() {
+
+        // close all the folders first
+        final ArrayList<Folder> openFolders = getOpenFolders();
+
+        WorkspaceOvershootInterpolator wi = new WorkspaceOvershootInterpolator();
+        RotateAnimation ra = new RotateAnimation((float) LauncherModel
+                .getPreviousOrientationRelativeToCurrent(), 0,
+                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
+                0.5f);
+        ra.setInterpolator(wi);
+        CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);
+        ra.setStartOffset(150);
+        ra.setDuration(650 + (int) (Math.random() * 400) - 200);
+
+        CellLayout.CellLayoutAnimationController animationController = new CellLayout.CellLayoutAnimationController(
+                ra, 0.0f);
+        currentScreen.setLayoutAnimation(animationController);
+        currentScreen.setLayoutAnimationListener(new AnimationListener() {
+            public void onAnimationStart(Animation animation) {
+                // do nothing
+            }
+
+            public void onAnimationRepeat(Animation animation) {
+                // do nothing
+            }
+
+            public void onAnimationEnd(Animation animation) {
+                for (int j = 0; j < openFolders.size(); ++j) {
+                    Folder folder = openFolders.get(j);
+                    if (!folder.getInfo().opened) {
+                        mLauncher.openFolder(folder.getInfo());
+                    }
+                }
+            }
+        });
+        animationController.start();
+
+        for (int j = 0; j < openFolders.size(); ++j) {
+            mLauncher.closeFolder(openFolders.get(j));
+        }
+    }
+
+    public void refreshWorkspaceChildren() {
+        final int count = getChildCount();
+        View child;
+
+        CellLayout.LayoutParams lp;
+        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel
+                .getLocalDeviceWidth(), MeasureSpec.EXACTLY);
+        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel
+                .getLocalDeviceHeight(), MeasureSpec.EXACTLY);
+
+        clearVacantCache();
+
+        for (int i = 0; i < count; i++) {
+            final CellLayout layout = (CellLayout) getChildAt(i);
+            int numChildren = layout.getChildCount();
+
+            // save reference to all current children
+            for (int j = 0; j < numChildren; j++) {
+                child = layout.getChildAt(j);
+
+                lp = (CellLayout.LayoutParams) child.getLayoutParams();
+                LauncherModelOrientationHelper.Coordinates localCoord = LauncherModel
+                        .getLocalCoordinatesFromPreviousLocalCoordinates(lp);
+
+                lp.cellX = localCoord.x;
+                lp.cellY = localCoord.y;
+            }
+
+            layout.measure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
     /**
      * Adds the specified child in the specified screen. The position and dimension of
      * the child are defined by x, y, spanX and spanY.
@@ -381,13 +477,23 @@
             lp.cellHSpan = spanX;
             lp.cellVSpan = spanY;
         }
-        group.addView(child, insert ? 0 : -1, lp);
+
+        // get the canonical child id to uniquely represent this view in this
+        // screen
+        int childId = LauncherModel.getCanonicalCellLayoutChildId(child.getId(), screen, x, y, spanX, spanY);
+        if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) {
+            // TODO: This branch occurs when the workspace is adding views
+            // outside of the defined grid
+            // maybe we should be deleting these items from the LauncherMode?
+            Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
+        }
+
         if (!(child instanceof Folder)) {
             child.setHapticFeedbackEnabled(false);
             child.setOnLongClickListener(mLongClickListener);
         }
         if (child instanceof DropTarget) {
-            mDragController.addDropTarget((DropTarget)child);
+            mDragController.addDropTarget((DropTarget) child);
         }
     }
 
@@ -432,14 +538,14 @@
                     Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);
         }
     }
-    
+
     @Override
     public void scrollTo(int x, int y) {
         super.scrollTo(x, y);
         mTouchX = x;
         mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
     }
-    
+
     @Override
     public void computeScroll() {
         if (mScroller.computeScrollOffset()) {
@@ -531,7 +637,6 @@
             getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
         }
 
-
         if (mFirstLayout) {
             setHorizontalScrollBarEnabled(false);
             scrollTo(mCurrentScreen * width, 0);
@@ -554,6 +659,12 @@
                 childLeft += childWidth;
             }
         }
+
+        if (LauncherApplication.isInPlaceRotationEnabled()) {
+            // When the device is rotated, the scroll position of the current screen
+            // needs to be refreshed
+            setCurrentScreen(getCurrentScreen());
+        }
     }
 
     @Override
@@ -613,7 +724,7 @@
                     if (mCurrentScreen > 0) {
                         getChildAt(mCurrentScreen - 1).addFocusables(views, direction);
                     }
-                } else if (direction == View.FOCUS_RIGHT){
+                } else if (direction == View.FOCUS_RIGHT) {
                     if (mCurrentScreen < getChildCount() - 1) {
                         getChildAt(mCurrentScreen + 1).addFocusables(views, direction);
                     }
@@ -662,7 +773,7 @@
             mVelocityTracker = VelocityTracker.obtain();
         }
         mVelocityTracker.addMovement(ev);
-        
+
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_MOVE: {
                 /*
@@ -683,9 +794,9 @@
                 final int touchSlop = mTouchSlop;
                 boolean xMoved = xDiff > touchSlop;
                 boolean yMoved = yDiff > touchSlop;
-                
+
                 if (xMoved || yMoved) {
-                    
+
                     if (xMoved) {
                         // Scroll if the user moved far enough along the X axis
                         mTouchState = TOUCH_STATE_SCROLLING;
@@ -707,14 +818,14 @@
                 break;
             }
 
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                // Remember location of down touch
-                mLastMotionX = x;
-                mLastMotionY = y;
-                mActivePointerId = ev.getPointerId(0);
-                mAllowLongPress = true;
+        case MotionEvent.ACTION_DOWN: {
+            final float x = ev.getX();
+            final float y = ev.getY();
+            // Remember location of down touch
+            mLastMotionX = x;
+            mLastMotionY = y;
+            mActivePointerId = ev.getPointerId(0);
+            mAllowLongPress = true;
 
                 /*
                  * If being flinged and user touches the screen, initiate drag;
@@ -727,36 +838,36 @@
 
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                
+
                 if (mTouchState != TOUCH_STATE_SCROLLING) {
                     final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen);
                     if (!currentScreen.lastDownOnOccupiedCell()) {
                         getLocationOnScreen(mTempCell);
                         // Send a tap to the wallpaper if the last down was on empty space
                         final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-                        mWallpaperManager.sendWallpaperCommand(getWindowToken(), 
+                        mWallpaperManager.sendWallpaperCommand(getWindowToken(),
                                 "android.wallpaper.tap",
                                 mTempCell[0] + (int) ev.getX(pointerIndex),
                                 mTempCell[1] + (int) ev.getY(pointerIndex), 0, null);
                     }
                 }
-                
+
                 // Release the drag
                 clearChildrenCache();
                 mTouchState = TOUCH_STATE_REST;
                 mActivePointerId = INVALID_POINTER;
                 mAllowLongPress = false;
-                
+
                 if (mVelocityTracker != null) {
                     mVelocityTracker.recycle();
                     mVelocityTracker = null;
                 }
 
-                break;
-                
-            case MotionEvent.ACTION_POINTER_UP:
-                onSecondaryPointerUp(ev);
-                break;
+            break;
+
+        case MotionEvent.ACTION_POINTER_UP:
+            onSecondaryPointerUp(ev);
+            break;
         }
 
         /*
@@ -765,7 +876,7 @@
          */
         return mTouchState != TOUCH_STATE_REST;
     }
-    
+
     private void onSecondaryPointerUp(MotionEvent ev) {
         final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                 MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -805,7 +916,7 @@
             }
             ViewParent parent = v.getParent();
             if (parent instanceof View) {
-                v = (View)v.getParent();
+                v = (View) v.getParent();
             } else {
                 return;
             }
@@ -818,7 +929,7 @@
             fromScreen = toScreen;
             toScreen = temp;
         }
-        
+
         final int count = getChildCount();
 
         fromScreen = Math.max(fromScreen, 0);
@@ -841,7 +952,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        
+
         if (mLauncher.isWorkspaceLocked()) {
             return false; // We don't want the events.  Let them fall through to the all apps view.
         }
@@ -910,11 +1021,11 @@
                 final VelocityTracker velocityTracker = mVelocityTracker;
                 velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
-                
+
                 final int screenWidth = getWidth();
                 final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
                 final float scrolledPos = (float) mScrollX / screenWidth;
-                
+
                 if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                     // Fling hard enough to move left.
                     // Don't fling across more than one screen at a time.
@@ -950,24 +1061,24 @@
 
         return true;
     }
-    
+
     void snapToScreen(int whichScreen) {
         snapToScreen(whichScreen, 0, false);
     }
 
     private void snapToScreen(int whichScreen, int velocity, boolean settle) {
-        //if (!mScroller.isFinished()) return;
+        // if (!mScroller.isFinished()) return;
 
         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
-        
+
         clearVacantCache();
         enableChildrenCache(mCurrentScreen, whichScreen);
 
         mNextScreen = whichScreen;
 
         if (mPreviousIndicator != null) {
-        mPreviousIndicator.setLevel(mNextScreen);
-        mNextIndicator.setLevel(mNextScreen);
+            mPreviousIndicator.setLevel(mNextScreen);
+            mNextIndicator.setLevel(mNextScreen);
         }
 
         View focusedChild = getFocusedChild();
@@ -975,7 +1086,7 @@
                 focusedChild == getChildAt(mCurrentScreen)) {
             focusedChild.clearFocus();
         }
-        
+
         final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
         final int newX = whichScreen * getWidth();
         final int delta = newX - mScrollX;
@@ -984,13 +1095,13 @@
         if (!mScroller.isFinished()) {
             mScroller.abortAnimation();
         }
-        
+
         if (settle) {
             mScrollInterpolator.setDistance(screenDelta);
         } else {
             mScrollInterpolator.disableSettle();
         }
-        
+
         velocity = Math.abs(velocity);
         if (velocity > 0) {
             duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
@@ -1006,15 +1117,15 @@
 
     void startDrag(CellLayout.CellInfo cellInfo) {
         View child = cellInfo.cell;
-        
+
         // Make sure the drag was started by a long press as opposed to a long click.
         if (!child.isInTouchMode()) {
             return;
         }
-        
+
         mDragInfo = cellInfo;
         mDragInfo.screen = mCurrentScreen;
-        
+
         CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));
 
         current.onDragChild(child);
@@ -1061,44 +1172,53 @@
             // Move internally
             if (mDragInfo != null) {
                 final View cell = mDragInfo.cell;
-                int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;                
+                int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
                 if (index != mDragInfo.screen) {
                     final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                     originalCellLayout.removeView(cell);
-                    cellLayout.addView(cell);
+                    addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY,
+                            mDragInfo.spanX, mDragInfo.spanY);
                 }
                 mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
-                        mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
-                cellLayout.onDropChild(cell, mTargetCell);
+                        mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout,
+                        mTargetCell);
+                cellLayout.onDropChild(cell);
 
+                // update the item's position after drop
                 final ItemInfo info = (ItemInfo) cell.getTag();
-                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
+                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell
+                        .getLayoutParams();
+                lp.cellX = mTargetCell[0];
+                lp.cellY = mTargetCell[1];
+
                 LauncherModel.moveItemInDatabase(mLauncher, info,
-                        LauncherSettings.Favorites.CONTAINER_DESKTOP, index, lp.cellX, lp.cellY);
+                        LauncherSettings.Favorites.CONTAINER_DESKTOP, index,
+                        lp.cellX, lp.cellY);
             }
         }
     }
 
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
+    public void onDragEnter(DragSource source, int x, int y, int xOffset,
+            int yOffset, DragView dragView, Object dragInfo) {
         clearVacantCache();
     }
 
-    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
+    public void onDragOver(DragSource source, int x, int y, int xOffset,
+            int yOffset, DragView dragView, Object dragInfo) {
     }
 
-    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
+    public void onDragExit(DragSource source, int x, int y, int xOffset,
+            int yOffset, DragView dragView, Object dragInfo) {
         clearVacantCache();
     }
 
-    private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
+    private void onDropExternal(int x, int y, Object dragInfo,
+            CellLayout cellLayout) {
         onDropExternal(x, y, dragInfo, cellLayout, false);
     }
-    
-    private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout,
-            boolean insertAtFirst) {
+
+    private void onDropExternal(int x, int y, Object dragInfo,
+            CellLayout cellLayout, boolean insertAtFirst) {
         // Drag from somewhere else
         ItemInfo info = (ItemInfo) dragInfo;
 
@@ -1109,41 +1229,42 @@
         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
             if (info.container == NO_ID && info instanceof ApplicationInfo) {
                 // Came from all apps -- make a copy
-                info = new ShortcutInfo((ApplicationInfo)info);
+                info = new ShortcutInfo((ApplicationInfo) info);
             }
-            view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info);
+            view = mLauncher.createShortcut(R.layout.application, cellLayout,
+                    (ShortcutInfo) info);
             break;
         case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
             view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
-                    (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
+                    (ViewGroup) getChildAt(mCurrentScreen),
+                    ((UserFolderInfo) info));
             break;
         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
             cellLayout.setTagToCellInfoForPoint(x, y);
             mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag());
             break;
         default:
-            throw new IllegalStateException("Unknown item type: " + info.itemType);
+            throw new IllegalStateException("Unknown item type: "
+                    + info.itemType);
         }
 
         // addAppWidgetFromDrop already took care of attaching the widget view to the appropriate cell
         // TODO why aren't we calling addInScreen here?
         if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
-            cellLayout.addView(view, insertAtFirst ? 0 : -1);
-            view.setHapticFeedbackEnabled(false);
-            view.setOnLongClickListener(mLongClickListener);
-            if (view instanceof DropTarget) {
-                mDragController.addDropTarget((DropTarget) view);
-            }
-
-            mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
-            cellLayout.onDropChild(view, mTargetCell);
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+            mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout,
+                    mTargetCell);
+            addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
+                    mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
+            cellLayout.onDropChild(view);
+            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view
+                    .getLayoutParams();
 
             LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
-                    LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
+                    LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen,
+                    lp.cellX, lp.cellY);
         }
     }
-    
+
     /**
      * Return the current {@link CellLayout}, correctly picking the destination
      * screen while a scroll is in progress.
@@ -1170,37 +1291,37 @@
 
         return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
     }
-    
+
     /**
      * {@inheritDoc}
      */
     public Rect estimateDropLocation(DragSource source, int x, int y,
             int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) {
         final CellLayout layout = getCurrentDropLayout();
-        
+
         final CellLayout.CellInfo cellInfo = mDragInfo;
         final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
         final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
         final View ignoreView = cellInfo == null ? null : cellInfo.cell;
-        
+
         final Rect location = recycle != null ? recycle : new Rect();
-        
+
         // Find drop cell and convert into rectangle
-        int[] dropCell = estimateDropCell(x - xOffset, y - yOffset,
-                spanX, spanY, ignoreView, layout, mTempCell);
-        
+        int[] dropCell = estimateDropCell(x - xOffset, y - yOffset, spanX,
+                spanY, ignoreView, layout, mTempCell);
+
         if (dropCell == null) {
             return null;
         }
-        
+
         layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate);
         location.left = mTempEstimate[0];
         location.top = mTempEstimate[1];
-        
+
         layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate);
         location.right = mTempEstimate[0];
         location.bottom = mTempEstimate[1];
-        
+
         return location;
     }
 
@@ -1218,7 +1339,7 @@
         return layout.findNearestVacantArea(pixelX, pixelY,
                 spanX, spanY, mVacantCache, recycle);
     }
-    
+
     void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }
@@ -1230,14 +1351,14 @@
     public void onDropCompleted(View target, boolean success) {
         clearVacantCache();
 
-        if (success){
+        if (success) {
             if (target != this && mDragInfo != null) {
                 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                 cellLayout.removeView(mDragInfo.cell);
                 if (mDragInfo.cell instanceof DropTarget) {
                     mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
                 }
-                //final Object tag = mDragInfo.cell.getTag();
+                // final Object tag = mDragInfo.cell.getTag();
             }
         } else {
             if (mDragInfo != null) {
@@ -1252,18 +1373,22 @@
     public void scrollLeft() {
         clearVacantCache();
         if (mScroller.isFinished()) {
-            if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
+            if (mCurrentScreen > 0)
+                snapToScreen(mCurrentScreen - 1);
         } else {
-            if (mNextScreen > 0) snapToScreen(mNextScreen - 1);            
+            if (mNextScreen > 0)
+                snapToScreen(mNextScreen - 1);
         }
     }
 
     public void scrollRight() {
         clearVacantCache();
         if (mScroller.isFinished()) {
-            if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
+            if (mCurrentScreen < getChildCount() - 1)
+                snapToScreen(mCurrentScreen + 1);
         } else {
-            if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);            
+            if (mNextScreen < getChildCount() - 1)
+                snapToScreen(mNextScreen + 1);
         }
     }
 
@@ -1291,7 +1416,7 @@
                 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
                 if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
                     Folder f = (Folder) child;
-                    if (f.getInfo() == tag) {
+                    if (f.getInfo() == tag && f.getInfo().opened) {
                         return f;
                     }
                 }
@@ -1321,7 +1446,7 @@
     public boolean allowLongPress() {
         return mAllowLongPress;
     }
-    
+
     /**
      * Set true to allow long-press events to be triggered, usually checked by
      * {@link Launcher} to accept or block dpad-initiated long-presses.
@@ -1349,17 +1474,17 @@
                 public void run() {
                     final ArrayList<View> childrenToRemove = new ArrayList<View>();
                     childrenToRemove.clear();
-        
+
                     int childCount = layout.getChildCount();
                     for (int j = 0; j < childCount; j++) {
                         final View view = layout.getChildAt(j);
                         Object tag = view.getTag();
-        
+
                         if (tag instanceof ShortcutInfo) {
                             final ShortcutInfo info = (ShortcutInfo) tag;
                             final Intent intent = info.intent;
                             final ComponentName name = intent.getComponent();
-        
+
                             if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                                 for (String packageName: packageNames) {
                                     if (packageName.equals(name.getPackageName())) {
@@ -1375,12 +1500,12 @@
                             final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
                             final int contentsCount = contents.size();
                             boolean removedFromFolder = false;
-        
+
                             for (int k = 0; k < contentsCount; k++) {
                                 final ShortcutInfo appInfo = contents.get(k);
                                 final Intent intent = appInfo.intent;
                                 final ComponentName name = intent.getComponent();
-        
+
                                 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                                     for (String packageName: packageNames) {
                                         if (packageName.equals(name.getPackageName())) {
@@ -1393,11 +1518,12 @@
                                     }
                                 }
                             }
-        
+
                             contents.removeAll(toRemove);
                             if (removedFromFolder) {
                                 final Folder folder = getOpenFolder();
-                                if (folder != null) folder.notifyDataSetChanged();
+                                if (folder != null)
+                                    folder.notifyDataSetChanged();
                             }
                         } else if (tag instanceof LiveFolderInfo) {
                             final LiveFolderInfo info = (LiveFolderInfo) tag;
@@ -1410,7 +1536,7 @@
                                     if (packageName.equals(providerInfo.packageName)) {
                                         // TODO: This should probably be done on a worker thread
                                         LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                                        childrenToRemove.add(view);                        
+                                        childrenToRemove.add(view);
                                     }
                                 }
                             }
@@ -1423,13 +1549,13 @@
                                     if (packageName.equals(provider.provider.getPackageName())) {
                                         // TODO: This should probably be done on a worker thread
                                         LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                                        childrenToRemove.add(view);                                
+                                        childrenToRemove.add(view);
                                     }
                                 }
                             }
                         }
                     }
-        
+
                     childCount = childrenToRemove.size();
                     for (int j = 0; j < childCount; j++) {
                         View child = childrenToRemove.get(j);
@@ -1438,7 +1564,7 @@
                             mDragController.removeDropTarget((DropTarget)child);
                         }
                     }
-        
+
                     if (childCount > 0) {
                         layout.requestLayout();
                         layout.invalidate();
@@ -1468,7 +1594,7 @@
                     if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
                             Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                         final int appCount = apps.size();
-                        for (int k=0; k<appCount; k++) {
+                        for (int k = 0; k < appCount; k++) {
                             ApplicationInfo app = apps.get(k);
                             if (app.componentName.equals(name)) {
                                 info.setIcon(mIconCache.getIcon(info.intent));