Initital changes for new customization drawer/widget tab design.

Change-Id: I160c8777fe2657ab303acfa20934f2e90f9e953e
diff --git a/res/drawable/default_widget_preview.9.png b/res/drawable/default_widget_preview.9.png
index b3ddada..5fedcc8 100644
--- a/res/drawable/default_widget_preview.9.png
+++ b/res/drawable/default_widget_preview.9.png
Binary files differ
diff --git a/res/drawable/widget_divider.png b/res/drawable/widget_divider.png
new file mode 100644
index 0000000..1b453c5
--- /dev/null
+++ b/res/drawable/widget_divider.png
Binary files differ
diff --git a/res/layout-xlarge-land/customization_drawer.xml b/res/layout-xlarge-land/customization_drawer.xml
new file mode 100644
index 0000000..4fcf761
--- /dev/null
+++ b/res/layout-xlarge-land/customization_drawer.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher2.CustomizePagedView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    launcher:widgetCellCountX="16" />
\ No newline at end of file
diff --git a/res/layout-xlarge-port/customization_drawer.xml b/res/layout-xlarge-port/customization_drawer.xml
new file mode 100644
index 0000000..6e4bc4c
--- /dev/null
+++ b/res/layout-xlarge-port/customization_drawer.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher2.CustomizePagedView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    launcher:widgetCellCountX="12" />
\ No newline at end of file
diff --git a/res/layout-xlarge/customize_paged_view_widget.xml b/res/layout-xlarge/customize_paged_view_widget.xml
index da5342b..4d70a12 100644
--- a/res/layout-xlarge/customize_paged_view_widget.xml
+++ b/res/layout-xlarge/customize_paged_view_widget.xml
@@ -13,20 +13,62 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/name"
-    android:layout_width="match_parent"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
     android:layout_height="match_parent"
-    android:gravity="center_horizontal"
-    android:paddingTop="2dip"
+    android:paddingLeft="12.5dp"
+    android:paddingRight="12.5dp"
+    android:paddingTop="40dp"
+    android:paddingBottom="50dp"
+    android:gravity="top"
+    android:orientation="vertical">
 
-    android:textColor="#FFFFFFFF"
-    android:textSize="14sp"
-    android:shadowColor="#FF000000"
-    android:shadowDx="0.0"
-    android:shadowDy="1.0"
-    android:shadowRadius="1.0"
+    <!-- The icon of the widget. -->
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0"
+        android:scaleType="fitStart" />
 
-    android:maxLines="2"
-    android:fadingEdge="horizontal" />
+    <!-- The divider image. -->
+    <ImageView
+        android:id="@+id/divider"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="10dp"
+        android:paddingBottom="10dp"
+        android:src="@drawable/widget_divider" />
+
+    <!-- The name of the widget. -->
+    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="left"
+
+        android:textColor="#FFFFFFFF"
+        android:textSize="14sp"
+        android:shadowColor="#FF000000"
+        android:shadowDx="0.0"
+        android:shadowDy="1.0"
+        android:shadowRadius="1.0"
+
+        android:maxLines="2"
+        android:fadingEdge="horizontal" />
+
+    <!-- The original dimensions of the widget (can't be the same text as above due to different
+         style. -->
+    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/dims"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="left"
+
+        android:textColor="#FF999999"
+        android:textSize="14sp"
+        android:shadowColor="#99000000"
+        android:shadowDx="0.0"
+        android:shadowDy="1.0"
+        android:shadowRadius="1.0" />
+</LinearLayout>
diff --git a/res/layout-xlarge/launcher.xml b/res/layout-xlarge/launcher.xml
index a3c7558..c6acec3 100644
--- a/res/layout-xlarge/launcher.xml
+++ b/res/layout-xlarge/launcher.xml
@@ -128,7 +128,7 @@
     <TabHost
         android:id="@android:id/tabhost"
         android:layout_width="match_parent"
-        android:layout_height="550dip"
+        android:layout_height="500dip"
         android:layout_gravity="bottom">
         <LinearLayout
             android:orientation="vertical"
diff --git a/res/values-xlarge/dimens.xml b/res/values-xlarge/dimens.xml
index 9c65897..4662aad 100644
--- a/res/values-xlarge/dimens.xml
+++ b/res/values-xlarge/dimens.xml
@@ -23,7 +23,7 @@
     <dimen name="smallScreenExtraSpacing">0dip</dimen>
 
     <!-- vertical spacing between edge of screen and mini screen thumbnails -->
-    <dimen name="smallScreenVerticalMargin">20dip</dimen>
+    <dimen name="smallScreenVerticalMargin">60dip</dimen>
 
     <dimen name="toolbar_padding">10dip</dimen>
 
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 09fb0da..8aa6efb 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -64,6 +64,13 @@
         <attr name="cellCountY" />
     </declare-styleable>
 
+    <!-- CustomizePagedView specific attributes. These attributes are used to customize
+         a CustomizePagedView view in XML files. -->
+    <declare-styleable name="CustomizePagedView">
+        <!-- The number of horizontal cells for the widget tab -->
+        <attr name="widgetCellCountX" format="integer" />
+    </declare-styleable>
+
     <!-- DeleteZone specific attributes. These attributes are used to customize
          a DeleteZone view in XML files. -->
     <declare-styleable name="DeleteZone">
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 786300b..d3d11db 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -28,7 +28,9 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
@@ -38,8 +40,13 @@
 import android.provider.LiveFolders;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.launcher.R;
@@ -55,6 +62,27 @@
         WallpaperCustomization
     }
 
