supporting swipable home screens on xlarge devices

- icons and widgets on home screens can be "dimmed"
- celllayout no longer renders a dimmed version of itself, but instead its children make dimmed versions of themselves
- celllayout no longer always takes up full size of workspace, in landscape mode 
neighboring screens (celllayouts) are visible
- on xlarge devices, in landscape mode side screens are "dimmed"
- moved holographic outline helper to its own file
- fixed bug where mini-screens were still able to scroll left/right

Change-Id: I9e85ab4147edfae1e7525c3d11d42be3fabf4f6d
diff --git a/proguard.flags b/proguard.flags
index aa75f4a..82411eb 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -9,8 +9,8 @@
 }
 
 -keep class com.android.launcher2.CellLayout {
-  public float getDimmedBitmapAlpha();
-  public void setDimmedBitmapAlpha(float);
+  public float getBackgroundAlpha();
+  public void setBackgroundAlpha(float);
 }
 
 -keep class com.android.launcher2.AllApps3D$Defines {
diff --git a/res/layout-land/application.xml b/res/layout-land/application.xml
index 6de5658..846c81c 100644
--- a/res/layout-land/application.xml
+++ b/res/layout-land/application.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 
-<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- 	style="@style/WorkspaceIcon.Landscape" />
+<com.android.launcher2.DimmableBubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+   style="@style/WorkspaceIcon.Landscape" />
diff --git a/res/layout-port/application.xml b/res/layout-port/application.xml
index f904a66..ec66976 100644
--- a/res/layout-port/application.xml
+++ b/res/layout-port/application.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 
-<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher2.DimmableBubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
  	style="@style/WorkspaceIcon.Portrait" />
diff --git a/res/layout-xlarge-land/workspace_screen.xml b/res/layout-xlarge-land/workspace_screen.xml
index 15fc3b1..f358443 100644
--- a/res/layout-xlarge-land/workspace_screen.xml
+++ b/res/layout-xlarge-land/workspace_screen.xml
@@ -18,13 +18,13 @@
     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"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:hapticFeedbackEnabled="false"
 
     launcher:cellWidth="@dimen/workspace_cell_width"
     launcher:cellHeight="@dimen/workspace_cell_height"
     launcher:yAxisStartPadding="40dip"
     launcher:yAxisEndPadding="40dip"
-    launcher:xAxisStartPadding="256dip"
-    launcher:xAxisEndPadding="256dip" />
+    launcher:xAxisStartPadding="40dip"
+    launcher:xAxisEndPadding="40dip" />
diff --git a/res/layout-xlarge-port/workspace_screen.xml b/res/layout-xlarge-port/workspace_screen.xml
index eb7620c..7314e60 100644
--- a/res/layout-xlarge-port/workspace_screen.xml
+++ b/res/layout-xlarge-port/workspace_screen.xml
@@ -18,13 +18,13 @@
     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"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:hapticFeedbackEnabled="false"
 
     launcher:cellWidth="@dimen/workspace_cell_width"
     launcher:cellHeight="@dimen/workspace_cell_height"
-    launcher:yAxisStartPadding="172dip"
-    launcher:yAxisEndPadding="172dip"
+    launcher:yAxisStartPadding="40dip"
+    launcher:yAxisEndPadding="40dip"
     launcher:xAxisStartPadding="40dip"
     launcher:xAxisEndPadding="40dip"/>
diff --git a/res/values-xlarge/colors.xml b/res/values-xlarge/colors.xml
index a6cdd06..d4c6fad 100644
--- a/res/values-xlarge/colors.xml
+++ b/res/values-xlarge/colors.xml
@@ -18,4 +18,5 @@
 -->
 <resources>
     <color name="app_info_filter">#A50000FE</color>
+    <color name="dimmed_view_color">#FF7F7F7F</color>
 </resources>
\ No newline at end of file
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 8cf7041..4d1c299 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -22,12 +22,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -37,17 +32,13 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.View.OnTouchListener;
 import android.view.animation.Animation;
 import android.view.animation.LayoutAnimationController;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 
 public class CellLayout extends ViewGroup {
     static final String TAG = "CellLayout";
-    // we make the dimmed bitmap smaller than the screen itself for memory + perf reasons
-    static final float DIMMED_BITMAP_SCALE = 0.25f;
 
     private boolean mPortrait;
 
@@ -77,17 +68,10 @@
 
     private OnTouchListener mInterceptTouchListener;
 
-    // this is what the home screen fades to when it shrinks
-    //   (ie in all apps and in home screen customize mode)
-    private Bitmap mDimmedBitmap;
-    private Canvas mDimmedBitmapCanvas;
-    private float mDimmedBitmapAlpha;
-    private boolean mDimmedBitmapDirty = false;
-    private final Paint mDimmedBitmapPaint = new Paint();
-    private final Rect mLayoutRect = new Rect();
-    private final Rect mDimmedBitmapRect = new Rect();
-    private Drawable mDimmedBitmapBackground;
-    private Drawable mDimmedBitmapBackgroundHover;
+    private float mBackgroundAlpha;
+    private final Rect mBackgroundLayoutRect = new Rect();
+    private Drawable mBackground;
+    private Drawable mBackgroundHover;
     // If we're actively dragging something over this screen and it's small,
     // mHover is true
     private boolean mHover = false;
@@ -129,13 +113,10 @@
         mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
 
         if (LauncherApplication.isScreenXLarge()) {
-            mDimmedBitmapBackground = getResources().getDrawable(
-                    R.drawable.mini_home_screen_bg);
-            mDimmedBitmapBackground.setFilterBitmap(true);
-
-            mDimmedBitmapBackgroundHover = getResources().getDrawable(
-                    R.drawable.mini_home_screen_bg_hover);
-            mDimmedBitmapBackgroundHover.setFilterBitmap(true);
+            mBackground = getResources().getDrawable(R.drawable.mini_home_screen_bg);
+            mBackground.setFilterBitmap(true);
+            mBackgroundHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
+            mBackgroundHover.setFilterBitmap(true);
         }
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
@@ -160,8 +141,6 @@
         setAlwaysDrawnWithCacheEnabled(false);
 
         mWallpaperManager = WallpaperManager.getInstance(getContext());
-
-        mDimmedBitmapPaint.setFilterBitmap(true);
     }
 
     public void setHover(boolean value) {
@@ -173,9 +152,9 @@
 
     @Override
     public void dispatchDraw(Canvas canvas) {
-        if (mDimmedBitmapAlpha > 0.0f) {
-            final Drawable bg = mHover ? mDimmedBitmapBackgroundHover : mDimmedBitmapBackground;
-            bg.setAlpha((int) (mDimmedBitmapAlpha * 255));
+        if (mBackgroundAlpha > 0.0f) {
+            final Drawable bg = mHover ? mBackgroundHover : mBackground;
+            bg.setAlpha((int) (mBackgroundAlpha * 255));
             bg.draw(canvas);
         }
         super.dispatchDraw(canvas);
@@ -191,15 +170,7 @@
                     (int)mDragRect.bottom);
             mDragRectDrawable.draw(canvas);
         }
-        if (mDimmedBitmap != null && mDimmedBitmapAlpha > 0.0f) {
-            if (mDimmedBitmapDirty) {
-                updateDimmedBitmap();
-                mDimmedBitmapDirty = false;
-            }
-            mDimmedBitmapPaint.setAlpha((int) (mDimmedBitmapAlpha * 255));
-
-            //canvas.drawBitmap(mDimmedBitmap, mDimmedBitmapRect, mLayoutRect, mDimmedBitmapPaint);
-        }
+        super.onDraw(canvas);
     }
 
     @Override
@@ -242,24 +213,16 @@
 
             // We might be in the middle or end of shrinking/fading to a dimmed view
             // Make sure this view's alpha is set the same as all the rest of the views
-            //child.setAlpha(1.0f - mDimmedBitmapAlpha);
+            child.setAlpha(getAlpha());
 
             addView(child, index, lp);
 
-            // next time we draw the dimmed bitmap we need to update it
-            mDimmedBitmapDirty = true;
             return true;
         }
         return false;
     }
 
     @Override
