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 3e776a87dc)
This commit is contained in:
Tony Wickham
2015-09-09 18:21:49 -07:00
parent 605156bd87
commit 6ed058cb6b
8 changed files with 144 additions and 56 deletions

View File

@@ -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"/>

View File

@@ -45,6 +45,10 @@ public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
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 @@ public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
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 @@ public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
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 @@ public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
if (mOnEndRunnable != null) {
mOnEndRunnable.run();
if (mOnEndCropHandler != null) {
mOnEndCropHandler.run(result);
}
}
}

View File

@@ -31,7 +31,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener;
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 class CropView extends TiledImageView implements OnScaleGestureListener {
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();

View File

@@ -54,7 +54,9 @@ public class ThirdPartyWallpaperPickerListAdapter extends BaseAdapter implements
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);
}

View File

@@ -124,7 +124,11 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
@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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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 class WallpaperCropActivity extends BaseActivity implements Handler.Callb
}
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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
@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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
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();
}
}

View File

@@ -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.PorterDuff;
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.BitmapCropTask;
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 class WallpaperPickerActivity extends WallpaperCropActivity {
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
@Override
public void run() {
if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
a.setWallpaperButtonEnabled(true);
}
}
@@ -215,7 +216,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
@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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
@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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
};
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 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
mSetWallpaperButton.setEnabled(enabled);
}
public float getWallpaperParallaxOffset() {
return mWallpaperParallaxOffset;
}
@Thunk void selectTile(View v) {
if (mSelectedTile != null) {
mSelectedTile.setSelected(false);

View File

@@ -748,6 +748,9 @@ public class Launcher extends Activity
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 @@ public class Launcher extends Activity
*/
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) {

View File

@@ -1410,7 +1410,7 @@ public class Workspace extends PagedView
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 @@ public class Workspace extends PagedView
// 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 @@ public class Workspace extends PagedView
}
}
private float wallpaperOffsetForCurrentScroll() {
return wallpaperOffsetForScroll(getScrollX());
}
private int numEmptyScreensToIgnore() {
int numScrollingPages = getChildCount() - numCustomPages();
if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {