Merge "Potential fix for launcher lockup (5369863)" into ics-mr1
diff --git a/res/drawable-hdpi/homescreen_small_blue.9.png b/res/drawable-hdpi/flying_icon_bg_pressed.9.png
similarity index 100%
rename from res/drawable-hdpi/homescreen_small_blue.9.png
rename to res/drawable-hdpi/flying_icon_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_small_blue_strong.9.png b/res/drawable-hdpi/homescreen_small_blue_strong.9.png
deleted file mode 100644
index 6eab8f2..0000000
--- a/res/drawable-hdpi/homescreen_small_blue_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/homescreen_small_blue.9.png b/res/drawable-mdpi/flying_icon_bg_pressed.9.png
similarity index 100%
rename from res/drawable-mdpi/homescreen_small_blue.9.png
rename to res/drawable-mdpi/flying_icon_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/homescreen_small_blue_strong.9.png b/res/drawable-mdpi/homescreen_small_blue_strong.9.png
deleted file mode 100644
index 79d84a4..0000000
--- a/res/drawable-mdpi/homescreen_small_blue_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/homescreen_small_blue.9.png b/res/drawable-xhdpi/flying_icon_bg_pressed.9.png
similarity index 100%
rename from res/drawable-xhdpi/homescreen_small_blue.9.png
rename to res/drawable-xhdpi/flying_icon_bg_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/homescreen_small_blue_strong.9.png b/res/drawable-xhdpi/homescreen_small_blue_strong.9.png
deleted file mode 100644
index 696d907..0000000
--- a/res/drawable-xhdpi/homescreen_small_blue_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/flying_icon_bg.xml b/res/drawable/flying_icon_bg.xml
index 6f5bf0b..167c3ba 100644
--- a/res/drawable/flying_icon_bg.xml
+++ b/res/drawable/flying_icon_bg.xml
@@ -15,6 +15,6 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/homescreen_small_blue" />
+    <item android:state_pressed="true" android:drawable="@drawable/flying_icon_bg_pressed" />
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 4d8a9cf..9000049 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -932,7 +932,7 @@
         Bitmap preview = Bitmap.createBitmap(bitmapSize, bitmapSize, Config.ARGB_8888);
 
         // Render the icon
-        Drawable icon = mIconCache.getFullResIcon(info, mPackageManager);
+        Drawable icon = mIconCache.getFullResIcon(info);
         renderDrawableToBitmap(icon, preview, offset, offset, mAppIconSize, mAppIconSize);
         return preview;
     }
@@ -1014,7 +1014,7 @@
                 Drawable icon = null;
                 int hoffset = (int) (bitmapWidth / 2 - mAppIconSize * iconScale / 2);
                 int yoffset = (int) (bitmapHeight / 2 - mAppIconSize * iconScale / 2);