-    public void removeView(View view) {
-        super.removeView(view);
-        mDimmedBitmapDirty = true;
-    }
-
-    @Override
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
         if (child != null) {
@@ -544,6 +507,10 @@
                 - mRightPadding - (cellWidth * mCountX);
         mWidthGap = hSpaceLeft / numWidthGaps;
 
+        // center it around the min gaps
+        int minGap = Math.min(mWidthGap, mHeightGap);
+        mWidthGap = mHeightGap = minGap;
+
         int count = getChildCount();
 
         for (int i = 0; i < count; i++) {
@@ -559,8 +526,15 @@
 
             child.measure(childWidthMeasureSpec, childheightMeasureSpec);
         }
-
-        setMeasuredDimension(widthSpecSize, heightSpecSize);
+        if (widthSpecMode == MeasureSpec.AT_MOST) {
+            int newWidth = mLeftPadding + mRightPadding + (mCountX * cellWidth) +
+                ((mCountX - 1) * minGap);
+            int newHeight = mTopPadding + mBottomPadding + (mCountY * cellHeight) +
+                ((mCountY - 1) * minGap);
+            setMeasuredDimension(newWidth, newHeight);
+        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
+            setMeasuredDimension(widthSpecSize, heightSpecSize);
+        }
     }
 
     @Override
@@ -593,13 +567,12 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mLayoutRect.set(0, 0, w, h);
-        mDimmedBitmapRect.set(0, 0, (int) (DIMMED_BITMAP_SCALE * w), (int) (DIMMED_BITMAP_SCALE * h));
-        if (mDimmedBitmapBackground != null) {
-            mDimmedBitmapBackground.setBounds(mLayoutRect);
+        mBackgroundLayoutRect.set(0, 0, w, h);
+        if (mBackground != null) {
+            mBackground.setBounds(mBackgroundLayoutRect);
         }
-        if (mDimmedBitmapBackgroundHover != null) {
-            mDimmedBitmapBackgroundHover.setBounds(mLayoutRect);
+        if (mBackgroundHover != null) {
+            mBackgroundHover.setBounds(mBackgroundLayoutRect);
         }
     }
 
@@ -619,22 +592,28 @@
         super.setChildrenDrawnWithCacheEnabled(enabled);
     }
 