+    /**
+     * The linear layout used strictly for the widget tab of the customization tray
+     */
+    private class WidgetLayout extends LinearLayout {
+        public WidgetLayout(Context context) {
+            super(context);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            // We eat up the touch events here, since the PagedView (which uses the same swiping
+            // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
+            // the user is scrolling between pages.  This means that if the pages themselves don't
+            // handle touch events, it gets forwarded up to PagedView itself, and it's own
+            // onTouchEvent() handling will prevent further intercept touch events from being called
+            // (it's the same view in that case).  This is not ideal, but to prevent more changes,
+            // we just always mark the touch event as handled.
+            return super.onTouchEvent(event) || true;
+        }
+    }
+
     private static final String TAG = "CustomizeWorkspace";
     private static final boolean DEBUG = false;
 
@@ -64,33 +92,57 @@
 
     private CustomizationType mCustomizationType;
 
-    private PagedViewCellLayout mTmpWidgetLayout;
-    private ArrayList<ArrayList<PagedViewCellLayout.LayoutParams>> mWidgetPages;
+    // The layout used to emulate the workspace in resolve the cell dimensions of a widget
+    private PagedViewCellLayout mWorkspaceWidgetLayout;
+
+    // The mapping between the pages and the widgets that will be laid out on them
+    private ArrayList<ArrayList<AppWidgetProviderInfo>> mWidgetPages;
+
+    // The max dimensions for the ImageView we use for displaying the widget
+    private int mMaxWidgetWidth;
+
+    // The max number of widget cells to take a "page" of widget
+    private int mMaxWidgetsCellHSpan;
+
+    // The raw sources of data for each of the different tabs of the customization page
     private List<AppWidgetProviderInfo> mWidgetList;
     private List<ResolveInfo> mFolderList;
     private List<ResolveInfo> mShortcutList;
 
-    private int mCellCountX;
-    private int mCellCountY;
+    private static final int sCellCountX = 8;
+    private static final int sCellCountY = 4;
+    private static final int sMinWidgetCellHSpan = 2;
+    private static final int sMaxWidgetCellHSpan = 4;
+
+    // The scale factor for widget previews inside the widget drawer
+    private static final float sScaleFactor = 0.75f;
 
     private final Canvas mCanvas = new Canvas();
     private final LayoutInflater mInflater;
 
     public CustomizePagedView(Context context) {
-        this(context, null);
+        this(context, null, 0);
     }
 
     public CustomizePagedView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mCellCountX = 8;
-        mCellCountY = 4;
+        this(context, attrs, 0);
+    }
+
+    public CustomizePagedView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomizePagedView,
+                defStyle, 0);
         mCustomizationType = CustomizationType.WidgetCustomization;
-        mWidgetPages = new ArrayList<ArrayList<PagedViewCellLayout.LayoutParams>>();
-        mTmpWidgetLayout = new PagedViewCellLayout(context);
+        mWidgetPages = new ArrayList<ArrayList<AppWidgetProviderInfo>>();
+        mWorkspaceWidgetLayout = new PagedViewCellLayout(context);
         mInflater = LayoutInflater.from(context);
-        setupPage(mTmpWidgetLayout);
+        mMaxWidgetsCellHSpan = a.getInt(R.styleable.CustomizePagedView_widgetCellCountX, 8);
+        a.recycle();
+
         setVisibility(View.GONE);
         setSoundEffectsEnabled(false);
+        setupWorkspaceLayout();
     }
 
     public void setLauncher(Launcher launcher) {
@@ -139,6 +191,7 @@
         // reset the icon cache
         mPageViewIconCache.clear();
 
+        // Refresh all the tabs
         invalidatePageData();
     }
 
@@ -166,26 +219,22 @@
         final View animView = v;
         switch (mCustomizationType) {
         case WidgetCustomization:
-            // We assume that the view v is a TextView with a compound drawable on top, and that the
-            // whole text view is centered horizontally and top aligned. We get a more precise
-            // drag point using this information
-            final TextView textView = (TextView) animView;
-            final Drawable[] drawables = textView.getCompoundDrawables();
-            final Drawable icon = drawables[1];
-            int dragPointOffsetX = 0;
-            int dragPointOffsetY = 0;
-            Rect bounds = null;
-            if (icon != null) {
-                bounds = icon.getBounds();
-                bounds.left = (v.getWidth() - bounds.right) / 2;
-                bounds.right += bounds.left;
-            }
+            // Get the icon as the drag representation
+            final LinearLayout l = (LinearLayout) animView;
+            final Drawable icon = ((ImageView) l.findViewById(R.id.icon)).getDrawable();
+            Bitmap b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(),
+                    Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(b);
+            icon.draw(c);
 
             AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo) v.getTag();
             LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(appWidgetInfo.provider);
             dragInfo.minWidth = appWidgetInfo.minWidth;
             dragInfo.minHeight = appWidgetInfo.minHeight;
-            mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY, bounds);
+            mDragController.startDrag(v, b, this, dragInfo, DragController.DRAG_ACTION_COPY, null);
+
+            // Cleanup the icon
+            b.recycle();
             return true;
         case FolderCustomization:
             // animate some feedback to the long press
@@ -236,80 +285,50 @@
         return false;
     }
 
