Refactoring WallpaperOffsetInterpolator to a new file
Removing some us unused methods

Change-Id: Ife790e5ca6848fa13dc3fab1bba1e6220bf83743
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
index 6f7a530..759613d 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
@@ -164,40 +164,6 @@
         }
     }
 
-    private RectF mTempRectF = new RectF();
-    public void positionFromMatrix(Matrix matrix) {
-        if (mRenderer.source != null) {
-            final int rotation = mRenderer.source.getRotation();
-            final boolean swap = !(rotation % 180 == 0);
-            final int width = swap ? mRenderer.source.getImageHeight()
-                    : mRenderer.source.getImageWidth();
-            final int height = swap ? mRenderer.source.getImageWidth()
-                    : mRenderer.source.getImageHeight();
-            mTempRectF.set(0, 0, width, height);
-            matrix.mapRect(mTempRectF);
-            matrix.getValues(mValues);
-            int cx = width / 2;
-            int cy = height / 2;
-            float scale = mValues[Matrix.MSCALE_X];
-            int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale);
-            int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale);
-            if (rotation == 90 || rotation == 180) {
-                cx += (mTempRectF.left / scale) - xoffset;
-            } else {
-                cx -= (mTempRectF.left / scale) - xoffset;
-            }
-            if (rotation == 180 || rotation == 270) {
-                cy += (mTempRectF.top / scale) - yoffset;
-            } else {
-                cy -= (mTempRectF.top / scale) - yoffset;
-            }
-            mRenderer.scale = scale;
-            mRenderer.centerX = swap ? cy : cx;
-            mRenderer.centerY = swap ? cx : cy;
-            invalidate();
-        }
-    }
-
     @Thunk class TileRenderer implements Renderer {
 
         private GLES20Canvas mCanvas;
diff --git a/src/com/android/launcher3/AnotherWindowDropTarget.java b/src/com/android/launcher3/AnotherWindowDropTarget.java
index eaac6be..0e18874 100644
--- a/src/com/android/launcher3/AnotherWindowDropTarget.java
+++ b/src/com/android/launcher3/AnotherWindowDropTarget.java
@@ -61,13 +61,4 @@
     // These methods are implemented in Views
     @Override
     public void getHitRectRelativeToDragLayer(Rect outRect) {}
-
-    @Override
-    public void getLocationInDragLayer(int[] loc) {}
-
-    @Override
-    public int getLeft() { return 0; }
-
-    @Override
-    public int getTop() { return 0; }
 }
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 4b94a1a..d882683 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -302,11 +302,6 @@
         return to;
     }
 
-    @Override
-    public void getLocationInDragLayer(int[] loc) {
-        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
-    }
-
     public void enableAccessibleDrag(boolean enable) {
         setOnClickListener(enable ? this : null);
     }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 92e4043..02f9008 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -152,9 +152,6 @@
     private static final boolean DESTRUCTIVE_REORDER = false;
     private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
 
-    static final int LANDSCAPE = 0;
-    static final int PORTRAIT = 1;
-
     private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
     private static final int REORDER_ANIMATION_DURATION = 150;
     @Thunk float mReorderPreviewAnimationMagnitude;
@@ -404,10 +401,6 @@
         mIsDragTarget = false;
     }
 
-    public boolean isDragTarget() {
-        return mIsDragTarget;
-    }
-
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
@@ -450,10 +443,6 @@
                 (ParcelableSparseArray) parcelable : new ParcelableSparseArray();
     }
 