-    public float getDimmedBitmapAlpha() {
-        return mDimmedBitmapAlpha;
+    public float getBackgroundAlpha() {
+        return mBackgroundAlpha;
     }
 
-    public void setDimmedBitmapAlpha(float alpha) {
-        // If we're dimming the screen after it was not dimmed, refresh
-        // to allow for updated widgets. We don't continually refresh it
-        // after this point, however, as an optimization
-        if (mDimmedBitmapAlpha == 0.0f && alpha > 0.0f) {
-            updateDimmedBitmap();
-        }
-        mDimmedBitmapAlpha = alpha;
-        //setChildrenAlpha(1.0f - mDimmedBitmapAlpha);
+    public void setBackgroundAlpha(float alpha) {
+        mBackgroundAlpha = alpha;
         invalidate();
     }
 
+    // Need to return true to let the view system know we know how to handle alpha-- this is
+    // because when our children have an alpha of 0.0f, they are still rendering their "dimmed"
+    // versions
+    @Override
+    protected boolean onSetAlpha(int alpha) {
+        return true;
+    }
+
+    public void setAlpha(float alpha) {
+        setChildrenAlpha(alpha);
+        super.setAlpha(alpha);
+    }
+
     private void setChildrenAlpha(float alpha) {
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -642,27 +621,6 @@
         }
     }
 
-    public void updateDimmedBitmap() {
-        if (mDimmedBitmap == null) {
-            mDimmedBitmap = Bitmap.createBitmap((int) (getWidth() * DIMMED_BITMAP_SCALE),
-                    (int) (getHeight() * DIMMED_BITMAP_SCALE), Bitmap.Config.ARGB_8888);
-            mDimmedBitmapCanvas = new Canvas(mDimmedBitmap);
-            mDimmedBitmapCanvas.scale(DIMMED_BITMAP_SCALE, DIMMED_BITMAP_SCALE);
-        }
-        // clear the canvas
-        mDimmedBitmapCanvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
-
-        // draw the screen into the bitmap
-        // just for drawing to the bitmap, make all the items on the screen opaque
-        //setChildrenAlpha(1.0f);
-        // call our superclass's dispatchdraw so we don't draw the background
-        super.dispatchDraw(mDimmedBitmapCanvas);
-        //setChildrenAlpha(1.0f - mDimmedBitmapAlpha);
-
-        // replace all colored areas with a dark  (semi-transparent black)
-        mDimmedBitmapCanvas.drawColor(Color.argb(160, 0, 0, 0), PorterDuff.Mode.SRC_IN);
-    }
-
     private boolean isVacant(int originX, int originY, int spanX, int spanY) {
         for (int i = 0; i < spanY; i++) {
             if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) {
diff --git a/src/com/android/launcher2/DimmableAppWidgetHostView.java b/src/com/android/launcher2/DimmableAppWidgetHostView.java
new file mode 100644
index 0000000..7a1d4f9
--- /dev/null
+++ b/src/com/android/launcher2/DimmableAppWidgetHostView.java
@@ -0,0 +1,147 @@
+/*
+ * 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 com.android.launcher.R;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.view.View;
+
+public class DimmableAppWidgetHostView extends LauncherAppWidgetHostView {
+    public DimmableAppWidgetHostView(Context context) {
+        super(context);
+        mPaint.setFilterBitmap(true);
+    }
+
+    private final Paint mPaint = new Paint();
+    private int mAlpha;
+    private int mDimmedAlpha;
+    private Bitmap mDimmedView;
+    private Canvas mDimmedViewCanvas;
+    private boolean isDimmedViewUpdatePass;
+
+    private static float cubic(float r) {
+        return (float) (Math.pow(r-1, 3) + 1);
+    }
+
+    /**
+     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
+     * pages.
+     */
+    public static float highlightAlphaInterpolator(float r) {
+        final float pivot = 0.3f;
+        if (r < pivot) {
+            return Math.max(0.5f, 0.65f*cubic(r/pivot));
+        } else {
+            return Math.min(1.0f, 0.65f*cubic(1 - (r-pivot)/(1-pivot)));
+        }
+    }
+
+    /**
+     * Returns the interpolated view alpha for the effect we want when scrolling pages.
+     */
+    public static float viewAlphaInterpolator(float r) {
+        final float pivot = 0.6f;
+        if (r < pivot) {
+            return r/pivot;
+        } else {
+            return 1.0f;
+        }
+    }
+
+    private void setChildAlpha(float alpha) {
+        if (getChildCount() > 0) {
+            final View child = getChildAt(0);
+            if (child.getAlpha() != alpha) {
+                getChildAt(0).setAlpha(alpha);
+            }
+        }
+    }
+
+    private void updateChildAlpha() {
+        // hacky, but sometimes widgets get their alpha set back to 1.0f, so we call
+        // this to force them back
+        setChildAlpha(getAlpha());
+    }
+
+    @Override
+    public boolean onSetAlpha(int alpha) {
+        super.onSetAlpha(alpha);
+        return true;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        final float viewAlpha = viewAlphaInterpolator(alpha);
+        final float dimmedAlpha = highlightAlphaInterpolator(alpha);
+        mAlpha = (int) (viewAlpha * 255);
+        mDimmedAlpha = (int) (dimmedAlpha * 255);
+        super.setAlpha(viewAlpha);
+        setChildAlpha(viewAlpha);
+    }
+
+    private void updateDimmedView() {
+        if (mDimmedView == null) {
+            mDimmedView = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
+                    Bitmap.Config.ARGB_8888);
+            mDimmedViewCanvas = new Canvas(mDimmedView);
+        }
+        mDimmedViewCanvas.drawColor(0x00000000);
+        mDimmedViewCanvas.concat(getMatrix());
+        isDimmedViewUpdatePass = true;
+        draw(mDimmedViewCanvas);
+        // make the bitmap look "dimmed"
+        int dimmedColor = getContext().getResources().getColor(R.color.dimmed_view_color);
+        mDimmedViewCanvas.drawColor(dimmedColor, PorterDuff.Mode.SRC_IN);
+        isDimmedViewUpdatePass = false;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mDimmedView == null && mDimmedAlpha > 0.0f) {
+            updateDimmedView();
+        }
+    }
+
+    @Override
+    public void dispatchDraw(Canvas canvas) {
+        if (isDimmedViewUpdatePass) {
+            final float alpha = getAlpha();
+            canvas.save();
+            setAlpha(1.0f);
+            super.dispatchDraw(canvas);
+            canvas.restore();
+            setAlpha(alpha);
+        } else {
+            if (mDimmedView != null && mDimmedAlpha > 0) {
+                // draw the dimmed version of this widget
+                mPaint.setAlpha(mDimmedAlpha);
+                canvas.drawBitmap(mDimmedView, 0, 0, mPaint);
+            }
+
+            updateChildAlpha();
+            super.dispatchDraw(canvas);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/DimmableBubbleTextView.java b/src/com/android/launcher2/DimmableBubbleTextView.java
new file mode 100644
index 0000000..66cc97a
--- /dev/null
+++ b/src/com/android/launcher2/DimmableBubbleTextView.java
@@ -0,0 +1,137 @@
+/*
+ * 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 com.android.launcher.R;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+
+public class DimmableBubbleTextView extends BubbleTextView {
+    private  Paint mDimmedPaint = new Paint();
+    private int mAlpha;
+    private int mDimmedAlpha;
+    private Bitmap mDimmedView;
+    private Canvas mDimmedViewCanvas;
+    private boolean isDimmedViewUpdatePass;
+
+    public DimmableBubbleTextView(Context context) {
+        super(context);
+        mDimmedPaint.setFilterBitmap(true);
+    }
+
+    public DimmableBubbleTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDimmedPaint.setFilterBitmap(true);
+    }
+
+    public DimmableBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mDimmedPaint.setFilterBitmap(true);
+    }
+
+    private static float cubic(float r) {
+        return (float) (Math.pow(r-1, 3) + 1);
+    }
+
+    /**
+     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
+     * pages.
+     */
+    public static float highlightAlphaInterpolator(float r) {
+        final float pivot = 0.3f;
+        if (r < pivot) {
+            return Math.max(0.5f, 0.65f*cubic(r/pivot));
+        } else {
+            return Math.min(1.0f, 0.65f*cubic(1 - (r-pivot)/(1-pivot)));
+        }
+    }
+
+    /**
+     * Returns the interpolated view alpha for the effect we want when scrolling pages.
+     */
+    public static float viewAlphaInterpolator(float r) {
+        final float pivot = 0.6f;
+        if (r < pivot) {
+            return r/pivot;
+        } else {
+            return 1.0f;
+        }
+    }
+
+    @Override
+    public boolean onSetAlpha(int alpha) {
+        super.onSetAlpha(alpha);
+        return true;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        final float viewAlpha = viewAlphaInterpolator(alpha);
+        final float dimmedAlpha = highlightAlphaInterpolator(alpha);
+        mAlpha = (int) (viewAlpha * 255);
+        mDimmedAlpha = (int) (dimmedAlpha * 255);
+        super.setAlpha(viewAlpha);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mDimmedView == null) {
+            isDimmedViewUpdatePass = true;
+            mDimmedView = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
+                    Bitmap.Config.ARGB_8888);
+            mDimmedViewCanvas = new Canvas(mDimmedView);
+            mDimmedViewCanvas.concat(getMatrix());
+
+            draw(mDimmedViewCanvas);
+
+            // MAKE THE DIMMED VERSION
+            int dimmedColor = getContext().getResources().getColor(R.color.dimmed_view_color);
+            mDimmedViewCanvas.drawColor(dimmedColor, PorterDuff.Mode.SRC_IN);
+
+            isDimmedViewUpdatePass = false;
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (isDimmedViewUpdatePass) {
+            canvas.save();
+            final float alpha = getAlpha();
+            super.setAlpha(1.0f);
+            super.onDraw(canvas);
+            super.setAlpha(alpha);
+            canvas.restore();
+        } else {
+            if (mAlpha > 0) {
+                super.onDraw(canvas);
+            }
+        }
+
+        if (mDimmedView != null && mDimmedAlpha > 0) {
+            mDimmedPaint.setAlpha(mDimmedAlpha);
+            canvas.drawBitmap(mDimmedView, mScrollX, mScrollY, mDimmedPaint);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
new file mode 100644
index 0000000..6210337
--- /dev/null
+++ b/src/com/android/launcher2/HolographicOutlineHelper.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 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.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+
+public class HolographicOutlineHelper {
+    private float mDensity;
+    private final Paint mHolographicPaint = new Paint();
+    private final Paint mBlurPaint = new Paint();
+    private final Paint mErasePaint = new Paint();
+    private static final Matrix mIdentity = new Matrix();;
+    private static final float BLUR_FACTOR = 3.5f;
+
+    public static final float DEFAULT_STROKE_WIDTH = 6.0f;
+    public static final int HOLOGRAPHIC_BLUE = 0xFF6699FF;
+    public static final int HOLOGRAPHIC_GREEN = 0xFF51E633;
+
+    HolographicOutlineHelper(float density) {
+        mDensity = density;
+        mHolographicPaint.setColor(HOLOGRAPHIC_BLUE);
+        mHolographicPaint.setFilterBitmap(true);
+        mHolographicPaint.setAntiAlias(true);
+        mBlurPaint.setMaskFilter(new BlurMaskFilter(BLUR_FACTOR * density,
+                BlurMaskFilter.Blur.OUTER));
+        mBlurPaint.setFilterBitmap(true);
+        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+        mErasePaint.setFilterBitmap(true);
+        mErasePaint.setAntiAlias(true);
+    }
+
+    private float cubic(float r) {
+        return (float) (Math.pow(r - 1, 3) + 1);
+    }
+
+    /**
+     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
+     * pages.
+     */
+    public float highlightAlphaInterpolator(float r) {
+        final float pivot = 0.3f;
+        if (r < pivot) {
+            return Math.max(0.5f, 0.65f * cubic(r / pivot));
+        } else {
+            return Math.min(1.0f, 0.65f * cubic(1 - (r - pivot) / (1 - pivot)));
+        }
+    }
+
+    /**
+     * Returns the interpolated view alpha for the effect we want when scrolling pages.
+     */
+    public float viewAlphaInterpolator(float r) {
+        final float pivot = 0.6f;
+        if (r < pivot) {
+            return r / pivot;
+        } else {
+            return 1.0f;
+        }
+    }
+
+    /**
+     * Sets the color of the holographic paint to be used when applying the outline/blur.
+     */
+    void setColor(int color) {
+        mHolographicPaint.setColor(color);
+    }
+
+    /**
+     * Applies an outline to whatever is currently drawn in the specified bitmap.
+     */
+    void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, float strokeWidth, PointF offset) {
+        strokeWidth *= mDensity;
+        Bitmap mask = srcDst.extractAlpha();
+        Matrix m = new Matrix();
+        final int width = srcDst.getWidth();
+        final int height = srcDst.getHeight();
+        float xScale = strokeWidth * 2.0f / width;
+        float yScale = strokeWidth * 2.0f / height;
+        m.preScale(1 + xScale, 1 + yScale, (width / 2.0f) + offset.x,
+                (height / 2.0f) + offset.y);
+
+        srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+        srcDstCanvas.drawBitmap(mask, m, mHolographicPaint);
+        srcDstCanvas.drawBitmap(mask, mIdentity, mErasePaint);
+        mask.recycle();
+    }
+
+    /**
+     * Applies an blur to whatever is currently drawn in the specified bitmap.
+     */
+    void applyBlur(Bitmap srcDst, Canvas srcDstCanvas) {
+        int[] xy = new int[2];
+        Bitmap mask = srcDst.extractAlpha(mBlurPaint, xy);
+        srcDstCanvas.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
+        mask.recycle();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index dc0e7e9..c5450f3 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -374,12 +374,6 @@
         registerReceiver(mCloseSystemDialogsReceiver, filter);
     }
 
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        // TODO Auto-generated method stub
-        super.onConfigurationChanged(newConfig);
-    }
-
     private void checkForLocaleChange() {
         if (sLocaleConfiguration == null) {
             new AsyncTask<Void, Void, LocaleConfiguration>() {
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
index a5761ec..75a9940 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHost.java
@@ -34,6 +34,10 @@
     @Override
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        return new LauncherAppWidgetHostView(context);
+        if (LauncherApplication.isScreenXLarge()) {
+            return new DimmableAppWidgetHostView(context);
+        } else {
+            return new AppWidgetHostView(context);
+        }
     }
 }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index c62c397..e3c36af 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -33,8 +33,8 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.animation.Animation;
-import android.view.animation.Animation.AnimationListener;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Animation.AnimationListener;
 import android.widget.Checkable;
 import android.widget.Scroller;
 
@@ -87,13 +87,11 @@
     private int mPagingTouchSlop;
     private int mMaximumVelocity;
 
-    private static final int INVALID_POINTER = -1;
+    protected static final int INVALID_POINTER = -1;
 
-    private int mActivePointerId = INVALID_POINTER;
+    protected int mActivePointerId = INVALID_POINTER;
 
-    private enum PageMovingState { PAGE_BEGIN_MOVING, PAGE_END_MOVING };
     private PageSwitchListener mPageSwitchListener;
-    private PageMovingListener mPageMovingListener;
 
     private ArrayList<Boolean> mDirtyPageContent;
     private boolean mDirtyPageAlpha;
@@ -266,10 +264,12 @@
     // we moved this functionality to a helper function so SmoothPagedView can reuse it
     protected boolean computeScrollHelper() {
         if (mScroller.computeScrollOffset()) {
+            mDirtyPageAlpha = true;
             scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
             invalidate();
             return true;
         } else if (mNextPage != INVALID_PAGE) {
+            mDirtyPageAlpha = true;
             mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
             mNextPage = INVALID_PAGE;
             notifyPageSwitchListener();
@@ -299,17 +299,41 @@
         }
 
         // The children are given the same width and height as the workspace
+        // unless they were set to WRAP_CONTENT
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
-            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
+            // disallowing padding in paged view (just pass 0)
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            int childWidthMode;
+            if (lp.width == LayoutParams.WRAP_CONTENT) {
+                childWidthMode = MeasureSpec.AT_MOST;
+            } else {
+                childWidthMode = MeasureSpec.EXACTLY;
+            }
+
+            int childHeightMode;
+            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                childHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                childHeightMode = MeasureSpec.EXACTLY;
+            }
+
+            final int childWidthMeasureSpec =
+                MeasureSpec.makeMeasureSpec(widthSize, childWidthMode);
+            final int childHeightMeasureSpec =
+                MeasureSpec.makeMeasureSpec(heightSize, childHeightMode);
+
+            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
         }
 
         setMeasuredDimension(widthSize, heightSize);
 
-        if (mFirstLayout) {
+        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
             setHorizontalScrollBarEnabled(false);
-            scrollTo(mCurrentPage * widthSize, 0);
-            mScroller.setFinalX(mCurrentPage * widthSize);
+            scrollTo(getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage), 0);
+            mScroller.setFinalX(getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage));
             setHorizontalScrollBarEnabled(true);
             mFirstLayout = false;
         }
@@ -327,7 +351,9 @@
             final View child = getChildAt(i);
             if (child.getVisibility() != View.GONE) {
                 final int childWidth = child.getMeasuredWidth();
-                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
+                final int childHeight = (getMeasuredHeight() - child.getMeasuredHeight()) / 2;
+                child.layout(childLeft, childHeight,
+                        childLeft + childWidth, childHeight + child.getMeasuredHeight());
                 childLeft += childWidth;
             }
         }
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index b8cc206..4fa83df 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -16,120 +16,25 @@
 
 package com.android.launcher2;
 
