Wallpaper preview parallax matches the actual wallpaper's.

Cherry picking the following changes from ub-launcher3-master:
Change-Id: I41c5bbbfdabfeb4e20d77e9b5804842a03211edf
Change-Id: I69afa3f8cc59c77e9c4c25e29e8db8c4beb87462
Change-Id: I82b7ba506d51ee4b3812af5fbdf95d3303b37aef
Change-Id: Id7c2b5483c5535d59be2f8a459ce7788e3c8318a

Bug: 23568800
Change-Id: I343169b9fdc5ceaab3d4b39044627d78b7267868
(cherry picked from commit 3e776a87dc5178ab7d2c31a8db06fe5657db4e4a)
diff --git a/WallpaperPicker/res/anim/fade_out.xml b/WallpaperPicker/res/anim/fade_out.xml
new file mode 100644
index 0000000..2749d92
--- /dev/null
+++ b/WallpaperPicker/res/anim/fade_out.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- startOffset is the same as the duration of the wallpaper_enter animation. We have this delay so
+    that we don't see the wallpaper changing before fading back to the home screen. -->
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+    android:startOffset="@android:integer/config_longAnimTime"
+    android:duration="@android:integer/config_mediumAnimTime"
+    android:fromAlpha="1"
+    android:toAlpha="0"/>
+
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
index 45118bf..cb7090f 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
@@ -45,6 +45,10 @@
         public void onBitmapCropped(byte[] imageBytes);
     }
 
+    public interface OnEndCropHandler {
+        public void run(boolean cropSucceeded);
+    }
+
     private static final int DEFAULT_COMPRESS_QUALITY = 90;
     private static final String LOGTAG = "BitmapCropTask";
 
@@ -59,56 +63,56 @@
     boolean mSetWallpaper;
     boolean mSaveCroppedBitmap;
     Bitmap mCroppedBitmap;
-    Runnable mOnEndRunnable;
+    BitmapCropTask.OnEndCropHandler mOnEndCropHandler;
     Resources mResources;
     BitmapCropTask.OnBitmapCroppedHandler mOnBitmapCroppedHandler;
     boolean mNoCrop;
 
     public BitmapCropTask(Context c, String filePath,
             RectF cropBounds, int rotation, int outWidth, int outHeight,
-            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            boolean setWallpaper, boolean saveCroppedBitmap, OnEndCropHandler onEndCropHandler) {
         mContext = c;
         mInFilePath = filePath;
         init(cropBounds, rotation,
-                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndCropHandler);
     }
 
     public BitmapCropTask(byte[] imageBytes,
             RectF cropBounds, int rotation, int outWidth, int outHeight,
-            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            boolean setWallpaper, boolean saveCroppedBitmap, OnEndCropHandler onEndCropHandler) {
         mInImageBytes = imageBytes;
         init(cropBounds, rotation,
-                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndCropHandler);
     }
 
     public BitmapCropTask(Context c, Uri inUri,
             RectF cropBounds, int rotation, int outWidth, int outHeight,
-            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            boolean setWallpaper, boolean saveCroppedBitmap, OnEndCropHandler onEndCropHandler) {
         mContext = c;
         mInUri = inUri;
         init(cropBounds, rotation,
-                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndCropHandler);
     }
 
     public BitmapCropTask(Context c, Resources res, int inResId,
             RectF cropBounds, int rotation, int outWidth, int outHeight,
-            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            boolean setWallpaper, boolean saveCroppedBitmap, OnEndCropHandler onEndCropHandler) {
         mContext = c;
         mInResId = inResId;
         mResources = res;
         init(cropBounds, rotation,
-                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndCropHandler);
     }
 
     private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
-            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+            boolean setWallpaper, boolean saveCroppedBitmap, OnEndCropHandler onEndCropHandler) {
         mCropBounds = cropBounds;
         mRotation = rotation;
         mOutWidth = outWidth;
         mOutHeight = outHeight;
         mSetWallpaper = setWallpaper;
         mSaveCroppedBitmap = saveCroppedBitmap;
-        mOnEndRunnable = onEndRunnable;
+        mOnEndCropHandler = onEndCropHandler;
     }
 
     public void setOnBitmapCropped(BitmapCropTask.OnBitmapCroppedHandler handler) {
@@ -119,8 +123,8 @@
         mNoCrop = value;
     }
 
-    public void setOnEndRunnable(Runnable onEndRunnable) {
-        mOnEndRunnable = onEndRunnable;
+    public void setOnEndRunnable(OnEndCropHandler onEndCropHandler) {
+        mOnEndCropHandler = onEndCropHandler;
     }
 
     // Helper to setup input stream
@@ -398,8 +402,8 @@
 
     @Override
     protected void onPostExecute(Boolean result) {
-        if (mOnEndRunnable != null) {
-            mOnEndRunnable.run();
+        if (mOnEndCropHandler != null) {
+            mOnEndCropHandler.run(result);
         }
     }
 }
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/CropView.java b/WallpaperPicker/src/com/android/launcher3/CropView.java
index 50f779a..e98e23e 100644
--- a/WallpaperPicker/src/com/android/launcher3/CropView.java
+++ b/WallpaperPicker/src/com/android/launcher3/CropView.java
@@ -31,7 +31,7 @@
 import com.android.photos.views.TiledImageRenderer.TileSource;
 import com.android.photos.views.TiledImageView;
 
-public class CropView extends TiledImageView implements OnScaleGestureListener {
+public class  CropView extends TiledImageView implements OnScaleGestureListener {
 
     private ScaleGestureDetector mScaleGestureDetector;
     private long mTouchDownTime;
@@ -189,6 +189,17 @@
     public void onScaleEnd(ScaleGestureDetector detector) {
     }
 
+    /**
+     * Offsets wallpaper preview according to the state it will be displayed in upon returning home.
+     * @param offset Ranges from 0 to 1, where 0 is the leftmost parallax and 1 is the rightmost.
+     */
+    public void setParallaxOffset(float offset, RectF crop) {
+        offset = Math.max(0, Math.min(offset, 1)); // Make sure the offset is in the correct range.
+        float screenWidth = getWidth() / mRenderer.scale;
+        mCenterX = screenWidth / 2 + offset * (crop.width() - screenWidth) + crop.left;
+        updateCenter();
+    }
+
     public void moveToLeft() {
         if (getWidth() == 0 || getHeight() == 0) {
             final ViewTreeObserver observer = getViewTreeObserver();
diff --git a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
index f46da53..099bbda 100644
--- a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
@@ -54,7 +54,9 @@
             final ComponentName itemComponentName = new ComponentName(
                     mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name);
             Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
-            launchIntent.setComponent(itemComponentName);
+            launchIntent.setComponent(itemComponentName)
+            .putExtra(WallpaperPickerActivity.EXTRA_WALLPAPER_OFFSET,
+                    a.getWallpaperParallaxOffset());
             a.startActivityForResultSafely(
                     launchIntent, WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
         }
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
index f2459dd..0dbd357 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
@@ -124,7 +124,11 @@
                     @Override
                     public void onClick(View v) {
                         boolean finishActivityWhenDone = true;
-                        cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
+                        // Never fade on finish because we return to the app that started us (e.g.
+                        // Photos), not the home screen.
+                        boolean shouldFadeOutOnFinish = false;
+                        cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone,
+                                shouldFadeOutOnFinish);
                     }
                 });
         mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);
@@ -246,8 +250,14 @@
             if (req.moveToLeft) {
                 mCropView.moveToLeft();
             }
-            if (req.scaleProvider != null) {
-                mCropView.setScale(req.scaleProvider.getScale(req.result));
+            if (req.scaleAndOffsetProvider != null) {
+                TileSource src = req.result;
+                Point wallpaperSize = WallpaperUtils.getDefaultWallpaperSize(
+                        getResources(), getWindowManager());
+                RectF crop = Utils.getMaxCropRect(src.getImageWidth(), src.getImageHeight(),
+                        wallpaperSize.x, wallpaperSize.y, false /* leftAligned */);
+                mCropView.setScale(req.scaleAndOffsetProvider.getScale(wallpaperSize, crop));
+                mCropView.setParallaxOffset(req.scaleAndOffsetProvider.getParallaxOffset(), crop);
             }
 
             // Free last image
@@ -265,13 +275,13 @@
     }
 
     public final void setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled,
-            boolean moveToLeft, CropViewScaleProvider scaleProvider, Runnable postExecute) {
+            boolean moveToLeft, CropViewScaleAndOffsetProvider scaleProvider, Runnable postExecute) {
         final LoadRequest req = new LoadRequest();
         req.moveToLeft = moveToLeft;
         req.src = bitmapSource;
         req.touchEnabled = touchEnabled;
         req.postExecute = postExecute;
-        req.scaleProvider = scaleProvider;
+        req.scaleAndOffsetProvider = scaleProvider;
         mCurrentLoadRequest = req;
 
         // Remove any pending requests
@@ -295,17 +305,21 @@
         return getResources().getBoolean(R.bool.allow_rotation);
     }
 