-    public boolean getIsDragOverlapping() {
-        return mIsDragOverlapping;
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         if (!mIsDragTarget) {
@@ -1311,9 +1300,7 @@
      * @param spanX Horizontal span of the object.
      * @param spanY Vertical span of the object.
      * @param direction The favored direction in which the views should move from x, y
-     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
-     *        matches exactly. Otherwise we find the best matching direction.
-     * @param occoupied The array which represents which cells in the CellLayout are occupied
+     * @param occupied The array which represents which cells in the CellLayout are occupied
      * @param blockOccupied The array which represents which cells in the specified block (cellX,
      *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
      * @param result Array in which to place the result, or null (in which case a new array will
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index bab46d9..90b8f1c 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -29,9 +29,7 @@
  */
 public interface DropTarget {
 
-    public static final String TAG = "DropTarget";
-
-    public static class DragObject {
+    class DragObject {
         public int x = -1;
         public int y = -1;
 
@@ -154,7 +152,4 @@
 
     // These methods are implemented in Views
     void getHitRectRelativeToDragLayer(Rect outRect);
-    void getLocationInDragLayer(int[] loc);
-    int getLeft();
-    int getTop();
 }
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 142932f..0bade53 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -947,16 +947,6 @@
         LauncherModel.moveItemsInDatabase(mLauncher, items, mInfo.id, 0);
     }
 
-    public void addItemLocationsInDatabase() {
-        ArrayList<View> list = getItemsInReadingOrder();
-        for (int i = 0; i < list.size(); i++) {
-            View v = list.get(i);
-            ItemInfo info = (ItemInfo) v.getTag();
-            LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
-                    info.cellX, info.cellY);
-        }
-    }
-
     public void notifyDrop() {
         if (mDragInProgress) {
             mItemAddedBackToSelfViaIcon = true;
@@ -1093,11 +1083,6 @@
         mItemsInvalidated = true;
     }
 
-    // TODO remove this once GSA code fix is submitted
-    public ViewGroup getContent() {
-        return (ViewGroup) mContent;
-    }
-
     public int getItemCount() {
         return mContent.getItemCount();
     }
@@ -1344,10 +1329,6 @@
         return mItemsInReadingOrder;
     }
 
-    public void getLocationInDragLayer(int[] loc) {
-        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
-    }
-
     public void onFocusChange(View v, boolean hasFocus) {
         if (v == mFolderName && hasFocus) {
             startEditingFolderName();
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 07bd0aa..7d1cb75 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -360,9 +360,6 @@
         mDragInfo = dragInfo;
     }
 
-    public void onDragOver(Object dragInfo) {
-    }
-
     OnAlarmListener mOnOpenListener = new OnAlarmListener() {
         public void onAlarm(Alarm alarm) {
             ShortcutInfo item;
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 7aff832..594fa3c 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -227,12 +227,6 @@
         return (CellLayout) getChildAt(index);
     }
 
-    public void removeCellLayoutView(View view) {
-        for (int i = getChildCount() - 1; i >= 0; i --) {
-            getPageAt(i).removeView(view);
-        }
-    }
-
     public CellLayout getCurrentCellLayout() {
         return getPageAt(getNextPage());
     }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5711db0..79e7b88 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -431,7 +431,6 @@
      * @return screenId and the coordinates for the item.
      */
     @Thunk Pair<Long, int[]> findSpaceForItem(
-            Context context,
             ArrayList<Long> workspaceScreens,
             ArrayList<Long> addedWorkspaceScreensFinal,
             int spanX, int spanY) {
@@ -525,9 +524,8 @@
                         }
 
                         // Find appropriate space for the item.
-                        Pair<Long, int[]> coords = findSpaceForItem(context,
-                                workspaceScreens, addedWorkspaceScreensFinal,
-                                1, 1);
+                        Pair<Long, int[]> coords = findSpaceForItem(
+                                workspaceScreens, addedWorkspaceScreensFinal, 1, 1);
                         long screenId = coords.first;
                         int[] cordinates = coords.second;
 
@@ -924,51 +922,6 @@
     }
 
     /**
-     * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
-     */
-    FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {
-        final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
-                "_id=? and (itemType=? or itemType=?)",
-                new String[] { String.valueOf(id),
-                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);
-
-        try {
-            if (c.moveToFirst()) {
-                final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
-                final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
-                final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
-                final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-                final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-                final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-                final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);
-
-                FolderInfo folderInfo = null;
-                switch (c.getInt(itemTypeIndex)) {
-                    case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                        folderInfo = findOrMakeFolder(folderList, id);
-                        break;
-                }
-
-                // Do not trim the folder label, as is was set by the user.
-                folderInfo.title = c.getString(titleIndex);
-                folderInfo.id = id;
-                folderInfo.container = c.getInt(containerIndex);
-                folderInfo.screenId = c.getInt(screenIndex);
-                folderInfo.cellX = c.getInt(cellXIndex);
-                folderInfo.cellY = c.getInt(cellYIndex);
-                folderInfo.options = c.getInt(optionsIndex);
-
-                return folderInfo;
-            }
-        } finally {
-            c.close();
-        }
-
-        return null;
-    }
-
-    /**
      * Add an item to the database in a specified container. Sets the container, screen, cellX and
      * cellY fields of the item. Also assigns an ID to the item.
      */
@@ -1030,15 +983,6 @@
         runOnWorkerThread(r);
     }
 
-    /**
-     * Creates a new unique child id, for a given cell span across all layouts.
-     */
-    static int getCellLayoutChildId(
-            long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {
-        return (((int) container & 0xFF) << 24)
-                | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
-    }
-
     private static ArrayList<ItemInfo> getItemsByPackageName(
             final String pn, final UserHandleCompat user) {
         ItemInfoFilter filter  = new ItemInfoFilter() {
@@ -1392,10 +1336,6 @@
         return screenIds;
     }
 
-    public boolean isAllAppsLoaded() {
-        return mAllAppsLoaded;
-    }
-
     /**
      * Runnable for the thread that loads the contents of the launcher:
      *   - workspace icons
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index a86a2f9..db0f845 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -247,15 +247,6 @@
                 + " user=" + user + ")";
     }
 
-    public static void dumpShortcutInfoList(String tag, String label,
-            ArrayList<ShortcutInfo> list) {
-        Log.d(tag, label + " size=" + list.size());
-        for (ShortcutInfo info: list) {
-            Log.d(tag, "   title=\"" + info.title + " icon=" + info.mIcon
-                    + " customIcon=" + info.customIcon);
-        }
-    }
-
     public ComponentName getTargetComponent() {
         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
     }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2bedb9f..9a61def 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -29,7 +29,6 @@
 import android.content.ComponentName;
 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.Paint;
@@ -59,7 +58,6 @@
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
-import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.UninstallDropTarget.UninstallSource;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
@@ -74,6 +72,7 @@
 import com.android.launcher3.dragndrop.SpringLoadedDragController;
 import com.android.launcher3.util.LongArrayMap;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.util.WallpaperUtils;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -114,7 +113,6 @@
 
     private LayoutTransition mLayoutTransition;
     @Thunk final WallpaperManager mWallpaperManager;
-    @Thunk IBinder mWindowToken;
 
     private ShortcutAndWidgetContainer mDragSourceInternal;
 
@@ -209,10 +207,7 @@
     public static final int DRAG_BITMAP_PADDING = 2;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
-    WallpaperOffsetInterpolator mWallpaperOffset;
-    @Thunk boolean mWallpaperIsLiveWallpaper;
-    @Thunk int mNumPagesForWallpaperParallax;
-    @Thunk float mLastSetWallpaperOffsetSteps = 0;
+    final WallpaperOffsetInterpolator mWallpaperOffset;
 
     @Thunk Runnable mDelayedResizeRunnable;
     private Runnable mDelayedSnapToPageRunnable;
@@ -306,6 +301,8 @@
         mFadeInAdjacentScreens = false;
         mWallpaperManager = WallpaperManager.getInstance(context);
 
+        mWallpaperOffset = new WallpaperOffsetInterpolator(this);
+
         mSpringLoadedShrinkFactor =
                 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
         mOverviewModeShrinkFactor =
@@ -428,8 +425,6 @@
         setMinScale(mOverviewModeShrinkFactor);
         setupLayoutTransition();
 
-        mWallpaperOffset = new WallpaperOffsetInterpolator();
-
         mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);
 
         // Set the wallpaper dimensions when Launcher starts up
@@ -815,8 +810,7 @@
     }
 
     public CellLayout getScreenWithId(long screenId) {
-        CellLayout layout = mWorkspaceScreens.get(screenId);
-        return layout;
+        return mWorkspaceScreens.get(screenId);
     }
 
     public long getIdForScreen(CellLayout layout) {
@@ -1327,191 +1321,6 @@
         snapToPage(getPageIndexForScreenId(screenId), r);
     }
 
-    class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {
-        float mFinalOffset = 0.0f;
-        float mCurrentOffset = 0.5f; // to force an initial update
-        boolean mWaitingForUpdate;
-        Choreographer mChoreographer;
-        Interpolator mInterpolator;
-        boolean mAnimating;
-        long mAnimationStartTime;
-        float mAnimationStartOffset;
-        private final int ANIMATION_DURATION = 250;
-        // Don't use all the wallpaper for parallax until you have at least this many pages
-        private final int MIN_PARALLAX_PAGE_SPAN = 3;
-        int mNumScreens;
-
-        public WallpaperOffsetInterpolator() {
-            mChoreographer = Choreographer.getInstance();
-            mInterpolator = new DecelerateInterpolator(1.5f);
-        }
-
-        @Override
-        public void doFrame(long frameTimeNanos) {
-            updateOffset(false);
-        }
-
-        private void updateOffset(boolean force) {
-            if (mWaitingForUpdate || force) {
-                mWaitingForUpdate = false;
-                if (computeScrollOffset() && mWindowToken != null) {
-                    try {
-                        mWallpaperManager.setWallpaperOffsets(mWindowToken,
-                                mWallpaperOffset.getCurrX(), 0.5f);
-                        setWallpaperOffsetSteps();
-                    } catch (IllegalArgumentException e) {
-                        Log.e(TAG, "Error updating wallpaper offset: " + e);
-                    }
-                }
-            }
-        }
-
-        public boolean computeScrollOffset() {
-            final float oldOffset = mCurrentOffset;
-            if (mAnimating) {
-                long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;
-                float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;
-                float t1 = mInterpolator.getInterpolation(t0);
-                mCurrentOffset = mAnimationStartOffset +
-                        (mFinalOffset - mAnimationStartOffset) * t1;
-                mAnimating = durationSinceAnimation < ANIMATION_DURATION;
-            } else {
-                mCurrentOffset = mFinalOffset;
-            }
-
-            if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {
-                scheduleUpdate();
-            }
-            if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {
-                return true;
-            }
-            return false;
-        }
-
-        public float wallpaperOffsetForScroll(int scroll) {
-            // TODO: do different behavior if it's  a live wallpaper?
-            // Don't use up all the wallpaper parallax until you have at least
-            // MIN_PARALLAX_PAGE_SPAN pages
-            int numScrollingPages = getNumScreensExcludingEmptyAndCustom();
-            int parallaxPageSpan;
-            if (mWallpaperIsLiveWallpaper) {
-                parallaxPageSpan = numScrollingPages - 1;
-            } else {
-                parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);
-            }
-            mNumPagesForWallpaperParallax = parallaxPageSpan;
-
-            if (getChildCount() <= 1) {
-                if (mIsRtl) {
-                    return 1 - 1.0f/mNumPagesForWallpaperParallax;
-                }
-                return 0;
-            }
-
-            // Exclude the leftmost page
-            int emptyExtraPages = numEmptyScreensToIgnore();
-            int firstIndex = numCustomPages();
-            // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)
-            int lastIndex = getChildCount() - 1 - emptyExtraPages;
-            if (mIsRtl) {
-                int temp = firstIndex;
-                firstIndex = lastIndex;
-                lastIndex = temp;
-            }
-
-            int firstPageScrollX = getScrollForPage(firstIndex);
-            int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;
-            if (scrollRange == 0) {
-                return 0;
-            } else {
-                // Sometimes the left parameter of the pages is animated during a layout transition;
-                // this parameter offsets it to keep the wallpaper from animating as well
-                int adjustedScroll =
-                        scroll - firstPageScrollX - getLayoutTransitionOffsetForPage(0);
-                float offset = Math.min(1, adjustedScroll / (float) scrollRange);
-                offset = Math.max(0, offset);
-
-                // On RTL devices, push the wallpaper offset to the right if we don't have enough
-                // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)
-                if (!mWallpaperIsLiveWallpaper && numScrollingPages < MIN_PARALLAX_PAGE_SPAN
-                        && mIsRtl) {
-                    return offset * (parallaxPageSpan - numScrollingPages + 1) / parallaxPageSpan;
-                }
-                return offset * (numScrollingPages - 1) / parallaxPageSpan;
-            }
-        }
-
-        private float wallpaperOffsetForCurrentScroll() {
-            return wallpaperOffsetForScroll(getScrollX());
-        }
-
-        private int numEmptyScreensToIgnore() {
-            int numScrollingPages = getChildCount() - numCustomPages();
-            if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-
-        private int getNumScreensExcludingEmptyAndCustom() {
-            int numScrollingPages = getChildCount() - numEmptyScreensToIgnore() - numCustomPages();
-            return numScrollingPages;
-        }
-
-        public void syncWithScroll() {
-            float offset = wallpaperOffsetForCurrentScroll();
-            mWallpaperOffset.setFinalX(offset);
-            updateOffset(true);
-        }
-
-        public float getCurrX() {
-            return mCurrentOffset;
-        }
-
-        public float getFinalX() {
-            return mFinalOffset;
-        }
-
-        private void animateToFinal() {
-            mAnimating = true;
-            mAnimationStartOffset = mCurrentOffset;
-            mAnimationStartTime = System.currentTimeMillis();
-        }
-
-        private void setWallpaperOffsetSteps() {
-            // Set wallpaper offset steps (1 / (number of screens - 1))
-            float xOffset = 1.0f / mNumPagesForWallpaperParallax;
-            if (xOffset != mLastSetWallpaperOffsetSteps) {
-                mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);
-                mLastSetWallpaperOffsetSteps = xOffset;
-            }
-        }
-
-        public void setFinalX(float x) {
-            scheduleUpdate();
-            mFinalOffset = Math.max(0f, Math.min(x, 1.0f));
-            if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {
-                if (mNumScreens > 0) {
-                    // Don't animate if we're going from 0 screens
-                    animateToFinal();
-                }
-                mNumScreens = getNumScreensExcludingEmptyAndCustom();
-            }
-        }
-
-        private void scheduleUpdate() {
-            if (!mWaitingForUpdate) {
-                mChoreographer.postFrameCallback(this);
-                mWaitingForUpdate = true;
-            }
-        }
-
-        public void jumpToFinal() {
-            mCurrentOffset = mFinalOffset;
-        }
-    }
-
     @Override
     public void computeScroll() {
         super.computeScroll();
@@ -1532,18 +1341,6 @@
         }
     }
 
-    float backgroundAlphaInterpolator(float r) {
-        float pivotA = 0.1f;
-        float pivotB = 0.4f;
-        if (r < pivotA) {
-            return 0;
-        } else if (r > pivotB) {
-            return 1.0f;
-        } else {
-            return (r - pivotA)/(pivotB - pivotA);
-        }
-    }
-
     private void updatePageAlphaValues(int screenCenter) {
         if (mWorkspaceFadeInAdjacentScreens &&
                 !workspaceInModalState() &&
@@ -1647,13 +1444,12 @@
         if (!am.isTouchExplorationEnabled()) {
             return null;
         }
-        OnClickListener listener = new OnClickListener() {
+        return new OnClickListener() {
             @Override
             public void onClick(View arg0) {
                 mLauncher.showOverviewMode(true);
             }
         };
-        return listener;
     }
 
     @Override
@@ -1665,14 +1461,15 @@
 
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mWindowToken = getWindowToken();
+        IBinder windowToken = getWindowToken();
+        mWallpaperOffset.setWindowToken(windowToken);
         computeScroll();
-        mDragController.setWindowToken(mWindowToken);
+        mDragController.setWindowToken(windowToken);
     }
 
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mWindowToken = null;
+        mWallpaperOffset.setWindowToken(null);
     }
 
     protected void onResume() {
@@ -1690,10 +1487,7 @@
         if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {
             setWallpaperDimension();
         }
-        mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;
-        // Force the wallpaper offset steps to be set again, because another app might have changed
-        // them
-        mLastSetWallpaperOffsetSteps = 0f;
+        mWallpaperOffset.onResume();
     }
 
     @Override
@@ -2816,19 +2610,6 @@
                 (int) (mTempXY[1] + scale * boundingLayout.getMeasuredHeight()));
     }
 
-    public void getViewLocationRelativeToSelf(View v, int[] location) {
-        getLocationInWindow(location);
-        int x = location[0];
-        int y = location[1];
-
-        v.getLocationInWindow(location);
-        int vX = location[0];
-        int vY = location[1];
-
-        location[0] = vX - x;
-        location[1] = vY - y;
-    }
-
     @Override
     public void onDragEnter(DragObject d) {
         if (ENFORCE_DRAG_EVENT_ORDER) {
@@ -3754,47 +3535,6 @@
         }
     }
 
-    void saveWorkspaceToDb() {
-        saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            saveWorkspaceScreenToDb(cl);
-        }
-    }
-
-    void saveWorkspaceScreenToDb(CellLayout cl) {
-        int count = cl.getShortcutsAndWidgets().getChildCount();
-
-        long screenId = getIdForScreen(cl);
-        int container = Favorites.CONTAINER_DESKTOP;
-
-        Hotseat hotseat = mLauncher.getHotseat();
-        if (mLauncher.isHotseatLayout(cl)) {
-            screenId = -1;
-            container = Favorites.CONTAINER_HOTSEAT;
-        }
-
-        for (int i = 0; i < count; i++) {
-            View v = cl.getShortcutsAndWidgets().getChildAt(i);
-            ItemInfo info = (ItemInfo) v.getTag();
-            // Null check required as the AllApps button doesn't have an item info
-            if (info != null) {
-                int cellX = info.cellX;
-                int cellY = info.cellY;
-                if (container == Favorites.CONTAINER_HOTSEAT) {
-                    cellX = hotseat.getCellXFromOrder((int) info.screenId);
-                    cellY = hotseat.getCellYFromOrder((int) info.screenId);
-                }
-                LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX, cellY);
-            }
-            if (v instanceof FolderIcon) {
-                FolderIcon fi = (FolderIcon) v;
-                fi.getFolder().addItemLocationsInDatabase();
-            }
-        }
-    }
-
     @Override
     public float getIntrinsicIconScaleFactor() {
         return 1f;
@@ -4392,10 +4132,6 @@
                 page + 1 - delta, nScreens);
     }
 
-    public void getLocationInDragLayer(int[] loc) {
-        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
-    }
-
     @Override
     public void fillInLaunchSourceData(Bundle sourceData) {
         sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN);
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index a4bd753..d61117c 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -166,11 +166,9 @@
      * @param bmp The bitmap that represents the view being dragged
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
+     * @param viewImageBounds the position of the image inside the view
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
      *        {@link #DRAG_ACTION_COPY}
-     * @param viewImageBounds the position of the image inside the view
-     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
-     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
      */
     public void startDrag(View v, Bitmap bmp, DragSource source, ItemInfo dragInfo,
             Rect viewImageBounds, int dragAction, float initialDragViewScale) {
@@ -269,44 +267,6 @@
     }
 
     /**
-     * Draw the view into a bitmap.
-     */
-    Bitmap getViewBitmap(View v) {
-        v.clearFocus();
-        v.setPressed(false);
-
-        boolean willNotCache = v.willNotCacheDrawing();
-        v.setWillNotCacheDrawing(false);
-
-        // Reset the drawing cache background color to fully transparent
-        // for the duration of this operation
-        int color = v.getDrawingCacheBackgroundColor();
-        v.setDrawingCacheBackgroundColor(0);
-        float alpha = v.getAlpha();
-        v.setAlpha(1.0f);
-
-        if (color != 0) {
-            v.destroyDrawingCache();
-        }
-        v.buildDrawingCache();
-        Bitmap cacheBitmap = v.getDrawingCache();
-        if (cacheBitmap == null) {
-            Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
-            return null;
-        }
-
-        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
-
-        // Restore the view
-        v.destroyDrawingCache();
-        v.setAlpha(alpha);
-        v.setWillNotCacheDrawing(willNotCache);
-        v.setDrawingCacheBackgroundColor(color);
-
-        return bitmap;
-    }
-
-    /**
      * Call this from a drag source view like this:
      *
      * <pre>
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
new file mode 100644
index 0000000..1fbd0dc
--- /dev/null
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -0,0 +1,225 @@
+package com.android.launcher3.util;
+
+import android.app.WallpaperManager;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+
+/**
+ * Utility class to handle wallpaper scrolling along with workspace.
+ */
+public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {
+    private static final String TAG = "WPOffsetInterpolator";
+    private static final int ANIMATION_DURATION = 250;
+
+    // Don't use all the wallpaper for parallax until you have at least this many pages
+    private static final int MIN_PARALLAX_PAGE_SPAN = 3;
+
+    private final Choreographer mChoreographer;
+    private final Interpolator mInterpolator;
+    private final WallpaperManager mWallpaperManager;
+    private final Workspace mWorkspace;
+    private final boolean mIsRtl;
+
+    private IBinder mWindowToken;
+    private boolean mWallpaperIsLiveWallpaper;
+    private float mLastSetWallpaperOffsetSteps = 0;
+
+    private float mFinalOffset = 0.0f;
+    private float mCurrentOffset = 0.5f; // to force an initial update
+    private boolean mWaitingForUpdate;
+
+    private boolean mAnimating;
+    private long mAnimationStartTime;
+    private float mAnimationStartOffset;
+    int mNumScreens;
+    int mNumPagesForWallpaperParallax;
+
+    public WallpaperOffsetInterpolator(Workspace workspace) {
+        mChoreographer = Choreographer.getInstance();
+        mInterpolator = new DecelerateInterpolator(1.5f);
+
+        mWorkspace = workspace;
+        mWallpaperManager = WallpaperManager.getInstance(workspace.getContext());
+        mIsRtl = Utilities.isRtl(workspace.getResources());
+    }
+
+    @Override
+    public void doFrame(long frameTimeNanos) {
+        updateOffset(false);
+    }
+
+    private void updateOffset(boolean force) {
+        if (mWaitingForUpdate || force) {
+            mWaitingForUpdate = false;
+            if (computeScrollOffset() && mWindowToken != null) {
+                try {
+                    mWallpaperManager.setWallpaperOffsets(mWindowToken, getCurrX(), 0.5f);
+                    setWallpaperOffsetSteps();
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Error updating wallpaper offset: " + e);
+                }
+            }
+        }
+    }
+
+    public boolean computeScrollOffset() {
+        final float oldOffset = mCurrentOffset;
+        if (mAnimating) {
+            long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;
+            float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;
+            float t1 = mInterpolator.getInterpolation(t0);
+            mCurrentOffset = mAnimationStartOffset +
+                    (mFinalOffset - mAnimationStartOffset) * t1;
+            mAnimating = durationSinceAnimation < ANIMATION_DURATION;
+        } else {
+            mCurrentOffset = mFinalOffset;
+        }
+
+        if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {
+            scheduleUpdate();
+        }
+        if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {
+            return true;
+        }
+        return false;
+    }
+
+    public float wallpaperOffsetForScroll(int scroll) {
+        // TODO: do different behavior if it's  a live wallpaper?
+        // Don't use up all the wallpaper parallax until you have at least
+        // MIN_PARALLAX_PAGE_SPAN pages
+        int numScrollingPages = getNumScreensExcludingEmptyAndCustom();
+        int parallaxPageSpan;
+        if (mWallpaperIsLiveWallpaper) {
+            parallaxPageSpan = numScrollingPages - 1;
+        } else {
+            parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);
+        }
+        mNumPagesForWallpaperParallax = parallaxPageSpan;
+
+        if (mWorkspace.getChildCount() <= 1) {
+            if (mIsRtl) {
+                return 1 - 1.0f/mNumPagesForWallpaperParallax;
+            }
+            return 0;
+        }
+
+        // Exclude the leftmost page
+        int emptyExtraPages = numEmptyScreensToIgnore();
+        int firstIndex = mWorkspace.numCustomPages();
+        // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)
+        int lastIndex = mWorkspace.getChildCount() - 1 - emptyExtraPages;
+        if (mIsRtl) {
+            int temp = firstIndex;
+            firstIndex = lastIndex;
+            lastIndex = temp;
+        }
+
+        int firstPageScrollX = mWorkspace.getScrollForPage(firstIndex);
+        int scrollRange = mWorkspace.getScrollForPage(lastIndex) - firstPageScrollX;
+        if (scrollRange == 0) {
+            return 0;
+        } else {
+            // Sometimes the left parameter of the pages is animated during a layout transition;
+            // this parameter offsets it to keep the wallpaper from animating as well
+            int adjustedScroll =
+                    scroll - firstPageScrollX - mWorkspace.getLayoutTransitionOffsetForPage(0);
+            float offset = Math.min(1, adjustedScroll / (float) scrollRange);
+            offset = Math.max(0, offset);
+
+            // On RTL devices, push the wallpaper offset to the right if we don't have enough
+            // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)
+            if (!mWallpaperIsLiveWallpaper && numScrollingPages < MIN_PARALLAX_PAGE_SPAN
+                    && mIsRtl) {
+                return offset * (parallaxPageSpan - numScrollingPages + 1) / parallaxPageSpan;
+            }
+            return offset * (numScrollingPages - 1) / parallaxPageSpan;
+        }
+    }
+
+    private float wallpaperOffsetForCurrentScroll() {
+        return wallpaperOffsetForScroll(mWorkspace.getScrollX());
+    }
+
+    private int numEmptyScreensToIgnore() {
+        int numScrollingPages = mWorkspace.getChildCount() - mWorkspace.numCustomPages();
+        if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private int getNumScreensExcludingEmptyAndCustom() {
+        return mWorkspace.getChildCount() - numEmptyScreensToIgnore() - mWorkspace.numCustomPages();
+    }
+
+    public void syncWithScroll() {
+        float offset = wallpaperOffsetForCurrentScroll();
+        setFinalX(offset);
+        updateOffset(true);
+    }
+
+    public float getCurrX() {
+        return mCurrentOffset;
+    }
+
+    public float getFinalX() {
+        return mFinalOffset;
+    }
+
+    private void animateToFinal() {
+        mAnimating = true;
+        mAnimationStartOffset = mCurrentOffset;
+        mAnimationStartTime = System.currentTimeMillis();
+    }
+
+    private void setWallpaperOffsetSteps() {
+        // Set wallpaper offset steps (1 / (number of screens - 1))
+        float xOffset = 1.0f / mNumPagesForWallpaperParallax;
+        if (xOffset != mLastSetWallpaperOffsetSteps) {
+            mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);
+            mLastSetWallpaperOffsetSteps = xOffset;
+        }
+    }
+
+    public void setFinalX(float x) {
+        scheduleUpdate();
+        mFinalOffset = Math.max(0f, Math.min(x, 1.0f));
+        if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {
+            if (mNumScreens > 0) {
+                // Don't animate if we're going from 0 screens
+                animateToFinal();
+            }
+            mNumScreens = getNumScreensExcludingEmptyAndCustom();
+        }
+    }
+
+    private void scheduleUpdate() {
+        if (!mWaitingForUpdate) {
+            mChoreographer.postFrameCallback(this);
+            mWaitingForUpdate = true;
+        }
+    }
+
+    public void jumpToFinal() {
+        mCurrentOffset = mFinalOffset;
+    }
+
+    public void onResume() {
+        mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;
+        // Force the wallpaper offset steps to be set again, because another app might have changed
+        // them
+        mLastSetWallpaperOffsetSteps = 0f;
+    }
+
+    public void setWindowToken(IBinder token) {
+        mWindowToken = token;
+    }
+}
\ No newline at end of file