+import com.android.launcher2.PagedView.PagedViewIconCache;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PointF;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.widget.Checkable;
 import android.widget.TextView;
 
-import com.android.launcher2.PagedView.PagedViewIconCache;
 
-class HolographicOutlineHelper {
-    private float mDensity;
-    private final Paint mHolographicPaint = new Paint();
-    private final Paint mBlurPaint = new Paint();
-    private final Paint mErasePaint = new Paint();
-    private static final Matrix mIdentity = new Matrix();;
-    private static final float BLUR_FACTOR = 3.5f;
-
-    public static final float DEFAULT_STROKE_WIDTH = 6.0f;
-    public static final int HOLOGRAPHIC_BLUE = 0xFF6699FF;
-    public static final int HOLOGRAPHIC_GREEN = 0xFF51E633;
-
-    HolographicOutlineHelper(float density) {
-        mDensity = density;
-        mHolographicPaint.setColor(HOLOGRAPHIC_BLUE);
-        mHolographicPaint.setFilterBitmap(true);
-        mHolographicPaint.setAntiAlias(true);
-        mBlurPaint.setMaskFilter(new BlurMaskFilter(BLUR_FACTOR * density, 
-                BlurMaskFilter.Blur.OUTER));
-        mBlurPaint.setFilterBitmap(true);
-        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
-        mErasePaint.setFilterBitmap(true);
-        mErasePaint.setAntiAlias(true);
-    }
-
-    private float cubic(float r) {
-        return (float) (Math.pow(r-1, 3) + 1);
-    }
-
-    /**
-     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling 
-     * pages.
-     */
-    public float highlightAlphaInterpolator(float r) {
-        final float pivot = 0.3f;
-        if (r < pivot) {
-            return Math.max(0.5f, 0.65f*cubic(r/pivot));
-        } else {
-            return Math.min(1.0f, 0.65f*cubic(1 - (r-pivot)/(1-pivot)));
-        }
-    }
-
-    /**
-     * Returns the interpolated view alpha for the effect we want when scrolling pages.
-     */
-    public float viewAlphaInterpolator(float r) {
-        final float pivot = 0.6f;
-        if (r < pivot) {
-            return r/pivot;
-        } else {
-            return 1.0f;
-        }
-    }
-
-    /**
-     * Sets the color of the holographic paint to be used when applying the outline/blur.
-     */
-    void setColor(int color) {
-        mHolographicPaint.setColor(color);
-    }
-
-    /**
-     * Applies an outline to whatever is currently drawn in the specified bitmap.
-     */
-    void applyOutline(Bitmap srcDst, Canvas srcDstCanvas, float strokeWidth, PointF offset) {
-        strokeWidth *= mDensity;
-        Bitmap mask = srcDst.extractAlpha();
-        Matrix m = new Matrix();
-        final int width = srcDst.getWidth();
-        final int height = srcDst.getHeight();
-        float xScale = strokeWidth*2.0f/width;
-        float yScale = strokeWidth*2.0f/height;
-        m.preScale(1+xScale, 1+yScale, (width / 2.0f) + offset.x,
-                (height / 2.0f) + offset.y);
-
-        srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
-        srcDstCanvas.drawBitmap(mask, m, mHolographicPaint);
-        srcDstCanvas.drawBitmap(mask, mIdentity, mErasePaint);
-        mask.recycle();
-    }
-
-    /**
-     * Applies an blur to whatever is currently drawn in the specified bitmap.
-     */
-    void applyBlur(Bitmap srcDst, Canvas srcDstCanvas) {
-        int[] xy = new int[2];
-        Bitmap mask = srcDst.extractAlpha(mBlurPaint, xy);
-        srcDstCanvas.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
-        mask.recycle();
-    }
-}
 
 /**
  * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
diff --git a/src/com/android/launcher2/SmoothPagedView.java b/src/com/android/launcher2/SmoothPagedView.java
index 3218349..73e147a 100644
--- a/src/com/android/launcher2/SmoothPagedView.java
+++ b/src/com/android/launcher2/SmoothPagedView.java
@@ -110,7 +110,7 @@
         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
 
         final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
-        final int newX = whichPage * getWidth();
+        final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         final int delta = newX - mScrollX;
         int duration = (screenDelta + 1) * 100;
 
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 59e061b..7ce7ea9 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -138,7 +138,10 @@
     public Workspace(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         mContentIsRefreshable = false;
-        mFadeInAdjacentScreens = false;
+
+        if (!LauncherApplication.isScreenXLarge()) {
+            mFadeInAdjacentScreens = false;
+        }
 
         mWallpaperManager = WallpaperManager.getInstance(context);
 
@@ -383,19 +386,46 @@
         return false;
     }
 
+    @Override
+    public boolean dispatchUnhandledMove(View focused, int direction) {
+        if (mIsSmall) {
+            // when the home screens are shrunken, shouldn't allow side-scrolling
+            return false;
+        }
+        return super.dispatchUnhandledMove(focused, direction);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mIsSmall) {
+            // when the home screens are shrunken, shouldn't allow side-scrolling
+            return false;
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
     protected void pageBeginMoving() {
         if (mNextPage != INVALID_PAGE) {
             // we're snapping to a particular screen
-            enableChildrenCache(mCurrentPage, mNextPage);
+            // there's an issue where the alpha of neighboring pages doesn't get updated
+            // if drawing cache is enabled on children-- we only use that on xlarge devices,
+            // so disable drawing cache in those cases
+            if (!LauncherApplication.isScreenXLarge()) {
+                enableChildrenCache(mCurrentPage, mNextPage);
+            }
         } else {
             // this is when user is actively dragging a particular screen, they might
             // swipe it either left or right (but we won't advance by more than one screen)
-            enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
+            if (!LauncherApplication.isScreenXLarge()) {
+                enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
+            }
         }
     }
 
     protected void pageEndMoving() {
-        clearChildrenCache();
+        if (!LauncherApplication.isScreenXLarge()) {
+            clearChildrenCache();
+        }
     }
 
     @Override
@@ -465,9 +495,6 @@
             for (int i = 0; i < pageCount; i++) {
                 final View page = (View) getChildAt(i);
 
-                if (page.getAlpha() != 1.0f) {
-                    page.setAlpha(1.0f);
-                }
                 drawChild(canvas, page, drawingTime);
             }
         } else {
@@ -596,6 +623,10 @@
     // we use this to shrink the workspace for the all apps view and the customize view
     private void shrink(ShrinkPosition shrinkPosition, boolean animated) {
         mIsSmall = true;
+        // we intercept and reject all touch events when we're small, so be sure to reset the state
+        mTouchState = TOUCH_STATE_REST;
+        mActivePointerId = INVALID_POINTER;
+
         final Resources res = getResources();
         final int screenWidth = getWidth();
         final int screenHeight = getHeight();
@@ -637,19 +668,21 @@
 
             if (animated) {
                 final int duration = res.getInteger(R.integer.config_workspaceShrinkTime);
-                new ObjectAnimator(duration, cl,
-                        new PropertyValuesHolder("x", newX),
-                        new PropertyValuesHolder("y", newY),
-                        new PropertyValuesHolder("scaleX", SHRINK_FACTOR * rotationScaleX),
-                        new PropertyValuesHolder("scaleY", SHRINK_FACTOR * rotationScaleY),
-                        new PropertyValuesHolder("dimmedBitmapAlpha", 1.0f),
-                        new PropertyValuesHolder("rotationY", rotation)).start();
+                new ObjectAnimator<Float>(duration, cl,
+                        new PropertyValuesHolder<Float>("x", newX),
+                        new PropertyValuesHolder<Float>("y", newY),
+                        new PropertyValuesHolder<Float>("scaleX", SHRINK_FACTOR),
+                        new PropertyValuesHolder<Float>("scaleY", SHRINK_FACTOR),
+                        new PropertyValuesHolder<Float>("backgroundAlpha", 1.0f),
+                        new PropertyValuesHolder<Float>("alpha", 0.0f),
+                        new PropertyValuesHolder<Float>("rotationY", rotation)).start();
             } else {
                 cl.setX((int)newX);
                 cl.setY((int)newY);
                 cl.setScaleX(SHRINK_FACTOR);
                 cl.setScaleY(SHRINK_FACTOR);
-                cl.setDimmedBitmapAlpha(1.0f);
+                cl.setBackgroundAlpha(1.0f);
+                cl.setAlpha(0.0f);
                 cl.setRotationY(rotation);
             }
             // increment newX for the next screen
@@ -673,7 +706,8 @@
 
     private void unshrink(int newCurrentPage) {
         if (mIsSmall) {
-            int delta = (newCurrentPage - mCurrentPage)*getWidth();
+            int newX = getChildOffset(newCurrentPage) - getRelativeChildOffset(newCurrentPage);
+            int delta = newX - mScrollX;
 
             final int screenCount = getChildCount();
             for (int i = 0; i < screenCount; i++) {
@@ -699,20 +733,23 @@
             final int duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
             for (int i = 0; i < screenCount; i++) {
                 final CellLayout cl = (CellLayout)getChildAt(i);
+                float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
                 if (animated) {
                     s.playTogether(
                             new ObjectAnimator<Float>(duration, cl, "translationX", 0.0f),
                             new ObjectAnimator<Float>(duration, cl, "translationY", 0.0f),
                             new ObjectAnimator<Float>(duration, cl, "scaleX", 1.0f),
                             new ObjectAnimator<Float>(duration, cl, "scaleY", 1.0f),
-                            new ObjectAnimator<Float>(duration, cl, "dimmedBitmapAlpha", 0.0f),
+                            new ObjectAnimator<Float>(duration, cl, "backgroundAlpha", 0.0f),
+                            new ObjectAnimator<Float>(duration, cl, "alpha", finalAlphaValue),
                             new ObjectAnimator<Float>(duration, cl, "rotationY", 0.0f));
                 } else {
                     cl.setTranslationX(0.0f);
                     cl.setTranslationY(0.0f);
                     cl.setScaleX(1.0f);
                     cl.setScaleY(1.0f);
-                    cl.setDimmedBitmapAlpha(0.0f);
+                    cl.setBackgroundAlpha(0.0f);
+                    cl.setAlpha(1.0f);
                     cl.setRotationY(0.0f);
                 }
             }
@@ -838,6 +875,8 @@
         // If we are dragging over a cell that contains a DropTarget that will
         // accept the drop, delegate to that DropTarget.
         final int[] cellXY = mTempCell;
+        int localDragPointX = dragPointX - (currentLayout.getLeft() - mScrollX);
+        int localDragPointY = dragPointY - (currentLayout.getTop() - mScrollY);
         currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY);
         View child = currentLayout.getChildAt(cellXY[0], cellXY[1]);
         if (child instanceof DropTarget) {
@@ -986,8 +1025,10 @@
         if ((!LauncherApplication.isScreenXLarge() || source == this)
                 && mDragTargetLayout != null) {
             final View child = (mDragInfo == null) ? null : mDragInfo.cell;
+            int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX);
+            int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY);
             mDragTargetLayout.visualizeDropLocation(
-                    child, originX, originY, item.spanX, item.spanY);
+                    child, localOriginX, localOriginY, item.spanX, item.spanY);
         }
     }
 
@@ -1143,7 +1184,9 @@
             int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
 
         final int[] cellXY = mTempCell;
-        layout.estimateDropCell(pixelX, pixelY, spanX, spanY, cellXY);
+        int localPixelX = pixelX - (layout.getLeft() - mScrollX);
+        int localPixelY = pixelY - (layout.getTop() - mScrollY);
+        layout.estimateDropCell(localPixelX, localPixelY, spanX, spanY, cellXY);
         layout.cellToPoint(cellXY[0], cellXY[1], mTempEstimate);
 
         final CellLayout.CellInfo cellInfo = layout.updateOccupiedCells(null, ignoreView);