+    /**
+     * Pre-processes the layout of the different widget pages.
+     * @return the number of pages of widgets that we have
+     */
     private int relayoutWidgets() {
-        final int widgetCount = mWidgetList.size();
-        if (widgetCount == 0) return 0;
+        if (mWidgetList.isEmpty()) return 0;
 
+        // create a new page for the first set of widgets
+        ArrayList<AppWidgetProviderInfo> newPage = new ArrayList<AppWidgetProviderInfo>();
         mWidgetPages.clear();
-        ArrayList<PagedViewCellLayout.LayoutParams> page = 
-            new ArrayList<PagedViewCellLayout.LayoutParams>();
-        mWidgetPages.add(page);
-        int rowOffsetX = 0;
-        int rowOffsetY = 0;
-        int curRowHeight = 0;
-        // we only get the cell dims this way for the layout calculations because
-        // we know that we aren't going to change the dims when we construct it
-        // afterwards
+        mWidgetPages.add(newPage);
+
+        // do this until we have no more widgets to lay out
+        final int maxNumCellsPerRow = mMaxWidgetsCellHSpan;
+        final int widgetCount = mWidgetList.size();
+        int numCellsInRow = 0;
         for (int i = 0; i < widgetCount; ++i) {
-            AppWidgetProviderInfo info = mWidgetList.get(i);
-            PagedViewCellLayout.LayoutParams params;
+            final AppWidgetProviderInfo info = mWidgetList.get(i);
 
-            final int cellSpanX = mTmpWidgetLayout.estimateCellHSpan(info.minWidth);
-            final int cellSpanY = mTmpWidgetLayout.estimateCellVSpan(info.minHeight);
+            // determine the size of the current widget
+            int cellSpanX = Math.max(sMinWidgetCellHSpan, Math.min(sMaxWidgetCellHSpan,
+                    mWorkspaceWidgetLayout.estimateCellHSpan(info.minWidth)));
 
-            if (((rowOffsetX + cellSpanX) <= mCellCountX) &&
-                    ((rowOffsetY + cellSpanY) <= mCellCountY)) {
-                // just add to end of current row
-                params = new PagedViewCellLayout.LayoutParams(rowOffsetX, rowOffsetY,
-                        cellSpanX, cellSpanY);
-
-                rowOffsetX += cellSpanX;
-                curRowHeight = Math.max(curRowHeight, cellSpanY);
-            } else {
-                /*
-                // fix all the items in this last row to be bottom aligned
-                int prevRowOffsetX = rowOffsetX;
-                for (int j = page.size() - 1; j >= 0; --j) {
-                    PagedViewCellLayout.LayoutParams params = page.get(j);
-                    // skip once we get to the previous row
-                    if (params.cellX > prevRowOffsetX)
-                        break;
-
-                    params.cellY += curRowHeight - params.cellVSpan;
-                    prevRowOffsetX = params.cellX;
-                }
-                */
-
-                // doesn't fit on current row, see if we can start a new row on
-                // this page
-                if ((rowOffsetY + curRowHeight + cellSpanY) > mCellCountY) {
-                    // start a new page and add this item to it
-                    page = new ArrayList<PagedViewCellLayout.LayoutParams>();
-                    mWidgetPages.add(page);
-
-                    params = new PagedViewCellLayout.LayoutParams(0, 0, cellSpanX, cellSpanY);
-                    rowOffsetX = cellSpanX;
-                    rowOffsetY = 0;
-                    curRowHeight = cellSpanY;
-                } else {
-                    // add it to the current page on this new row
-                    params = new PagedViewCellLayout.LayoutParams(0, rowOffsetY + curRowHeight,
-                            cellSpanX, cellSpanY);
-
-                    rowOffsetX = cellSpanX;
-                    rowOffsetY += curRowHeight;
-                    curRowHeight = cellSpanY;
-                }
+            // create a new page if necessary
+            if ((numCellsInRow + cellSpanX) > maxNumCellsPerRow) {
+                numCellsInRow = 0;
+                newPage = new ArrayList<AppWidgetProviderInfo>();
+                mWidgetPages.add(newPage);
             }
 
-            params.setTag(info);
-            page.add(params);
+            // add the item to the current page
+            newPage.add(info);
+            numCellsInRow += cellSpanX;
         }
+
         return mWidgetPages.size();
     }
 
-    private Drawable getWidgetIcon(PagedViewCellLayout.LayoutParams params, 
-            AppWidgetProviderInfo info) {
+    /**
+     * This method will extract the preview image specified by the widget developer (if it exists),
+     * otherwise, it will try to generate a default image preview with the widget's package icon.
+     * @return the drawable will be used and sized in the ImageView to represent the widget
+     */
+    private Drawable getWidgetIcon(AppWidgetProviderInfo info) {
         PackageManager packageManager = mLauncher.getPackageManager();
         String packageName = info.provider.getPackageName();
         Drawable drawable = null;
@@ -327,15 +346,11 @@
         if (drawable == null) {
             Resources resources = mLauncher.getResources();
 
-            // Determine the size the widget will take in the layout
             // Create a new bitmap to hold the widget preview
-            int[] dims = mTmpWidgetLayout.estimateCellDimensions(getMeasuredWidth(), 
-                    getMeasuredHeight(), params.cellHSpan, params.cellVSpan);
-            final int width = dims[0];
-            final int height = dims[1] - 35;
-            // TEMP
-            // TEMP: HACK ABOVE TO GET TEXT TO SHOW
-            // TEMP
+            final int minDim = mWorkspaceWidgetLayout.estimateCellWidth(1);
+            final int maxDim = mWorkspaceWidgetLayout.estimateCellWidth(3);
+            int width = (int) (Math.max(minDim, Math.min(maxDim, info.minWidth)) * sScaleFactor);
+            int height = (int) (Math.max(minDim, Math.min(maxDim, info.minHeight)) * sScaleFactor);
             Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
             mCanvas.setBitmap(bitmap);
             // For some reason, we must re-set the clip rect here, otherwise it will be wrong
@@ -349,19 +364,16 @@
             try {
                 Rect tmpRect = new Rect();
                 Drawable icon = null;
-                if (info.icon != 0) {
+                if (info.icon > 0) {
                     icon = packageManager.getDrawable(packageName, info.icon, null);
                 } else {
                     icon = resources.getDrawable(R.drawable.ic_launcher_application);
                 }
                 background.getPadding(tmpRect);
 
-                final int iconSize = Math.min(
-                        Math.min(icon.getIntrinsicWidth(), width - tmpRect.left - tmpRect.right),
-                        Math.min(icon.getIntrinsicHeight(), height - tmpRect.top - tmpRect.bottom));
-                final int left = (width / 2) - (iconSize / 2);
-                final int top = (height / 2) - (iconSize / 2);
-                icon.setBounds(new Rect(left, top, left + iconSize, top + iconSize));
+                final int iconSize = minDim / 2;
+                final int offset = iconSize / 4;
+                icon.setBounds(new Rect(offset, offset, offset + iconSize, offset + iconSize));
                 icon.draw(mCanvas);
             } catch (Resources.NotFoundException e) {
                 // if we can't find the icon, then just don't draw it
@@ -374,62 +386,77 @@
     }
 
     private void setupPage(PagedViewCellLayout layout) {
-        layout.setCellCount(mCellCountX, mCellCountY);
+        layout.setCellCount(sCellCountX, sCellCountY);
         layout.setPadding(20, 10, 20, 0);
     }
 
+    private void setupWorkspaceLayout() {
+        mWorkspaceWidgetLayout.setCellCount(sCellCountX, sCellCountY);
+        mWorkspaceWidgetLayout.setPadding(20, 10, 20, 0);
+
+        mMaxWidgetWidth = mWorkspaceWidgetLayout.estimateCellWidth(sMaxWidgetCellHSpan);
+    }
+
     private void syncWidgetPages() {
         if (mWidgetList == null) return;
 
-        // calculate the layout for all the widget pages first and ensure that
-        // we have the right number of pages
+        // we need to repopulate with the LinearLayout layout for the widget pages
+        removeAllViews();
         int numPages = relayoutWidgets();
-        int curNumPages = getChildCount();
-        // remove any extra pages after the "last" page
-        int extraPageDiff = curNumPages - numPages;
-        for (int i = 0; i < extraPageDiff; ++i) {
-            removeViewAt(numPages);
-        }
-        // add any necessary pages
-        for (int i = curNumPages; i < numPages; ++i) {
-            PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
-            setupPage(layout);
-            addView(layout);
+        for (int i = 0; i < numPages; ++i) {
+            LinearLayout layout = new WidgetLayout(getContext());
+            layout.setGravity(Gravity.CENTER_HORIZONTAL);
+
+            // Temporary change to prevent the last page from being too small (and items bleeding
+            // onto it).  We can remove this once we properly fix the fading algorithm
+            if (i < numPages - 1) {
+                addView(layout, new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.WRAP_CONTENT,
+                        LinearLayout.LayoutParams.MATCH_PARENT));
+            } else {
+                addView(layout, new LinearLayout.LayoutParams(
+                        LinearLayout.LayoutParams.MATCH_PARENT,
+                        LinearLayout.LayoutParams.MATCH_PARENT));
+            }
         }
     }
 
     private void syncWidgetPageItems(int page) {
         // ensure that we have the right number of items on the pages
-        PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
-        final ArrayList<PagedViewCellLayout.LayoutParams> list = mWidgetPages.get(page);
+        LinearLayout layout = (LinearLayout) getChildAt(page);
+        final ArrayList<AppWidgetProviderInfo> list = mWidgetPages.get(page);
         final int count = list.size();
         layout.removeAllViews();
         for (int i = 0; i < count; ++i) {
-            PagedViewCellLayout.LayoutParams params = list.get(i);
-            AppWidgetProviderInfo info = (AppWidgetProviderInfo) params.getTag();
-            final Drawable icon = getWidgetIcon(params, info);
-            TextView text = (TextView) mInflater.inflate(R.layout.customize_paged_view_widget, 
-                    layout, false);
-            text.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
-            text.setText(info.label);
-            text.setTag(info);
-            text.setOnLongClickListener(this);
+            AppWidgetProviderInfo info = (AppWidgetProviderInfo) list.get(i);
+            LinearLayout l = (LinearLayout) mInflater.inflate(
+                    R.layout.customize_paged_view_widget, layout, false);
+            l.setTag(info);
+            l.setOnLongClickListener(this);
 
-            layout.addViewToCellLayout(text, -1, mWidgetList.indexOf(info), params);
+            final Drawable icon = getWidgetIcon(info);
+            final int hSpan = mWorkspaceWidgetLayout.estimateCellHSpan(info.minWidth);
+            final int vSpan = mWorkspaceWidgetLayout.estimateCellHSpan(info.minHeight);
+
+            ImageView image = (ImageView) l.findViewById(R.id.icon);
+            image.setMaxWidth(mMaxWidgetWidth);
+            image.setImageDrawable(icon);
+            TextView name = (TextView) l.findViewById(R.id.name);
+            name.setText(info.label);
+            TextView dims = (TextView) l.findViewById(R.id.dims);
+            dims.setText("" + hSpan + " x " + vSpan);
+
+            layout.addView(l);
         }
     }
 
     private void syncListPages(List<ResolveInfo> list) {
+        // we need to repopulate with PagedViewCellLayouts
+        removeAllViews();
+
         // ensure that we have the right number of pages
-        int numPages = (int) Math.ceil((float) list.size() / (mCellCountX * mCellCountY));
-        int curNumPages = getChildCount();
-        // remove any extra pages after the "last" page
-        int extraPageDiff = curNumPages - numPages;
-        for (int i = 0; i < extraPageDiff; ++i) {
-            removeViewAt(numPages);
-        }
-        // add any necessary pages
-        for (int i = curNumPages; i < numPages; ++i) {
+        int numPages = (int) Math.ceil((float) list.size() / (sCellCountX * sCellCountY));
+        for (int i = 0; i < numPages; ++i) {
             PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
             setupPage(layout);
             addView(layout);
@@ -438,7 +465,7 @@
 
     private void syncListPageItems(int page, List<ResolveInfo> list) {
         // ensure that we have the right number of items on the pages
-        int numCells = mCellCountX * mCellCountY;
+        int numCells = sCellCountX * sCellCountY;
         int startIndex = page * numCells;
         int endIndex = Math.min(startIndex + numCells, list.size());
         PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
@@ -452,24 +479,22 @@
             icon.setOnLongClickListener(this);
 
             final int index = i - startIndex;
-            final int x = index % mCellCountX;
-            final int y = index / mCellCountX;
+            final int x = index % sCellCountX;
+            final int y = index / sCellCountX;
+            setupPage(layout);
             layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
         }
     }
 
     private void syncWallpaperPages() {
         // NOT CURRENTLY IMPLEMENTED
-        // ensure that we have the right number of pages
-        int numPages = 1;
-        int curNumPages = getChildCount();
-        // remove any extra pages after the "last" page
-        int extraPageDiff = curNumPages - numPages;
-        for (int i = 0; i < extraPageDiff; ++i) {
-            removeViewAt(numPages);
-        }
+
+        // we need to repopulate with PagedViewCellLayouts
+        removeAllViews();
+
         // add any necessary pages
-        for (int i = curNumPages; i < numPages; ++i) {
+        int numPages = 1;
+        for (int i = 0; i < numPages; ++i) {
             PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
             setupPage(layout);
             addView(layout);
@@ -485,23 +510,28 @@
         // NOTE: this is just place holder text until MikeJurka implements wallpaper picker
         text.setText("Wallpaper customization coming soon!");
 
+        setupPage(layout);
         layout.addViewToCellLayout(text, -1, 0, new PagedViewCellLayout.LayoutParams(0, 0, 3, 1));
     }
 
     @Override
     public void syncPages() {
+        boolean centerPagedViewCellLayouts = false;
         switch (mCustomizationType) {
         case WidgetCustomization:
             syncWidgetPages();
             break;
         case FolderCustomization:
             syncListPages(mFolderList);
+            centerPagedViewCellLayouts = true;
             break;
         case ShortcutCustomization:
             syncListPages(mShortcutList);
+            centerPagedViewCellLayouts = true;
             break;
         case WallpaperCustomization:
             syncWallpaperPages();
+            centerPagedViewCellLayouts = true;
             break;
         default:
             removeAllViews();
@@ -511,13 +541,15 @@
 
         // only try and center the page if there is one page
         final int childCount = getChildCount();
-        if (childCount == 1) {
-            PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(0);
-            layout.enableCenteredContent(true);
-        } else {
-            for (int i = 0; i < childCount; ++i) {
-                PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
-                layout.enableCenteredContent(false);
+        if (centerPagedViewCellLayouts) {
+            if (childCount == 1) {
+                PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(0);
+                layout.enableCenteredContent(true);
+            } else {
+                for (int i = 0; i < childCount; ++i) {
+                    PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+                    layout.enableCenteredContent(false);
+                }
             }
         }
 
@@ -542,4 +574,11 @@
             break;
         }
     }
+
+    protected int getAssociatedLowerPageBound(int page) {
+        return 0;
+    }
+    protected int getAssociatedUpperPageBound(int page) {
+        return getChildCount();
+    }
 }
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index e18470a..7fc905b 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -134,7 +134,7 @@
         void onDragStart(DragSource source, Object info, int dragAction);
         
         /**
-         * The drag has eneded
+         * The drag has ended
          */
         void onDragEnd();
     }
@@ -202,6 +202,35 @@
     /**
      * Starts a drag.
      *
+     * @param v The view that is being dragged
+     * @param bmp The bitmap that represents the view being dragged
+     * @param source An object representing where the drag originated
+     * @param dragInfo The data associated with the object that is being dragged
+     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+     *        {@link #DRAG_ACTION_COPY}
+     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
+     */
+    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
+            Rect dragRegion) {
+        mOriginator = v;
+
+        int[] loc = mCoordinatesTemp;
+        v.getLocationOnScreen(loc);
+        int screenX = loc[0];
+        int screenY = loc[1];
+
+        startDrag(bmp, screenX, screenY, 0, 0, bmp.getWidth(), bmp.getHeight(),
+                source, dragInfo, dragAction, dragRegion);
+
+        if (dragAction == DRAG_ACTION_MOVE) {
+            v.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Starts a drag.
+     *
      * @param b The bitmap to display as the drag image.  It will be re-scaled to the
      *          enlarged size.
      * @param screenX The x position on screen of the left-top of the bitmap.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index c5450f3..8eece96 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -281,7 +281,8 @@
             mHomeCustomizationDrawer.setup();
 
             // share the same customization workspace across all the tabs
-            mCustomizePagedView = new CustomizePagedView(this);
+            mCustomizePagedView = (CustomizePagedView) mInflater.inflate(
+                    R.layout.customization_drawer, mHomeCustomizationDrawer, false);
             TabContentFactory contentFactory = new TabContentFactory() {
                 public View createTabContent(String tag) {
                     return mCustomizePagedView;
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 1e0dad4..0772c0a 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -16,7 +16,8 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashMap;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -25,6 +26,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.ActionMode;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -33,13 +35,13 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
 import android.widget.Checkable;
+import android.widget.LinearLayout;
 import android.widget.Scroller;
 
-import java.util.ArrayList;
-import java.util.HashMap;
+import com.android.launcher.R;
 
 /**
  * An abstraction of the original Workspace which supports browsing through a
@@ -345,7 +347,7 @@
         final int childCount = getChildCount();
         int childLeft = 0;
         if (childCount > 0) {
-            childLeft = (getMeasuredWidth() - getChildAt(0).getMeasuredWidth()) / 2;
+            childLeft = getRelativeChildOffset(0);
         }
 
         for (int i = 0; i < childCount; i++) {
@@ -360,11 +362,12 @@
         }
     }
 
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
+    protected void updateAdjacentPagesAlpha() {
         if (mFadeInAdjacentScreens) {
             if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
-                int screenCenter = mScrollX + (getMeasuredWidth() / 2);
+                int halfScreenSize = getMeasuredWidth() / 2;
+                int screenCenter = mScrollX + halfScreenSize;
+
                 final int childCount = getChildCount();
                 for (int i = 0; i < childCount; ++i) {
                     View layout = (View) getChildAt(i);
@@ -389,9 +392,13 @@
                 mDirtyPageAlpha = false;
             }
         }
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        updateAdjacentPagesAlpha();
 
         // Find out which screens are visible; as an optimization we only call draw on them
-
         // As an optimization, this code assumes that all pages have the same width as the 0th
         // page.
         final int pageCount = getChildCount();
@@ -591,11 +598,11 @@
                 if ((mTouchState != TOUCH_STATE_PREV_PAGE) &&
                         (mTouchState != TOUCH_STATE_NEXT_PAGE)) {
                     if (getChildCount() > 0) {
-                        int relativeChildLeft = getChildOffset(0);
-                        int relativeChildRight = relativeChildLeft + getChildAt(0).getMeasuredWidth();
-                        if (x < relativeChildLeft) {
+                        int width = getMeasuredWidth();
+                        int offset = getRelativeChildOffset(mCurrentPage);
+                        if (x < offset) {
                             mTouchState = TOUCH_STATE_PREV_PAGE;
-                        } else if (x > relativeChildRight) {
+                        } else if (x > (width - offset)) {
                             mTouchState = TOUCH_STATE_NEXT_PAGE;
                         }
                     }
@@ -842,6 +849,19 @@
         }
     }
 
+    protected int getChildIndexForRelativeOffset(int relativeOffset) {
+        final int childCount = getChildCount();
+        int left = getRelativeChildOffset(0);
+        for (int i = 0; i < childCount; ++i) {
+            final int right = (left + getChildAt(i).getMeasuredWidth());
+            if (left <= relativeOffset && relativeOffset <= right) {
+                return i;
+            }
+            left = right;
+        }
+        return -1;
+    }
+
     protected int getRelativeChildOffset(int index) {
         return (getMeasuredWidth() - getChildAt(index).getMeasuredWidth()) / 2;
     }
@@ -889,7 +909,6 @@
     protected void snapToPage(int whichPage, int duration) {
         whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
 
-
         int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         final int sX = getScrollX();
         final int delta = newX - sX;
@@ -1015,8 +1034,8 @@
         if (mContentIsRefreshable) {
             final int count = getChildCount();
             if (page < count) {
-                int lowerPageBound = Math.max(0, page - 1);
-                int upperPageBound = Math.min(page + 1, count - 1);
+                int lowerPageBound = getAssociatedLowerPageBound(page);
+                int upperPageBound = getAssociatedUpperPageBound(page);
                 for (int i = 0; i < count; ++i) {
                     final ViewGroup layout = (ViewGroup) getChildAt(i);
                     final int childCount = layout.getChildCount();
@@ -1036,6 +1055,14 @@
         }
     }
 
+    protected int getAssociatedLowerPageBound(int page) {
+        return Math.max(0, page - 1);
+    }
+    protected int getAssociatedUpperPageBound(int page) {
+        final int count = getChildCount();
+        return Math.min(page + 1, count - 1);
+    }
+
     protected void startChoiceMode(int mode, ActionMode.Callback callback) {
         if (isChoiceMode(CHOICE_MODE_NONE)) {
             mChoiceMode = mode;
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 219a362..b247a06 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -252,6 +252,16 @@
         requestLayout();
     }
 
+    public void setCellDimensions(int width, int height) {
+        mCellWidth = width;
+        mCellHeight = height;
+        requestLayout();
+    }
+
+    public int getDefaultCellDimensions() {
+        return sDefaultCellDimensions;
+    }
+
     private void setChildrenAlpha(float alpha) {
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -281,37 +291,36 @@
         lp.isDragging = true;
     }
 
+    /**
+     * Estimates the number of cells that the specified width would take up.
+     */
     public int estimateCellHSpan(int width) {
+        // TODO: we need to take widthGap into effect
         return (width + mCellWidth) / mCellWidth;
     }
+
+    /**
+     * Estimates the number of cells that the specified height would take up.
+     */
     public int estimateCellVSpan(int height) {
+        // TODO: we need to take heightGap into effect
         return (height + mCellHeight) / mCellHeight;
     }
-    public int[] estimateCellDimensions(int approxWidth, int approxHeight, 
-            int cellHSpan, int cellVSpan) {
-        // NOTE: we are disabling this until we find a good way to approximate this without fully
-        // measuring
-        /*
-        // we may want to use this before any measuring/layout happens, so we pass in an approximate
-        // size for the layout
-        int numWidthGaps = mCellCountX - 1;
-        int numHeightGaps = mCellCountY - 1;
-        int hSpaceLeft = approxWidth - mPaddingLeft
-            - mPaddingRight - (mCellWidth * mCellCountX);
-        int vSpaceLeft = approxHeight - mPaddingTop
-            - mPaddingBottom - (mCellHeight * mCellCountY);
-        int widthGap = hSpaceLeft / numWidthGaps;
-        int heightGap = vSpaceLeft / numHeightGaps;
-        int minGap = Math.min(widthGap, heightGap);
-        return new int[] {
-            (cellHSpan * mCellWidth) + ((cellHSpan - 1) * minGap),
-            (cellVSpan * mCellHeight) + ((cellVSpan - 1) * minGap)
-        };
-        */
-        return new int[] {
-            (cellHSpan * mCellWidth),
-            (cellVSpan * mCellHeight)
-        };
+
+    /**
+     * Estimates the width that the number of vSpan cells will take up.
+     */
+    public int estimateCellWidth(int hSpan) {
+        // TODO: we need to take widthGap into effect
+        return hSpan * mCellWidth;
+    }
+
+    /**
+     * Estimates the height that the number of vSpan cells will take up.
+     */
+    public int estimateCellHeight(int vSpan) {
+        // TODO: we need to take heightGap into effect
+        return vSpan * mCellHeight;
     }
 
     @Override