-                if (info.icon > 0) icon = mPackageManager.getDrawable(packageName, info.icon, null);
+                if (info.icon > 0) icon = mIconCache.getFullResIcon(packageName, info.icon);
                 if (icon == null) icon = resources.getDrawable(R.drawable.ic_launcher_application);
 
                 renderDrawableToBitmap(icon, preview, hoffset, yoffset,
@@ -1152,8 +1152,6 @@
         layout.createHardwareLayer();
 
         invalidate();
-        forceUpdateAdjacentPagesAlpha();
-
         /* TEMPORARILY DISABLE HOLOGRAPHIC ICONS
         if (mFadeInAdjacentScreens) {
             prepareGenerateHoloOutlinesTask(data.page, data.items, data.generatedImages);
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 54fdcc5..9ffc1d0 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -96,12 +96,7 @@
     private float mBackgroundAlphaMultiplier = 1.0f;
 
     private Drawable mNormalBackground;
-    private Drawable mActiveBackground;
     private Drawable mActiveGlowBackground;
-    private Drawable mNormalBackgroundMini;
-    private Drawable mNormalGlowBackgroundMini;
-    private Drawable mActiveBackgroundMini;
-    private Drawable mActiveGlowBackgroundMini;
     private Drawable mOverScrollForegroundDrawable;
     private Drawable mOverScrollLeft;
     private Drawable mOverScrollRight;
@@ -112,11 +107,8 @@
     private float mGlowBackgroundAlpha;
     private int mForegroundPadding;
 
-    private boolean mAcceptsDrops = true;
     // If we're actively dragging something over this screen, mIsDragOverlapping is true
     private boolean mIsDragOverlapping = false;
-    private boolean mIsDragOccuring = false;
-    private boolean mIsDefaultDropTarget = false;
     private final Point mDragCenter = new Point();
 
     // These arrays are used to implement the drag visualization on x-large screens.
@@ -182,25 +174,15 @@
         final Resources res = getResources();
 
         mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
-        mActiveBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
         mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
 
-        mNormalBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue);
-        mNormalGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
-        mActiveBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
-        mActiveGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
         mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
         mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
         mForegroundPadding =
                 res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
 
         mNormalBackground.setFilterBitmap(true);
-        mActiveBackground.setFilterBitmap(true);
         mActiveGlowBackground.setFilterBitmap(true);
-        mNormalBackgroundMini.setFilterBitmap(true);
-        mNormalGlowBackgroundMini.setFilterBitmap(true);
-        mActiveBackgroundMini.setFilterBitmap(true);
-        mActiveGlowBackgroundMini.setFilterBitmap(true);
 
         // Initialize the data structures used for the drag visualization.
 
@@ -358,20 +340,6 @@
         return null;
     }
 
-    public void setIsDefaultDropTarget(boolean isDefaultDropTarget) {
-        if (mIsDefaultDropTarget != isDefaultDropTarget) {
-            mIsDefaultDropTarget = isDefaultDropTarget;
-            invalidate();
-        }
-    }
-
-    void setIsDragOccuring(boolean isDragOccuring) {
-        if (mIsDragOccuring != isDragOccuring) {
-            mIsDragOccuring = isDragOccuring;
-            invalidate();
-        }
-    }
-
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
@@ -454,47 +422,17 @@
         // backgrounds
         if (mBackgroundAlpha > 0.0f) {
             Drawable bg;
-            boolean mini = getScaleX() < 0.5f;
 
             if (mIsDragOverlapping) {
                 // In the mini case, we draw the active_glow bg *over* the active background
-                bg = mini ? mActiveBackgroundMini : mActiveGlowBackground;
-            } else if (mIsDragOccuring && mAcceptsDrops) {
-                bg = mini ? mActiveBackgroundMini : mActiveBackground;
-            } else if (mIsDefaultDropTarget && mini) {
-                bg = mNormalGlowBackgroundMini;
+                bg = mActiveGlowBackground;
             } else {
-                bg = mini ? mNormalBackgroundMini : mNormalBackground;
+                bg = mNormalBackground;
             }
 
             bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
             bg.setBounds(mBackgroundRect);
             bg.draw(canvas);
-
-            if (mini && mIsDragOverlapping) {
-                boolean modifiedClipRect = false;
-                if (mGlowBackgroundScale > 1.0f) {
-                    // If the hover background's scale is greater than 1, we'll be drawing outside
-                    // the bounds of this CellLayout. Get around that by temporarily increasing the
-                    // size of the clip rect
-                    float marginFraction = (mGlowBackgroundScale - 1.0f) / 2.0f;
-                    Rect clipRect = canvas.getClipBounds();
-                    int marginX = (int) (marginFraction * (clipRect.right - clipRect.left));
-                    int marginY = (int) (marginFraction * (clipRect.bottom - clipRect.top));
-                    canvas.save(Canvas.CLIP_SAVE_FLAG);
-                    canvas.clipRect(-marginX, -marginY,
-                            getWidth() + marginX, getHeight() + marginY, Region.Op.REPLACE);
-                    modifiedClipRect = true;
-                }
-
-                mActiveGlowBackgroundMini.setAlpha(
-                        (int) (mBackgroundAlpha * mGlowBackgroundAlpha * 255));
-                mActiveGlowBackgroundMini.setBounds(mGlowBackgroundRect);
-                mActiveGlowBackgroundMini.draw(canvas);
-                if (modifiedClipRect) {
-                    canvas.restore();
-                }
-            }
         }
 
         if (mCrosshairsVisibility > 0.0f) {
@@ -691,13 +629,6 @@
         return false;
     }
 
-    public void setAcceptsDrops(boolean acceptsDrops) {
-        if (mAcceptsDrops != acceptsDrops) {
-            mAcceptsDrops = acceptsDrops;
-            invalidate();
-        }
-    }
-
     @Override
     public void removeAllViews() {
         clearOccupiedCells();
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 7f3ae86..a0412af 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -86,10 +86,25 @@
         return (d != null) ? d : getFullResDefaultActivityIcon();
     }
 
-    public Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
+    public Drawable getFullResIcon(String packageName, int iconId) {
         Resources resources;
         try {
-            resources = packageManager.getResourcesForApplication(
+            resources = mPackageManager.getResourcesForApplication(packageName);
+        } catch (PackageManager.NameNotFoundException e) {
+            resources = null;
+        }
+        if (resources != null) {
+            if (iconId != 0) {
+                return getFullResIcon(resources, iconId);
+            }
+        }
+        return getFullResDefaultActivityIcon();
+    }
+
+    public Drawable getFullResIcon(ResolveInfo info) {
+        Resources resources;
+        try {
+            resources = mPackageManager.getResourcesForApplication(
                     info.activityInfo.applicationInfo);
         } catch (PackageManager.NameNotFoundException e) {
             resources = null;
@@ -198,7 +213,7 @@
             }
 
             entry.icon = Utilities.createIconBitmap(
-                    getFullResIcon(info, mPackageManager), mContext);
+                    getFullResIcon(info), mContext);
         }
         return entry;
     }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 9b3a339..d8a8bb2 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -94,6 +94,9 @@
     protected float mLastMotionY;
     protected float mTotalMotionX;
     private int mLastScreenCenter = -1;
+    private int[] mChildOffsets;
+    private int[] mChildRelativeOffsets;
+    private int[] mChildOffsetsWithLayoutScale;
 
     protected final static int TOUCH_STATE_REST = 0;
     protected final static int TOUCH_STATE_SCROLLING = 1;
@@ -135,7 +138,6 @@
     private PageSwitchListener mPageSwitchListener;
 
     private ArrayList<Boolean> mDirtyPageContent;
-    private boolean mDirtyPageAlpha = true;
 
     // choice modes
     protected static final int CHOICE_MODE_NONE = 0;
@@ -386,13 +388,11 @@
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
             if (mScrollX != mScroller.getCurrX() || mScrollY != mScroller.getCurrY()) {
-                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();
@@ -519,6 +519,7 @@
     // tightens the layout accordingly
     public void setLayoutScale(float childrenScale) {
         mLayoutScale = childrenScale;
+        invalidateCachedOffsets();
 
         // Now we need to do a re-layout, but preserving absolute X and Y coordinates
         int childCount = getChildCount();
@@ -596,80 +597,25 @@
         if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
             mFirstLayout = false;
         }
-    }
-
-    protected void forceUpdateAdjacentPagesAlpha() {
-        mDirtyPageAlpha = true;
-        updateAdjacentPagesAlpha();
-    }
-
-    protected void updateAdjacentPagesAlpha() {
-        if (mFadeInAdjacentScreens) {
-            if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
-                int screenWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
-                int halfScreenSize = screenWidth / 2;
-                int screenCenter = mScrollX + halfScreenSize + mPaddingLeft;
-                final int childCount = getChildCount();
-                for (int i = 0; i < childCount; ++i) {
-                    View layout = (View) getPageAt(i);
-                    int childWidth = getScaledMeasuredWidth(layout);
-                    int halfChildWidth = (childWidth / 2);
-                    int childCenter = getChildOffset(i) + halfChildWidth;
-
-                    // On the first layout, we may not have a width nor a proper offset, so for now
-                    // we should just assume full page width (and calculate the offset according to
-                    // that).
-                    if (childWidth <= 0) {
-                        childWidth = screenWidth;
-                        childCenter = (i * childWidth) + (childWidth / 2);
-                    }
-
-                    int d = halfChildWidth;
-                    int distanceFromScreenCenter = childCenter - screenCenter;
-                    if (distanceFromScreenCenter > 0) {
-                        if (i > 0) {
-                            d += getScaledMeasuredWidth(getPageAt(i - 1)) / 2;
-                        } else {
-                            continue;
-                        }
-                    } else {
-                        if (i < childCount - 1) {
-                            d += getScaledMeasuredWidth(getPageAt(i + 1)) / 2;
-                        } else {
-                            continue;
-                        }
-                    }
-                    d += mPageSpacing;
-
-                    // Preventing potential divide-by-zero
-                    d = Math.max(1, d);
-
-                    float dimAlpha = (float) (Math.abs(distanceFromScreenCenter)) / d;
-                    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;
-                    }
-
-                    // Due to the way we're setting alpha on our children in PagedViewCellLayout,
-                    // this optimization causes alpha to not be properly updated sometimes (repro
-                    // case: in xlarge mode, swipe to second page in All Apps, then click on "My
-                    // Apps" tab. the page will have alpha 0 until you swipe it). Removing
-                    // optimization fixes the issue, but we should fix this in a better manner
-                    //if (Float.compare(alpha, layout.getAlpha()) != 0) {
-                        layout.setAlpha(alpha);
-                    //}
-                }
-                mDirtyPageAlpha = false;
-            }
-        }
+        invalidateCachedOffsets();
     }
 
     protected void screenScrolled(int screenCenter) {
-        updateScrollingIndicator();
+        if (isScrollingIndicatorEnabled()) {
+            updateScrollingIndicator();
+        }
+        if (mFadeInAdjacentScreens) {
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                if (child != null) {
+                    float scrollProgress = getScrollProgress(screenCenter, child, i);
+                    float alpha = 1 - Math.abs(scrollProgress);
+                    child.setFastAlpha(alpha);
+                    child.fastInvalidate();
+                }
+            }
+            invalidate();
+        }
     }
 
     @Override
@@ -682,6 +628,71 @@
         invalidate();
     }
 
+    protected void invalidateCachedOffsets() {
+        int count = getChildCount();
+        if (count == 0) return;
+
+        mChildOffsets = new int[count];
+        mChildRelativeOffsets = new int[count];
+        mChildOffsetsWithLayoutScale = new int[count];
+        for (int i = 0; i < count; i++) {
+            mChildOffsets[i] = -1;
+            mChildRelativeOffsets[i] = -1;
+            mChildOffsetsWithLayoutScale[i] = -1;
+        }
+    }
+
+    protected int getChildOffset(int index) {
+        int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
+                mChildOffsets : mChildOffsetsWithLayoutScale;
+
+        if (childOffsets != null && childOffsets[index] != -1) {
+            return childOffsets[index];
+        } else {
+            if (getChildCount() == 0)
+                return 0;
+
+            int offset = getRelativeChildOffset(0);
+            for (int i = 0; i < index; ++i) {
+                offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
+            }
+            if (childOffsets != null) {
+                childOffsets[index] = offset;
+            }
+            return offset;
+        }
+    }
+
+    protected int getRelativeChildOffset(int index) {
+        if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
+            return mChildRelativeOffsets[index];
+        } else {
+            final int padding = mPaddingLeft + mPaddingRight;
+            final int offset = mPaddingLeft +
+                    (getMeasuredWidth() - padding - getChildWidth(index)) / 2;
+            if (mChildRelativeOffsets != null) {
+                mChildRelativeOffsets[index] = offset;
+            }
+            return offset;
+        }
+    }
+
+    protected int getScaledRelativeChildOffset(int index) {
+        final int padding = mPaddingLeft + mPaddingRight;
+        final int offset = mPaddingLeft + (getMeasuredWidth() - padding -
+                getScaledMeasuredWidth(getPageAt(index))) / 2;
+        return offset;
+    }
+
+    protected int getScaledMeasuredWidth(View child) {
+        // This functions are called enough times that it actually makes a difference in the
+        // profiler -- so just inline the max() here
+        final int measuredWidth = child.getMeasuredWidth();
+        final int minWidth = mMinimumWidth;
+        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
+        return (int) (maxWidth * mLayoutScale + 0.5f);
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         int halfScreenSize = getMeasuredWidth() / 2;
@@ -689,7 +700,6 @@
 
         if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
             screenScrolled(screenCenter);
-            updateAdjacentPagesAlpha();
             mLastScreenCenter = screenCenter;
             mForceScreenScrolled = false;
         }
@@ -1322,13 +1332,6 @@
         return -1;
     }
 
-    protected void setMinimumWidthOverride(int minimumWidth) {
-        mMinimumWidth = minimumWidth;
-    }
-    protected void resetMinimumWidthOverride() {
-        mMinimumWidth = 0;
-    }
-
     protected int getChildWidth(int index) {
         // This functions are called enough times that it actually makes a difference in the
         // profiler -- so just inline the max() here
@@ -1337,36 +1340,6 @@
         return (minWidth > measuredWidth) ? minWidth : measuredWidth;
     }
 
-    protected int getRelativeChildOffset(int index) {
-        int padding = mPaddingLeft + mPaddingRight;
-        return mPaddingLeft + (getMeasuredWidth() - padding - getChildWidth(index)) / 2;
-    }
-    protected int getScaledRelativeChildOffset(int index) {
-        int padding = mPaddingLeft + mPaddingRight;
-        return mPaddingLeft + (getMeasuredWidth() - padding -
-                getScaledMeasuredWidth(getPageAt(index))) / 2;
-    }
-
-    protected int getChildOffset(int index) {
-        if (getChildCount() == 0)
-            return 0;
-
-        int offset = getRelativeChildOffset(0);
-        for (int i = 0; i < index; ++i) {
-            offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
-        }
-        return offset;
-    }
-
-    protected int getScaledMeasuredWidth(View child) {
-        // This functions are called enough times that it actually makes a difference in the
-        // profiler -- so just inline the max() here
-        final int measuredWidth = child.getMeasuredWidth();
-        final int minWidth = mMinimumWidth;
-        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
-        return (int) (maxWidth * mLayoutScale + 0.5f);
-    }
-
     int getPageNearestToCenterOfScreen() {
         int minDistanceFromScreenCenter = Integer.MAX_VALUE;
         int minDistanceFromScreenCenterIndex = -1;
@@ -1726,8 +1699,6 @@
 
             // Load any pages that are necessary for the current window of views
             loadAssociatedPages(mCurrentPage, immediateAndOnly);
-            mDirtyPageAlpha = true;
-            updateAdjacentPagesAlpha();
             requestLayout();
         }
     }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 0c297dd..a6ba98e 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -192,7 +192,6 @@
     private Runnable mDelayedResizeRunnable;
     private int mDisplayWidth;
     private int mDisplayHeight;
-    private boolean mIsStaticWallpaper;
     private int mWallpaperTravelWidth;
 
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
@@ -639,7 +638,6 @@
 
     protected void onPageBeginMoving() {
         super.onPageBeginMoving();
-        mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null;
 
         if (isHardwareAccelerated()) {
             updateChildrenLayersEnabled();
@@ -692,12 +690,6 @@
     };
 
     // As a ratio of screen height, the total distance we want the parallax effect to span
-    // vertically
-    private float wallpaperTravelToScreenHeightRatio(int width, int height) {
-        return 1.1f;
-    }
-
-    // As a ratio of screen height, the total distance we want the parallax effect to span
     // horizontally
     private float wallpaperTravelToScreenWidthRatio(int width, int height) {
         float aspectRatio = width / (float) height;
@@ -739,7 +731,7 @@
         // parallax effects
         if (LauncherApplication.isScreenLarge()) {
             mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
-            mWallpaperHeight = (int)(maxDim * wallpaperTravelToScreenHeightRatio(maxDim, minDim));
+            mWallpaperHeight = maxDim;
         } else {
             mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
             mWallpaperHeight = maxDim;
@@ -765,52 +757,31 @@
     }
 
     private float wallpaperOffsetForCurrentScroll() {
-        final boolean overScrollWallpaper = LauncherApplication.isScreenLarge();
-        final boolean isStaticWallpaper = mIsStaticWallpaper;
         // The wallpaper travel width is how far, from left to right, the wallpaper will move
-        // at this orientation (for example, in portrait mode we don't move all the way to the
-        // edges of the wallpaper, or otherwise the parallax effect would be too strong)
-        int wallpaperTravelWidth = mWallpaperTravelWidth;
-        if (!overScrollWallpaper || !isStaticWallpaper) {
-            wallpaperTravelWidth = mWallpaperWidth;
+        // at this orientation. On tablets in portrait mode we don't move all the way to the
+        // edges of the wallpaper, or otherwise the parallax effect would be too strong.
+        int wallpaperTravelWidth = mWallpaperWidth;
+        if (LauncherApplication.isScreenLarge()) {
+            wallpaperTravelWidth = mWallpaperTravelWidth;
         }
 
         // Set wallpaper offset steps (1 / (number of screens - 1))
-        // We have 3 vertical offset states (centered, and then top/bottom aligned
-        // for all apps/customize)
-        if (LauncherApplication.isScreenLarge()) {
-            mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f / (3 - 1));
-        } else {
-            mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
-        }
+        mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
 
-        // For the purposes of computing the scrollRange and overScrollOffset, we ignore
-        // assume that mLayoutScale is 1. This means that when we're in spring-loaded mode,
+        // For the purposes of computing the scrollRange and overScrollOffset, we assume
+        // that mLayoutScale is 1. This means that when we're in spring-loaded mode,
         // there's no discrepancy between the wallpaper offset for a given page.
         float layoutScale = mLayoutScale;
         mLayoutScale = 1f;
         int scrollRange = getScrollRange();
-        float scrollProgressOffset = 0;
-
-        // Account for over scroll: you only see the absolute edge of the wallpaper if
-        // you over scroll as far as you can in landscape mode. Only do this for static wallpapers
-        // because live wallpapers (and probably 3rd party wallpaper providers) rely on the offset
-        // being even intervals from 0 to 1 (eg [0, 0.25, 0.5, 0.75, 1])
-        if (isStaticWallpaper && overScrollWallpaper) {
-            int overScrollOffset = (int) (maxOverScroll() * mDisplayWidth);
-            scrollProgressOffset += overScrollOffset / (float) getScrollRange();
-            scrollRange += 2 * overScrollOffset;
-        }
 
         // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale
-
-        float adjustedScrollX = overScrollWallpaper ?
-                mScrollX : Math.max(0, Math.min(mScrollX, mMaxScrollX));
+        float adjustedScrollX = Math.max(0, Math.min(mScrollX, mMaxScrollX));
         adjustedScrollX *= mWallpaperScrollRatio;
         mLayoutScale = layoutScale;
 
         float scrollProgress =
-            adjustedScrollX / (float) scrollRange + scrollProgressOffset;
+            adjustedScrollX / (float) scrollRange;
         float offsetInDips = wallpaperTravelWidth * scrollProgress +
             (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
         float offset = offsetInDips / (float) mWallpaperWidth;
@@ -889,8 +860,6 @@
         float mVerticalCatchupConstant = 0.35f;
 
         public WallpaperOffsetInterpolator() {
-            mVerticalWallpaperOffset = LauncherApplication.isScreenLarge() ? 0.5f : 0f;
-            mFinalVerticalWallpaperOffset = LauncherApplication.isScreenLarge() ? 0.5f : 0f;
         }
 
         public void setOverrideHorizontalCatchupConstant(boolean override) {
@@ -1151,10 +1120,16 @@
                                 backgroundAlphaInterpolator(Math.abs(scrollProgress)));
                     }
                 }
-                cl.setTranslationX(translationX);
-                cl.setRotationY(rotation);
+                cl.setFastTranslationX(translationX);
+                cl.setFastRotationY(rotation);
+                if (mFadeInAdjacentScreens && !isSmall()) {
+                    float alpha = 1 - Math.abs(scrollProgress);
+                    cl.setFastAlpha(alpha);
+                }
+                cl.fastInvalidate();
             }
         }
+        invalidate();
     }
 
     private void resetCellLayoutTransforms(CellLayout cl, boolean left) {
@@ -1188,10 +1163,12 @@
 
     @Override
     protected void screenScrolled(int screenCenter) {
-        super.screenScrolled(screenCenter);
         if (LauncherApplication.isScreenLarge()) {
+            // We don't call super.screenScrolled() here because we handle the adjacent pages alpha
+            // ourselves (for efficiency), and there are no scrolling indicators to update.
             screenScrolledLargeUI(screenCenter);
         } else {
+            super.screenScrolled(screenCenter);
             screenScrolledStandardUI(screenCenter);
         }
     }
@@ -1379,13 +1356,6 @@
                 position[0], position[1], 0, null);
     }
 
-    @Override
-    protected void updateAdjacentPagesAlpha() {
-        if (!isSmall()) {
-            super.updateAdjacentPagesAlpha();
-        }
-    }
-
     /*
      * This interpolator emulates the rate at which the perceived scale of an object changes
      * as its distance from a camera increases. When this interpolator is applied to a scale
@@ -1525,6 +1495,9 @@
     }
 
     void changeState(final State state, boolean animated, int delay) {
+        if (mState == state) {
+            return;
+        }
         if (mFirstLayout) {
             // (mFirstLayout == "first layout has not happened yet")
             // cancel any pending shrinks that were set earlier
@@ -1545,7 +1518,6 @@
 
         final State oldState = mState;
         final boolean oldStateIsNormal = (oldState == State.NORMAL);
-        final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
         final boolean oldStateIsSmall = (oldState == State.SMALL);
         mState = state;
         final boolean stateIsNormal = (state == State.NORMAL);
@@ -2390,7 +2362,6 @@
 
             // Show the current page outlines to indicate that we can accept this drop
             showOutlines();
-            layout.setIsDragOccuring(true);
             layout.onDragEnter();
             layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, null, null);
 
@@ -2451,7 +2422,6 @@
         }
         case DragEvent.ACTION_DRAG_ENDED:
             // Hide the page outlines after the drop
-            layout.setIsDragOccuring(false);
             layout.onDragExit();
             hideOutlines();
             return true;