Merge "Fixing clipped landscape layout and crash when tapping to add widgets."
diff --git a/res/layout-large/all_apps_tabbed.xml b/res/layout-large/all_apps_tabbed.xml
index b00b3c3..1a20440 100644
--- a/res/layout-large/all_apps_tabbed.xml
+++ b/res/layout-large/all_apps_tabbed.xml
@@ -101,8 +101,6 @@
                 android:id="@+id/all_apps_paged_view"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                launcher:cellCountX="@integer/all_apps_view_cellCountX"
-                launcher:cellCountY="@integer/all_apps_view_cellCountY"
                 launcher:pageLayoutWidthGap="@dimen/all_apps_view_pageLayoutWidthGap"
                 launcher:pageLayoutHeightGap="@dimen/all_apps_view_pageLayoutHeightGap"
                 launcher:pageLayoutPaddingTop="@dimen/all_apps_view_pageLayoutPaddingTop"
diff --git a/res/values-large-land/dimens.xml b/res/values-large-land/dimens.xml
index 196cdb0..0f7e0ed 100644
--- a/res/values-large-land/dimens.xml
+++ b/res/values-large-land/dimens.xml
@@ -22,8 +22,6 @@
     <dimen name="customization_drawer_height">480dp</dimen>
     <dimen name="customization_drawer_content_height">420dp</dimen>
 
-    <integer name="all_apps_view_cellCountX">7</integer>
-    <integer name="all_apps_view_cellCountY">5</integer>
     <dimen name="all_apps_view_pageLayoutWidthGap">36dp</dimen>
     <dimen name="all_apps_view_pageLayoutHeightGap">6dp</dimen>
     <dimen name="all_apps_view_pageLayoutPaddingTop">20dp</dimen>
diff --git a/res/values-large-port/dimens.xml b/res/values-large-port/dimens.xml
index 47cac78..2ea9e38 100644
--- a/res/values-large-port/dimens.xml
+++ b/res/values-large-port/dimens.xml
@@ -22,8 +22,6 @@
     <dimen name="customization_drawer_height">800dp</dimen>
     <dimen name="customization_drawer_content_height">420dp</dimen>
 
-    <integer name="all_apps_view_cellCountX">5</integer>
-    <integer name="all_apps_view_cellCountY">7</integer>
     <dimen name="all_apps_view_pageLayoutWidthGap">36dp</dimen>
     <dimen name="all_apps_view_pageLayoutHeightGap">36dp</dimen>
     <dimen name="all_apps_view_pageLayoutPaddingTop">25dp</dimen>
diff --git a/res/values-large/config.xml b/res/values-large/config.xml
index 99ee1ec..8b77696 100644
--- a/res/values-large/config.xml
+++ b/res/values-large/config.xml
@@ -21,6 +21,9 @@
          Should be an even number, for pixel alignment. -->
     <integer name="config_dragViewExtraPixels">0</integer>
 
+    <!-- When shrinking the workspace, this is the percentage of its original size. -->
+    <integer name="config_workspaceShrinkPercent">17</integer>
+
     <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
          of the bright green hover outline, and then fade out the outline at the end. These are
          the values used in that animation -->
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index c812a46..d308209 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -69,6 +69,9 @@
     private int mPageContentWidth;
     private boolean mHasMadeSuccessfulDrop;
 
+    private int mLastMeasureWidth = -1;
+    private int mLastMeasureHeight = -1;
+
     public AllAppsPagedView(Context context) {
         this(context, null);
     }
@@ -80,8 +83,6 @@
     public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, defStyle, 0);
-        mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
-        mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
         mInflater = LayoutInflater.from(context);
         mApps = new ArrayList<ApplicationInfo>();
         mFilteredApps = new ArrayList<ApplicationInfo>();
@@ -91,11 +92,6 @@
         Resources r = context.getResources();
         setDragSlopeThreshold(
                 r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold) / 100.0f);
-
-        // Create a dummy page and set it up to find out the content width (used by our parent)
-        PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
-        setupPage(layout);
-        mPageContentWidth = layout.getContentWidth();
     }
 
     @Override
@@ -104,6 +100,80 @@
         mCenterPagesVertically = false;
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        final int height = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (mLastMeasureWidth != width || mLastMeasureHeight != height) {
+            // Create a dummy page and set it up to find out the content width (used by our parent)
+            PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+            setupPage(layout);
+            mPageContentWidth = layout.getContentWidth();
+
+            mCellCountX = determineCellCountX(width, layout);
+            mCellCountY = determineCellCountY(height, layout);
+            mLastMeasureWidth = width;
+            mLastMeasureHeight = height;
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (mFirstLayout) {
+            invalidatePageData();
+
+            // invalidatePageData() is what causes the child pages to be created. We need the
+            // children to be measured before layout, so force a new measure here.
+            measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+        }
+        super.onLayout(changed, left, top, right, bottom);
+    }
+
+    private int determineCellCountX(int availableWidth, PagedViewCellLayout layout) {
+        int cellCountX = 0;
+        final int cellWidth = layout.getCellWidth();
+
+        // Subtract padding for current page and adjacent pages
+        availableWidth -= mPageLayoutPaddingLeft * 2 + mPageLayoutPaddingRight * 2;
+
+        availableWidth -= cellWidth; // Assume at least one column
+        cellCountX = 1 + availableWidth / (cellWidth + mPageLayoutWidthGap);
+        availableWidth = availableWidth % (cellWidth + mPageLayoutWidthGap);
+
+        // Ensures that we show at least 30% of the holo icons on each side
+        final int minLeftoverWidth = (int) (cellWidth * 0.6f);
+
+        // Reserve room for the holo outlines
+        if (cellCountX <= 4) {
+            // When we're really tight on space, just pack the icons a bit closer together
+            final int missingWidth = minLeftoverWidth - availableWidth;
+            if (missingWidth > 0) {
+                mPageLayoutWidthGap -= Math.ceil(missingWidth * 1.0f / (cellCountX - 1));
+            }
+        } else {
+            if (cellCountX >= 8) {
+                // Carve out a few extra columns for very large widths
+                cellCountX = (int) (cellCountX * 0.9f);
+            } else if (availableWidth < minLeftoverWidth) {
+                cellCountX -= 1;
+            }
+        }
+        return cellCountX;
+    }
+
+    private int determineCellCountY(int availableHeight, PagedViewCellLayout layout) {
+        final int cellHeight = layout.getCellHeight();
+        final int screenHeight = mLauncher.getResources().getDisplayMetrics().heightPixels;
+
+        availableHeight -= mPageLayoutPaddingTop + mPageLayoutPaddingBottom;
+        availableHeight -= cellHeight; // Assume at least one row
+        availableHeight -= screenHeight * 0.16f;
+        return (1 + availableHeight / (cellHeight + mPageLayoutHeightGap));
+    }
+
     void allowHardwareLayerCreation() {
         // This is called after the first time we launch into All Apps. Before that point,
         // there's no need for hardware layers here since there's a hardware layer set on the
@@ -482,6 +552,11 @@
 
     @Override
     public void syncPages() {
+        if (mCellCountX <= 0 || mCellCountY <= 0) {
+            // We don't know our size yet, which means we haven't calculated cell count x/y;
+            // onMeasure will call us once we figure out our size
+            return;
+        }
         // ensure that we have the right number of pages (min of 1, since we have placeholders)
         int numPages = Math.max(1,
                 (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY)));
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index 96de5a7..a2f10f5 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -35,7 +35,6 @@
 import android.widget.TextView;
 
 import java.util.ArrayList;
-import java.util.Random;
 
 /**
  * Implements a tabbed version of AllApps2D.
@@ -126,16 +125,6 @@
             }
         });
 
-        // Set the width of the tab bar properly
-        int pageWidth = mAllApps.getPageContentWidth();
-        View allAppsTabBar = (View) findViewById(R.id.all_apps_tab_bar);
-        if (allAppsTabBar == null) throw new Resources.NotFoundException();
-        int tabWidgetPadding = 0;
-        final int childCount = tabWidget.getChildCount();
-        if (childCount > 0) {
-            tabWidgetPadding += tabWidget.getChildAt(0).getPaddingLeft() * 2;
-        }
-        allAppsTabBar.getLayoutParams().width = pageWidth + tabWidgetPadding;
 
         // It needs to be INVISIBLE so that it will be measured in the layout.
         // Otherwise the animations is messed up when we show it for the first time.
@@ -175,7 +164,20 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mFirstLayout = false;
+        if (mFirstLayout) {
+            mFirstLayout = false;
+            // Set the width of the tab bar properly
+            int pageWidth = mAllApps.getPageContentWidth();
+            TabWidget tabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
+            View allAppsTabBar = (View) findViewById(R.id.all_apps_tab_bar);
+            if (allAppsTabBar == null) throw new Resources.NotFoundException();
+            int tabWidgetPadding = 0;
+            final int childCount = tabWidget.getChildCount();
+            if (childCount > 0) {
+                tabWidgetPadding += tabWidget.getChildAt(0).getPaddingLeft() * 2;
+            }
+            allAppsTabBar.getLayoutParams().width = pageWidth + tabWidgetPadding;
+        }
         super.onLayout(changed, l, t, r, b);
     }
 
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index b2e308d..68ec535 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -54,6 +54,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.Checkable;
@@ -124,6 +125,8 @@
     private final Canvas mCanvas = new Canvas();
     private final LayoutInflater mInflater;
 
+    private boolean mFirstMeasure = true;
+
     private final float mTmpFloatPos[] = new float[2];
     private final float ANIMATION_SCALE = 0.5f;
 
@@ -173,12 +176,6 @@
         setDragSlopeThreshold(
                 r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f);
 
-        // Create a dummy page and set it up to find out the content width (used by our parent)
-        PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
-        setupPage(layout);
-        mPageContentWidth = layout.getContentWidth();
-        mMinPageWidth = layout.getWidthBeforeFirstLayout();
-
         setVisibility(View.GONE);
         setSoundEffectsEnabled(false);
         setupWorkspaceLayout();
@@ -190,6 +187,32 @@
         mCenterPagesVertically = false;
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (mFirstMeasure) {
+            mFirstMeasure = false;
+
+            // TODO: actually calculate mCellCountX/mCellCountY as some function of
+            // widthSize and heightSize
+            //mCellCountX = ?
+            //mCellCountY = ?
+
+            // Since mCellCountX/mCellCountY changed, we need to update the pages
+            invalidatePageData();
+
+            // Create a dummy page and set it up to find out the content width (used by our parent)
+            PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+            setupPage(layout);
+            mPageContentWidth = layout.getContentWidth();
+            mMinPageWidth = layout.getWidthBeforeFirstLayout();
+        }
+    }
+
     public void setLauncher(Launcher launcher) {
         Context context = getContext();
         mLauncher = launcher;
@@ -1093,6 +1116,11 @@
 
     @Override
     public void syncPages() {
+        if (mFirstMeasure) {
+            // We don't know our size yet, which means we haven't calculated cell count x/y;
+            // onMeasure will call us once we figure out our size
+            return;
+        }
         boolean enforceMinimumPagedWidths = false;
         boolean centerPagedViewCellLayouts = false;
         switch (mCustomizationType) {
diff --git a/src/com/android/launcher2/CustomizeTrayTabHost.java b/src/com/android/launcher2/CustomizeTrayTabHost.java
index 2c47895..ab50cf1 100644
--- a/src/com/android/launcher2/CustomizeTrayTabHost.java
+++ b/src/com/android/launcher2/CustomizeTrayTabHost.java
@@ -115,17 +115,6 @@
                 }
             }
         });
-
-        // Set the width of the tab bar properly
-        int pageWidth = customizePagedView.getPageContentWidth();
-        TabWidget customizeTabBar = (TabWidget) findViewById(com.android.internal.R.id.tabs);
-        if (customizeTabBar == null) throw new Resources.NotFoundException();
-        int tabWidgetPadding = 0;
-        final int childCount = tabWidget.getChildCount();
-        if (childCount > 0) {
-            tabWidgetPadding += tabWidget.getChildAt(0).getPaddingLeft() * 2;
-        }
-        customizeTabBar.getLayoutParams().width = pageWidth + tabWidgetPadding;
     }
 
     @Override
@@ -150,7 +139,23 @@
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mFirstLayout = false;
+        if (mFirstLayout) {
+            mFirstLayout = false;
+
+            final CustomizePagedView customizePagedView =
+                (CustomizePagedView) findViewById(R.id.customization_drawer_tab_contents);
+            TabWidget tabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
+            // Set the width of the tab bar properly
+            int pageWidth = customizePagedView.getPageContentWidth();
+            TabWidget customizeTabBar = (TabWidget) findViewById(com.android.internal.R.id.tabs);
+            if (customizeTabBar == null) throw new Resources.NotFoundException();
+            int tabWidgetPadding = 0;
+            final int childCount = tabWidget.getChildCount();
+            if (childCount > 0) {
+                tabWidgetPadding += tabWidget.getChildAt(0).getPaddingLeft() * 2;
+            }
+            customizeTabBar.getLayoutParams().width = pageWidth + tabWidgetPadding;
+        }
         super.onLayout(changed, l, t, r, b);
     }
 
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index fdd4125..5d9b5db 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -112,12 +112,6 @@
             if (item instanceof LauncherAppWidgetInfo) {
                 mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
             }
-        } else if (source instanceof Folder) {
-            final Folder folder = (Folder) source;
-            final FolderInfo folderInfo = (FolderInfo) folder.getInfo();
-            // Item must be a ShortcutInfo otherwise it couldn't have been in the folder
-            // in the first place.
-            folderInfo.remove((ShortcutInfo)item);
         }
 
         if (item instanceof FolderInfo) {
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index a4aeec4..0470e41 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -25,7 +25,6 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
-import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -81,6 +80,8 @@
     private int mMaxCountX;
     private int mMaxCountY;
     private Rect mNewSize = new Rect();
+    private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
+    boolean mItemsInvalidated = false;
 
     /**
      * Used to inflate the Workspace from XML.
@@ -213,10 +214,12 @@
     void bind(FolderInfo info) {
         mInfo = info;
         ArrayList<ShortcutInfo> children = info.contents;
+        setupContentForNumItems(children.size());
         for (int i = 0; i < children.size(); i++) {
             ShortcutInfo child = (ShortcutInfo) children.get(i);
-            onAdd(child);
+            createAndAddShortcut(child);
         }
+        mItemsInvalidated = true;
         mInfo.addListener(this);
     }
 
@@ -460,25 +463,27 @@
 
         int countX = mContent.getCountX();
         int countY = mContent.getCountY();
-        if (countX * countY < count) {
-            // Current grid is too small, expand it
-            if (countX <= countY && countX < mMaxCountX) {
-                countX++;
-            } else if (countY < mMaxCountY) {
-                countY++;
-            }
-            if (countY == 0) countY++;
+        boolean done = false;
 
-            mContent.setGridSize(countX, countY);
-        } else if ((countX - 1) * countY >= count || (countY - 1) * countX >= count) {
-            // Current grid is too big, shrink it
-            if (countX <= countY) {
-                countY--;
-            } else {
-                countX--;
+        while (!done) {
+            int oldCountX = countX;
+            int oldCountY = countY;
+            if (countX * countY < count) {
+                // Current grid is too small, expand it
+                if (countX <= countY && countX < mMaxCountX) {
+                    countX++;
+                } else if (countY < mMaxCountY) {
+                    countY++;
+                }
+                if (countY == 0) countY++;
+            } else if ((countY - 1) * countX >= count && countY >= countX) {
+                countY = Math.max(0, countY - 1);
+            } else if ((countX - 1) * countY >= count) {
+                countX = Math.max(0, countX - 1);
             }
-            mContent.setGridSize(countX, countY);
+            done = countX == oldCountX && countY == oldCountY;
         }
+        mContent.setGridSize(countX, countY);
         arrangeChildren(list);
     }
 
@@ -531,7 +536,6 @@
     }
 
     private void setupContentForNumItems(int count) {
-
         setupContentDimension(count);
 
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
@@ -561,10 +565,14 @@
             info.cellY = vacant[1];
             boolean insert = false;
             mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
+            LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
+                    info.cellX, info.cellY);
         }
+        mItemsInvalidated = true;
     }
 
     public void onAdd(ShortcutInfo item) {
+        mItemsInvalidated = true;
         if (!findAndSetEmptyCells(item)) {
             // The current layout is full, can we expand it?
             setupContentForNumItems(getItemCount() + 1);
@@ -581,19 +589,6 @@
         return mContent.getChildrenLayout().getChildAt(index);
     }
 
-    private ArrayList<View> getItemsInReadingOrder() {
-        ArrayList<View> list = new ArrayList<View>();
-        for (int j = 0; j < mContent.getCountY(); j++) {
-            for (int i = 0; i < mContent.getCountX(); i++) {
-                View v = mContent.getChildAt(i, j);
-                if (v != null) {
-                    list.add(v);
-                }
-            }
-        }
-        return list;
-    }
-
     private void onCloseComplete() {
         if (mRearrangeOnClose) {
             setupContentForNumItems(getItemCount());
@@ -602,6 +597,7 @@
     }
 
     public void onRemove(ShortcutInfo item) {
+        mItemsInvalidated = true;
         View v = mContent.getChildAt(mDragItemPosition[0], mDragItemPosition[1]);
         mContent.removeView(v);
         if (mState == STATE_ANIMATING) {
@@ -610,4 +606,20 @@
             setupContentForNumItems(getItemCount());
         }
     }
+
+    public ArrayList<View> getItemsInReadingOrder() {
+        if (mItemsInvalidated) {
+            mItemsInReadingOrder.clear();
+            for (int j = 0; j < mContent.getCountY(); j++) {
+                for (int i = 0; i < mContent.getCountX(); i++) {
+                    View v = mContent.getChildAt(i, j);
+                    if (v != null) {
+                        mItemsInReadingOrder.add(v);
+                    }
+                }
+            }
+            mItemsInvalidated = false;
+        }
+        return mItemsInReadingOrder;
+    }
 }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index f49297e..2a5a5a0 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -27,6 +29,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.TextView;
@@ -265,13 +268,14 @@
         int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
         canvas.translate(xShift, yShift);
 
-        for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
-                i < mFolder.getItemCount(); i++) {
-            v = (TextView) mFolder.getItemAt(i);
+        ArrayList<View> items = mFolder.getItemsInReadingOrder();
+        int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW);
+        for (int i = firstItemIndex; i < items.size(); i++) {
+            v = (TextView) items.get(i);
             d = v.getCompoundDrawables()[1];
 
             canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
-            canvas.rotate(i == 0 ? ICON_ANGLE : -ICON_ANGLE);
+            canvas.rotate(i == firstItemIndex ? ICON_ANGLE : -ICON_ANGLE);
             canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
 
             if (d != null) {
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 1180106..bd41e02 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -113,8 +113,8 @@
     protected int mPageLayoutWidthGap;
     protected int mPageLayoutHeightGap;
     protected int mPageLayoutMaxHeight;
-    protected int mCellCountX;
-    protected int mCellCountY;
+    protected int mCellCountX = -1;
+    protected int mCellCountY = -1;
     protected boolean mCenterPagesVertically;
     protected boolean mAllowOverScroll = true;
     protected int mUnboundedScrollX;
@@ -1549,7 +1549,7 @@
      */
     public abstract void syncPageItems(int page);
 
-    public void invalidatePageData() {
+    protected void invalidatePageData() {
         if (mContentIsRefreshable) {
             // Update all the pages
             syncPages();
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 9022cac..15b155f 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -79,6 +79,14 @@
         addView(mHolographicChildren);
     }
 
+    public int getCellWidth() {
+        return mCellWidth;
+    }
+
+    public int getCellHeight() {
+        return mCellHeight;
+    }
+
     public void allowHardwareLayerCreation() {
         // This is called after the first time we launch into All Apps. Before that point,
         // there's no need for hardware layers here since there's a hardware layer set on the
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index bc15b32..3f0c54e 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -80,10 +80,6 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
 
-    // This is how much the workspace shrinks when we enter all apps or
-    // customization mode
-    private static final float SHRINK_FACTOR = 0.16f;
-
     // How much the screens shrink when we enter spring loaded drag mode
     private static final float SPRING_LOADED_DRAG_SHRINK_FACTOR = 0.7f;
 
@@ -1512,12 +1508,15 @@
         final int screenWidth = getWidth();
         final int screenHeight = getHeight();
 
+        // How much the workspace shrinks when we enter all apps or customization mode
+        final float shrinkFactor = res.getInteger(R.integer.config_workspaceShrinkPercent) / 100.0f;
+
         // Making the assumption that all pages have the same width as the 0th
         final int pageWidth = getChildAt(0).getMeasuredWidth();
         final int pageHeight = getChildAt(0).getMeasuredHeight();
 
-        final int scaledPageWidth = (int) (SHRINK_FACTOR * pageWidth);
-        final int scaledPageHeight = (int) (SHRINK_FACTOR * pageHeight);
+        final int scaledPageWidth = (int) (shrinkFactor * pageWidth);
+        final int scaledPageHeight = (int) (shrinkFactor * pageHeight);
         final float extraScaledSpacing = res.getDimension(R.dimen.smallScreenExtraSpacing);
 
         final int screenCount = getChildCount();
@@ -1568,20 +1567,21 @@
 
         mAnimator = new AnimatorSet();
 
-        final float[] oldXs = new float[getChildCount()];
-        final float[] oldYs = new float[getChildCount()];
-        final float[] oldScaleXs = new float[getChildCount()];
-        final float[] oldScaleYs = new float[getChildCount()];
-        final float[] oldBackgroundAlphas = new float[getChildCount()];
-        final float[] oldAlphas = new float[getChildCount()];
-        final float[] oldRotationYs = new float[getChildCount()];
-        final float[] newXs = new float[getChildCount()];
-        final float[] newYs = new float[getChildCount()];
-        final float[] newScaleXs = new float[getChildCount()];
-        final float[] newScaleYs = new float[getChildCount()];
-        final float[] newBackgroundAlphas = new float[getChildCount()];
-        final float[] newAlphas = new float[getChildCount()];
-        final float[] newRotationYs = new float[getChildCount()];
+        final int childCount = getChildCount();
+        final float[] oldXs = new float[childCount];
+        final float[] oldYs = new float[childCount];
+        final float[] oldScaleXs = new float[childCount];
+        final float[] oldScaleYs = new float[childCount];
+        final float[] oldBackgroundAlphas = new float[childCount];
+        final float[] oldAlphas = new float[childCount];
+        final float[] oldRotationYs = new float[childCount];
+        final float[] newXs = new float[childCount];
+        final float[] newYs = new float[childCount];
+        final float[] newScaleXs = new float[childCount];
+        final float[] newScaleYs = new float[childCount];
+        final float[] newBackgroundAlphas = new float[childCount];
+        final float[] newAlphas = new float[childCount];
+        final float[] newRotationYs = new float[childCount];
 
         for (int i = 0; i < screenCount; i++) {
             final CellLayout cl = (CellLayout) getChildAt(i);
@@ -1606,15 +1606,15 @@
                 oldRotationYs[i] = cl.getRotationY();
                 newXs[i] = x;
                 newYs[i] = y;
-                newScaleXs[i] = SHRINK_FACTOR * rotationScaleX * extraShrinkFactor;
-                newScaleYs[i] = SHRINK_FACTOR * rotationScaleY * extraShrinkFactor;
+                newScaleXs[i] = shrinkFactor * rotationScaleX * extraShrinkFactor;
+                newScaleYs[i] = shrinkFactor * rotationScaleY * extraShrinkFactor;
                 newBackgroundAlphas[i] = finalAlpha;
                 newRotationYs[i] = rotation;
             } else {
                 cl.setX((int)x);
                 cl.setY((int)y);
-                cl.setScaleX(SHRINK_FACTOR * rotationScaleX * extraShrinkFactor);
-                cl.setScaleY(SHRINK_FACTOR * rotationScaleY * extraShrinkFactor);
+                cl.setScaleX(shrinkFactor * rotationScaleX * extraShrinkFactor);
+                cl.setScaleY(shrinkFactor * rotationScaleY * extraShrinkFactor);
                 cl.setBackgroundAlpha(finalAlpha);
                 cl.setAlpha(finalAlpha);
                 cl.setRotationY(rotation);