-    protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) {
+    protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone,
+                final boolean shouldFadeOutOnFinish) {
         int rotation = BitmapUtils.getRotationFromExif(getContext(), uri);
         BitmapCropTask cropTask = new BitmapCropTask(
                 getContext(), uri, null, rotation, 0, 0, true, false, null);
         final Point bounds = cropTask.getImageBounds();
-        Runnable onEndCrop = new Runnable() {
-            public void run() {
+        BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
+            public void run(boolean cropSucceeded) {
                 updateWallpaperDimensions(bounds.x, bounds.y);
                 if (finishActivityWhenDone) {
                     setResult(Activity.RESULT_OK);
                     finish();
+                    if (cropSucceeded && shouldFadeOutOnFinish) {
+                        overridePendingTransition(0, R.anim.fade_out);
+                    }
                 }
             }
         };
@@ -314,8 +328,8 @@
         cropTask.execute();
     }
 
-    protected void cropImageAndSetWallpaper(
-            Resources res, int resId, final boolean finishActivityWhenDone) {
+    protected void cropImageAndSetWallpaper(Resources res, int resId,
+                final boolean finishActivityWhenDone, final boolean shouldFadeOutOnFinish) {
         // crop this image and scale it down to the default wallpaper size for
         // this device
         int rotation = BitmapUtils.getRotationFromExif(res, resId);
@@ -324,14 +338,17 @@
                 getWindowManager());
         RectF crop = Utils.getMaxCropRect(
                 inSize.x, inSize.y, outSize.x, outSize.y, false);
-        Runnable onEndCrop = new Runnable() {
-            public void run() {
+        BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
+            public void run(boolean cropSucceeded) {
                 // Passing 0, 0 will cause launcher to revert to using the
                 // default wallpaper size
                 updateWallpaperDimensions(0, 0);
                 if (finishActivityWhenDone) {
                     setResult(Activity.RESULT_OK);
                     finish();
+                    if (cropSucceeded && shouldFadeOutOnFinish) {
+                        overridePendingTransition(0, R.anim.fade_out);
+                    }
                 }
             }
         };
@@ -342,7 +359,8 @@
 
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     protected void cropImageAndSetWallpaper(Uri uri,
-            BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+            BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler,
+            final boolean finishActivityWhenDone, final boolean shouldFadeOutOnFinish) {
         boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
         // Get the crop
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
@@ -418,13 +436,16 @@
         final int outWidth = (int) Math.round(cropRect.width() * cropScale);
         final int outHeight = (int) Math.round(cropRect.height() * cropScale);
 
-        Runnable onEndCrop = new Runnable() {
-            public void run() {
+        BitmapCropTask.OnEndCropHandler onEndCrop = new BitmapCropTask.OnEndCropHandler() {
+            public void run(boolean cropSucceeded) {
                 updateWallpaperDimensions(outWidth, outHeight);
                 if (finishActivityWhenDone) {
                     setResult(Activity.RESULT_OK);
                     finish();
                 }
+                if (cropSucceeded && shouldFadeOutOnFinish) {
+                    overridePendingTransition(0, R.anim.fade_out);
+                }
             }
         };
         BitmapCropTask cropTask = new BitmapCropTask(getContext(), uri,
@@ -456,12 +477,13 @@
         boolean touchEnabled;
         boolean moveToLeft;
         Runnable postExecute;
-        CropViewScaleProvider scaleProvider;
+        CropViewScaleAndOffsetProvider scaleAndOffsetProvider;
 
         TileSource result;
     }
 
-    interface CropViewScaleProvider {
-        float getScale(TileSource src);
+    interface CropViewScaleAndOffsetProvider {
+        float getScale(Point wallpaperSize, RectF crop);
+        float getParallaxOffset();
     }
 }
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 5985850..041e4aa 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3;
 
-import android.Manifest.permission;
+import android.Manifest;
 import android.animation.LayoutTransition;
 import android.annotation.TargetApi;
 import android.app.ActionBar;
@@ -38,7 +38,6 @@
 import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.Manifest;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -75,10 +74,8 @@
 import com.android.gallery3d.common.BitmapUtils;
 import com.android.gallery3d.common.Utils;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.WallpaperUtils;
 import com.android.photos.BitmapRegionTileSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource;
-import com.android.photos.views.TiledImageRenderer.TileSource;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -90,6 +87,8 @@
 
     public static final int IMAGE_PICK = 5;
     public static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
+    /** An Intent extra used when opening the wallpaper picker from the workspace overlay. */
+    public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
     private static final String TEMP_WALLPAPER_TILES = "TEMP_WALLPAPER_TILES";
     private static final String SELECTED_INDEX = "SELECTED_INDEX";
     private static final int FLAG_POST_DELAY_MILLIS = 200;
@@ -110,6 +109,7 @@
     ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>();
     private SavedWallpaperImages mSavedImages;
     @Thunk int mSelectedIndex = -1;
+    private float mWallpaperParallaxOffset;
 
     public static abstract class WallpaperTileInfo {
         protected View mView;
@@ -179,7 +179,8 @@
                     a.getSavedImages().writeImage(thumb, imageBytes);
                 }
             };
-            a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone);
+            boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
+            a.cropImageAndSetWallpaper(mUri, h, finishActivityWhenDone, shouldFadeOutOnFinish);
         }
         @Override
         public boolean isSelectable() {
@@ -207,7 +208,7 @@
 
                 @Override
                 public void run() {
-                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { 
+                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
                         a.setWallpaperButtonEnabled(true);
                     }
                 }
@@ -215,7 +216,8 @@
         }
         @Override
         public void onSave(WallpaperPickerActivity a) {
-            a.setWallpaper(Uri.fromFile(mFile), true);
+            boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
+            a.setWallpaper(Uri.fromFile(mFile), true, shouldFadeOutOnFinish);
         }
         @Override
         public boolean isSelectable() {
@@ -241,16 +243,16 @@
             a.setWallpaperButtonEnabled(false);
             final BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
                     new BitmapRegionTileSource.ResourceBitmapSource(mResources, mResId);
-            a.setCropViewTileSource(bitmapSource, false, false, new CropViewScaleProvider() {
+            a.setCropViewTileSource(bitmapSource, false, false, new CropViewScaleAndOffsetProvider() {
 
                 @Override
-                public float getScale(TileSource src) {
-                    Point wallpaperSize = WallpaperUtils.getDefaultWallpaperSize(
-                            a.getResources(), a.getWindowManager());
-                    RectF crop = Utils.getMaxCropRect(
-                            src.getImageWidth(), src.getImageHeight(),
-                            wallpaperSize.x, wallpaperSize.y, false);
-                    return wallpaperSize.x / crop.width();
+                public float getScale(Point wallpaperSize, RectF crop) {
+                    return wallpaperSize.x /crop.width();
+                }
+
+                @Override
+                public float getParallaxOffset() {
+                    return a.getWallpaperParallaxOffset();
                 }
             }, new Runnable() {
 
@@ -265,7 +267,9 @@
         @Override
         public void onSave(WallpaperPickerActivity a) {
             boolean finishActivityWhenDone = true;
-            a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone);
+            boolean shouldFadeOutOnFinish = true;
+            a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone,
+                    shouldFadeOutOnFinish);
         }
         @Override
         public boolean isSelectable() {
@@ -296,12 +300,17 @@
             LoadRequest req = new LoadRequest();
             req.moveToLeft = false;
             req.touchEnabled = false;
-            req.scaleProvider = new CropViewScaleProvider() {
+            req.scaleAndOffsetProvider = new CropViewScaleAndOffsetProvider() {
 
                 @Override
-                public float getScale(TileSource src) {
+                public float getScale(Point wallpaperSize, RectF crop) {
                     return 1f;
                 }
+
+                @Override
+                public float getParallaxOffset() {
+                    return 0;
+                }
             };
             req.result = new DrawableTileSource(a.getContext(),
                     defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE);
@@ -461,6 +470,8 @@
             }
         };
 
+        mWallpaperParallaxOffset = getIntent().getFloatExtra(EXTRA_WALLPAPER_OFFSET, 0);
+
         // Populate the built-in wallpapers
         ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
         mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
@@ -661,6 +672,10 @@
         mSetWallpaperButton.setEnabled(enabled);
     }
 
+    public float getWallpaperParallaxOffset() {
+        return mWallpaperParallaxOffset;
+    }
+
     @Thunk void selectTile(View v) {
         if (mSelectedTile != null) {
             mSelectedTile.setSelected(false);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1f843cb..0a085f6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -748,6 +748,9 @@
             return;
         } else if (requestCode == REQUEST_PICK_WALLPAPER) {
             if (resultCode == RESULT_OK && mWorkspace.isInOverviewMode()) {
+                // User could have free-scrolled between pages before picking a wallpaper; make sure
+                // we move to the closest one now to avoid visual jump.
+                mWorkspace.setCurrentPage(mWorkspace.getPageNearestToCenterOfScreen());
                 showWorkspace(false);
             }
             return;
@@ -2744,7 +2747,10 @@
      */
     protected void onClickWallpaperPicker(View v) {
         if (LOGD) Log.d(TAG, "onClickWallpaperPicker");
-        startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER).setPackage(getPackageName()),
+        int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
+        float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
+        startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER).setPackage(getPackageName())
+                        .putExtra(WallpaperPickerActivity.EXTRA_WALLPAPER_OFFSET, offset),
                 REQUEST_PICK_WALLPAPER);
 
         if (mLauncherCallbacks != null) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 856e3b8..b7d7c62 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1410,7 +1410,7 @@
             return false;
         }
 
-        private float wallpaperOffsetForCurrentScroll() {
+        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
@@ -1449,7 +1449,7 @@
                 // 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 =
-                        getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0);
+                        scroll - firstPageScrollX - getLayoutTransitionOffsetForPage(0);
                 float offset = Math.min(1, adjustedScroll / (float) scrollRange);
                 offset = Math.max(0, offset);
 
@@ -1463,6 +1463,10 @@
             }
         }
 
+        private float wallpaperOffsetForCurrentScroll() {
+            return wallpaperOffsetForScroll(getScrollX());
+        }
+
         private int numEmptyScreensToIgnore() {
             int numScrollingPages = getChildCount() - numCustomPages();
             if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {