-Added 3D effect to home screen scrolling
-Added background outline fade in / out
-Modified the feel of scrolling: now using quintic
 interpolator and modified the influence of
 scroll velocity

Change-Id: Ifddcab5223ac20be7d9f800ccf09442d9b4db781
diff --git a/res/drawable-xlarge/home_screen_bg.9.png b/res/drawable-xlarge/home_screen_bg.9.png
new file mode 100644
index 0000000..d939d5c
--- /dev/null
+++ b/res/drawable-xlarge/home_screen_bg.9.png
Binary files differ
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 585d1c3..0caaf2e 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -37,7 +37,7 @@
 
 import java.util.Arrays;
 
-public class CellLayout extends ViewGroup {
+public class CellLayout extends ViewGroup implements Dimmable {
     static final String TAG = "CellLayout";
 
     private int mCellWidth;
@@ -68,8 +68,10 @@
 
     private float mBackgroundAlpha;
     private final Rect mBackgroundLayoutRect = new Rect();
+
     private Drawable mBackground;
-    private Drawable mBackgroundHover;
+    private Drawable mBackgroundMini;
+    private Drawable mBackgroundMiniHover;
     // If we're actively dragging something over this screen and it's small,
     // mHover is true
     private boolean mHover = false;
@@ -108,10 +110,12 @@
         mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
 
         if (LauncherApplication.isScreenXLarge()) {
-            mBackground = getResources().getDrawable(R.drawable.mini_home_screen_bg);
+            mBackgroundMini = getResources().getDrawable(R.drawable.mini_home_screen_bg);
+            mBackgroundMini.setFilterBitmap(true);
+            mBackground = getResources().getDrawable(R.drawable.home_screen_bg);
             mBackground.setFilterBitmap(true);
-            mBackgroundHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
-            mBackgroundHover.setFilterBitmap(true);
+            mBackgroundMiniHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
+            mBackgroundMiniHover.setFilterBitmap(true);
         }
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
@@ -149,7 +153,14 @@
     @Override
     public void dispatchDraw(Canvas canvas) {
         if (mBackgroundAlpha > 0.0f) {
-            final Drawable bg = mHover ? mBackgroundHover : mBackground;
+            Drawable bg;
+            if (mHover && getScaleX() < 0.5f) {
+                bg = mBackgroundMiniHover;
+            } else if (getScaleX() < 0.5f) {
+                bg = mBackgroundMini;
+            } else {
+                bg = mBackground;
+            }
             bg.setAlpha((int) (mBackgroundAlpha * 255));
             bg.draw(canvas);
         }
@@ -169,6 +180,20 @@
         super.onDraw(canvas);
     }
 
+    public void setDimmableProgress(float progress) {
+        for (int i = 0; i < getChildCount(); i++) {
+            Dimmable d = (Dimmable) getChildAt(i);
+            d.setDimmableProgress(progress);
+        }
+    }
+
+    public float getDimmableProgress() {
+        if (getChildCount() > 0) {
+            return ((Dimmable) getChildAt(0)).getDimmableProgress();
+        }
+        return 0.0f;
+    }
+
     @Override
     public void cancelLongPress() {
         super.cancelLongPress();
@@ -523,8 +548,11 @@
         if (mBackground != null) {
             mBackground.setBounds(mBackgroundLayoutRect);
         }
-        if (mBackgroundHover != null) {
-            mBackgroundHover.setBounds(mBackgroundLayoutRect);
+        if (mBackgroundMiniHover != null) {
+            mBackgroundMiniHover.setBounds(mBackgroundLayoutRect);
+        }
+        if (mBackgroundMini != null) {
+            mBackgroundMini.setBounds(mBackgroundLayoutRect);
         }
     }
 
diff --git a/src/com/android/launcher2/Dimmable.java b/src/com/android/launcher2/Dimmable.java
new file mode 100644
index 0000000..df43b3c
--- /dev/null
+++ b/src/com/android/launcher2/Dimmable.java
@@ -0,0 +1,6 @@
+package com.android.launcher2;
+
+public interface Dimmable {
+    public void setDimmableProgress(float progress);
+    public float getDimmableProgress();
+}
diff --git a/src/com/android/launcher2/DimmableAppWidgetHostView.java b/src/com/android/launcher2/DimmableAppWidgetHostView.java
index 7a1d4f9..1f512a3 100644
--- a/src/com/android/launcher2/DimmableAppWidgetHostView.java
+++ b/src/com/android/launcher2/DimmableAppWidgetHostView.java
@@ -21,52 +21,21 @@
 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 class DimmableAppWidgetHostView extends LauncherAppWidgetHostView implements Dimmable {
     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 float mDimmableProgress;
 
     private void setChildAlpha(float alpha) {
         if (getChildCount() > 0) {
@@ -83,20 +52,18 @@
         setChildAlpha(getAlpha());
     }
 
-    @Override
+    //@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);
+    public void setDimmableProgress(float progress) {
+        mDimmableProgress = progress;
+    }
+
+    public float getDimmableProgress() {
+        return mDimmableProgress;
     }
 
     private void updateDimmedView() {
@@ -113,13 +80,14 @@
         int dimmedColor = getContext().getResources().getColor(R.color.dimmed_view_color);
         mDimmedViewCanvas.drawColor(dimmedColor, PorterDuff.Mode.SRC_IN);
         isDimmedViewUpdatePass = false;
+        invalidate();
     }
 
     @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) {
+        if (mDimmedView == null && mDimmableProgress > 0.0f) {
             updateDimmedView();
         }
     }
@@ -134,9 +102,9 @@
             canvas.restore();
             setAlpha(alpha);
         } else {
-            if (mDimmedView != null && mDimmedAlpha > 0) {
+            if (mDimmedView != null && mDimmableProgress > 0) {
                 // draw the dimmed version of this widget
-                mPaint.setAlpha(mDimmedAlpha);
+                mPaint.setAlpha((int) (mDimmableProgress * 255));
                 canvas.drawBitmap(mDimmedView, 0, 0, mPaint);
             }
 
@@ -144,4 +112,4 @@
             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
index 66cc97a..cb3b8ef 100644
--- a/src/com/android/launcher2/DimmableBubbleTextView.java
+++ b/src/com/android/launcher2/DimmableBubbleTextView.java
@@ -21,18 +21,17 @@
 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 {
+public class DimmableBubbleTextView extends BubbleTextView implements Dimmable {
     private  Paint mDimmedPaint = new Paint();
     private int mAlpha;
-    private int mDimmedAlpha;
     private Bitmap mDimmedView;
     private Canvas mDimmedViewCanvas;
     private boolean isDimmedViewUpdatePass;
+    private float mDimmableProgress;
 
     public DimmableBubbleTextView(Context context) {
         super(context);
@@ -49,48 +48,12 @@
         mDimmedPaint.setFilterBitmap(true);
     }
 
-    private static float cubic(float r) {
-        return (float) (Math.pow(r-1, 3) + 1);
+    public void setDimmableProgress(float progress) {
+        mDimmableProgress = progress;
     }
 
-    /**
-     * 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);
+    public float getDimmableProgress() {
+        return mDimmableProgress;
     }
 
     @Override
@@ -124,13 +87,11 @@
             super.setAlpha(alpha);
             canvas.restore();
         } else {
-            if (mAlpha > 0) {
-                super.onDraw(canvas);
-            }
+            super.onDraw(canvas);
         }
 
-        if (mDimmedView != null && mDimmedAlpha > 0) {
-            mDimmedPaint.setAlpha(mDimmedAlpha);
+        if (mDimmedView != null && mDimmableProgress > 0) {
+            mDimmedPaint.setAlpha((int) (mDimmableProgress * 255));
             canvas.drawBitmap(mDimmedView, mScrollX, mScrollY, mDimmedPaint);
         }
     }
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
index 29ffe6e..9352ec2 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHost.java
@@ -30,7 +30,7 @@
     public LauncherAppWidgetHost(Context context, int hostId) {
         super(context, hostId);
     }
-    
+
     @Override
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 5aec48e..4e47acb 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -78,6 +78,7 @@
     protected final static int TOUCH_STATE_SCROLLING = 1;
     protected final static int TOUCH_STATE_PREV_PAGE = 2;
     protected final static int TOUCH_STATE_NEXT_PAGE = 3;
+    protected final static float ALPHA_QUANTIZE_LEVEL = 0.01f;
 
     protected int mTouchState = TOUCH_STATE_REST;
 
@@ -367,7 +368,6 @@
             if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
                 int halfScreenSize = getMeasuredWidth() / 2;
                 int screenCenter = mScrollX + halfScreenSize;
-
                 final int childCount = getChildCount();
                 for (int i = 0; i < childCount; ++i) {
                     View layout = (View) getChildAt(i);
@@ -391,6 +391,12 @@
                     dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha)));
                     float alpha = 1.0f - dimAlpha;
 
+                    if (alpha < ALPHA_QUANTIZE_LEVEL) {
+                        alpha = 0.0f;
+                    } else if (alpha > 1.0f - ALPHA_QUANTIZE_LEVEL) {
+                        alpha = 1.0f;
+                    }
+
                     if (Float.compare(alpha, layout.getAlpha()) != 0) {
                         layout.setAlpha(alpha);
                     }
@@ -400,10 +406,16 @@
         }
     }
 
+    protected void screenScrolled(int screenCenter) {
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         updateAdjacentPagesAlpha();
 
+        int halfScreenSize = getMeasuredWidth() / 2;
+        int screenCenter = mScrollX + halfScreenSize;
+        screenScrolled(screenCenter);
         // 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.
diff --git a/src/com/android/launcher2/SmoothPagedView.java b/src/com/android/launcher2/SmoothPagedView.java
index 5f80f25..56037ff 100644
--- a/src/com/android/launcher2/SmoothPagedView.java
+++ b/src/com/android/launcher2/SmoothPagedView.java
@@ -26,11 +26,15 @@
     private static final float SMOOTHING_SPEED = 0.75f;
     private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
 
+    private float mBaseLineFlingVelocity;
+    private float mFlingVelocityInfluence;
 
-    private static final float BASELINE_FLING_VELOCITY = 2500.f;
-    private static final float FLING_VELOCITY_INFLUENCE = 0.4f;
+    static final int OVERSHOOT_MODE = 0;
+    static final int QUINTIC_MODE = 1;
 
-    private WorkspaceOvershootInterpolator mScrollInterpolator;
+    int mScrollMode;
+
+    private Interpolator mScrollInterpolator;
 
     private static class WorkspaceOvershootInterpolator implements Interpolator {
         private static final float DEFAULT_TENSION = 1.3f;
@@ -56,6 +60,16 @@
         }
     }
 
+    private static class QuinticInterpolator implements Interpolator {
+        public QuinticInterpolator() {
+        }
+
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t*t*t*t*t + 1;
+        }
+    }
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -83,14 +97,27 @@
         mDeferScrollUpdate = true;
     }
 
+    protected int getScrollMode() {
+        return OVERSHOOT_MODE;
+    }
+
     /**
      * Initializes various states for this workspace.
      */
     @Override
     protected void init() {
         super.init();
-        mScrollInterpolator = new WorkspaceOvershootInterpolator();
-        // overwrite the previous mScroller
+
+        mScrollMode = getScrollMode();
+        if (mScrollMode == QUINTIC_MODE) {
+            mBaseLineFlingVelocity = 700.0f;
+            mFlingVelocityInfluence = 0.8f;
+            mScrollInterpolator = new QuinticInterpolator();
+        } else {  // QUINTIC_MODE
+            mBaseLineFlingVelocity = 2500.0f;
+            mFlingVelocityInfluence = 0.4f;
+            mScrollInterpolator = new WorkspaceOvershootInterpolator();
+        }
         mScroller = new Scroller(getContext(), mScrollInterpolator);
     }
 
@@ -112,25 +139,32 @@
         final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
         final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         final int delta = newX - mScrollX;
-        int duration = (screenDelta + 1) * 100;
+        int duration;
+        if (mScrollMode == OVERSHOOT_MODE) {
+            duration = (screenDelta + 1) * 100;
+        } else { // QUINTIC_MODE
+            duration = Math.round(Math.abs(delta) * 0.6f);
+        }
 
         if (!mScroller.isFinished()) {
             mScroller.abortAnimation();
         }
 
-        if (settle) {
-            mScrollInterpolator.setDistance(screenDelta);
-        } else {
-            mScrollInterpolator.disableSettle();
+        if (mScrollMode == OVERSHOOT_MODE) {
+            if (settle) {
+                ((WorkspaceOvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
+            } else {
+                ((WorkspaceOvershootInterpolator) mScrollInterpolator).disableSettle();
+            }
         }
 
         velocity = Math.abs(velocity);
         if (velocity > 0) {
-            duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
-                    * FLING_VELOCITY_INFLUENCE;
+            duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
         } else {
             duration += 100;
         }
+
         snapToPage(whichPage, delta, duration);
     }
 
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 08f3daa..160283b 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -33,7 +33,9 @@
 import android.content.pm.ProviderInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Camera;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -64,8 +66,8 @@
     // customization mode
     private static final float SHRINK_FACTOR = 0.16f;
 
-    // The maximum Y rotation to apply to the mini home screens
-    private static final float MINI_PAGE_MAX_ROTATION = 25.0f;
+    // Y rotation to apply to the workspace screens
+    private static final float WORKSPACE_ROTATION = 12.5f;
 
     // These are extra scale factors to apply to the mini home screens
     // so as to achieve the desired transform
@@ -73,6 +75,18 @@
     private static final float EXTRA_SCALE_FACTOR_1 = 1.0f;
     private static final float EXTRA_SCALE_FACTOR_2 = 1.08f;
 
+    private static final int BACKGROUND_FADE_OUT_DELAY = 300;
+    private static final int BACKGROUND_FADE_OUT_DURATION = 300;
+    private static final int BACKGROUND_FADE_IN_DURATION = 100;
+
+    static final int SCROLL_RIGHT = 0;
+    static final int SCROLL_LEFT = 1;
+
+    // These animators are used to fade the
+    private ObjectAnimator<Float> mBackgroundFadeIn;
+    private ObjectAnimator<Float> mBackgroundFadeOut;
+    private float mBackgroundAlpha = 0;
+
     private enum ShrinkPosition { SHRINK_TO_TOP, SHRINK_TO_MIDDLE, SHRINK_TO_BOTTOM };
 
     private final WallpaperManager mWallpaperManager;
@@ -181,6 +195,15 @@
     }
 
     @Override
+    protected int getScrollMode() {
+        if (LauncherApplication.isScreenXLarge()) {
+            return SmoothPagedView.QUINTIC_MODE;
+        } else {
+            return SmoothPagedView.OVERSHOOT_MODE;
+        }
+    }
+
+    @Override
     public void addView(View child, int index, LayoutParams params) {
         if (!(child instanceof CellLayout)) {
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
@@ -383,12 +406,14 @@
                 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
             }
         }
+        showOutlines();
     }
 
     protected void pageEndMoving() {
         if (!LauncherApplication.isScreenXLarge()) {
             clearChildrenCache();
         }
+        hideOutlines();
     }
 
     @Override
@@ -425,6 +450,99 @@
         }
     }
 
+    private float getScaleXForRotation(float degrees) {
+        return (float) (1.0f / Math.cos(Math.PI * degrees / 180.0f));
+    }
+
+    public void showOutlines() {
+        if (mBackgroundFadeOut != null) mBackgroundFadeOut.cancel();
+        if (mBackgroundFadeIn != null) mBackgroundFadeIn.cancel();
+        mBackgroundFadeIn = new ObjectAnimator<Float>(BACKGROUND_FADE_IN_DURATION, this,
+                        new PropertyValuesHolder<Float>("backgroundAlpha", 1.0f));
+        mBackgroundFadeIn.start();
+    }
+
+    public void hideOutlines() {
+        if (mBackgroundFadeIn != null) mBackgroundFadeIn.cancel();
+        if (mBackgroundFadeOut != null) mBackgroundFadeOut.cancel();
+        mBackgroundFadeOut = new ObjectAnimator<Float>(BACKGROUND_FADE_OUT_DURATION, this,
+                        new PropertyValuesHolder<Float>("backgroundAlpha", 0.0f));
+        mBackgroundFadeOut.setStartDelay(BACKGROUND_FADE_OUT_DELAY);
+        mBackgroundFadeOut.start();
+    }
+
+    public void setBackgroundAlpha(float alpha) {
+        mBackgroundAlpha = alpha;
+        for (int i = 0; i < getChildCount(); i++) {
+            CellLayout cl = (CellLayout) getChildAt(i);
+            cl.setBackgroundAlpha(alpha);
+        }
+    }
+
+    public float getBackgroundAlpha() {
+        return mBackgroundAlpha;
+    }
+
+    @Override
+    protected void screenScrolled(int screenCenter) {
+        View cur = getChildAt(mCurrentPage);
+        View toRight = getChildAt(mCurrentPage + 1);
+        View toLeft = getChildAt(mCurrentPage - 1);
+
+        for (int i = 0; i < mCurrentPage - 1; i++) {
+            View v = getChildAt(i);
+            if (v != null) {
+                v.setRotationY(WORKSPACE_ROTATION);
+                v.setScaleX(getScaleXForRotation(WORKSPACE_ROTATION));
+            }
+        }
+        for (int i = mCurrentPage + 1; i < getChildCount(); i++) {
+            View v = getChildAt(i);
+            if (v != null) {
+                v.setRotationY(-WORKSPACE_ROTATION);
+                v.setScaleX(getScaleXForRotation(-WORKSPACE_ROTATION));
+            }
+        }
+
+        int pageWidth = cur.getMeasuredWidth();
+        int delta = screenCenter - (mCurrentPage * pageWidth + pageWidth / 2 +
+                getRelativeChildOffset(0));
+
+        float scrollProgress = Math.abs(delta/(pageWidth*1.0f));
+        int scrollDirection = delta > 0 ? SCROLL_LEFT : SCROLL_RIGHT;
+
+        float rotation;
+
+        if (scrollDirection == SCROLL_RIGHT) {
+            rotation = -scrollProgress * WORKSPACE_ROTATION;
+            cur.setRotationY(rotation);
+            cur.setScaleX(getScaleXForRotation(rotation));
+            if (toLeft != null) {
+                rotation = WORKSPACE_ROTATION * (1 - scrollProgress);
+                toLeft.setRotationY(rotation);
+                toLeft.setScaleX(getScaleXForRotation(rotation));
+            }
+            if (toRight != null) {
+                toRight.setRotationY(-WORKSPACE_ROTATION);
+                toRight.setScaleX(getScaleXForRotation(WORKSPACE_ROTATION));
+            }
+        } else {
+            rotation = scrollProgress * WORKSPACE_ROTATION;
+            cur.setRotationY(rotation);
+            cur.setScaleX(getScaleXForRotation(rotation));
+
+            if (toRight != null) {
+                rotation = -WORKSPACE_ROTATION * (1 - scrollProgress);
+                toRight.setRotationY(rotation);
+                toRight.setScaleX(getScaleXForRotation(rotation));
+            }
+            if (toLeft != null) {
+                toLeft.setRotationY(WORKSPACE_ROTATION);
+                toLeft.setScaleX(getScaleXForRotation(WORKSPACE_ROTATION));
+            }
+        }
+    }
+
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         computeScroll();
@@ -625,7 +743,7 @@
         for (int i = 0; i < screenCount; i++) {
             CellLayout cl = (CellLayout) getChildAt(i);
 
-            float rotation = (-i + 2) * MINI_PAGE_MAX_ROTATION / 2.0f;
+            float rotation = (-i + 2) * WORKSPACE_ROTATION;
             float rotationScaleX = (float) (1.0f / Math.cos(Math.PI * rotation / 180.0f));
             float rotationScaleY = getYScaleForScreen(i);
 
@@ -637,14 +755,16 @@
                         new PropertyValuesHolder<Float>("scaleX", SHRINK_FACTOR * rotationScaleX),
                         new PropertyValuesHolder<Float>("scaleY", SHRINK_FACTOR * rotationScaleY),
                         new PropertyValuesHolder<Float>("backgroundAlpha", 1.0f),
+                        new PropertyValuesHolder<Float>("dimmableProgress", 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.setScaleX(SHRINK_FACTOR * rotationScaleX);
+                cl.setScaleY(SHRINK_FACTOR * rotationScaleY);
                 cl.setBackgroundAlpha(1.0f);
+                cl.setDimmableProgress(1.0f);
                 cl.setAlpha(0.0f);
                 cl.setRotationY(rotation);
             }
@@ -697,6 +817,14 @@
             for (int i = 0; i < screenCount; i++) {
                 final CellLayout cl = (CellLayout)getChildAt(i);
                 float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+                float rotation = 0.0f;
+
+                if (i < mCurrentPage) {
+                    rotation = WORKSPACE_ROTATION;
+                } else if (i > mCurrentPage) {
+                    rotation = -WORKSPACE_ROTATION;
+                }
+
                 if (animated) {
                     s.playTogether(
                             new ObjectAnimator<Float>(duration, cl, "translationX", 0.0f),
@@ -705,15 +833,17 @@
                             new ObjectAnimator<Float>(duration, cl, "scaleY", 1.0f),
                             new ObjectAnimator<Float>(duration, cl, "backgroundAlpha", 0.0f),
                             new ObjectAnimator<Float>(duration, cl, "alpha", finalAlphaValue),
-                            new ObjectAnimator<Float>(duration, cl, "rotationY", 0.0f));
+                            new ObjectAnimator<Float>(duration, cl, "dimmableProgress", 0.0f),
+                            new ObjectAnimator<Float>(duration, cl, "rotationY", rotation));
                 } else {
                     cl.setTranslationX(0.0f);
                     cl.setTranslationY(0.0f);
                     cl.setScaleX(1.0f);
                     cl.setScaleY(1.0f);
                     cl.setBackgroundAlpha(0.0f);
-                    cl.setAlpha(1.0f);
-                    cl.setRotationY(0.0f);
+                    cl.setDimmableProgress(0.0f);
+                    cl.setAlpha(finalAlphaValue);
+                    cl.setRotationY(rotation);
                 }
             }
             s.addListener(mUnshrinkAnimationListener);