Passing the full image and crop hint when setting the wallpaper

Bug: 25454157
Change-Id: Ia0ae7dd4963b72cd7902622847deedfcb5a0eca2
This commit is contained in:
Sunny Goyal
2016-04-15 17:45:39 -07:00
parent 0a197dbbf6
commit fceb9ff0f5
5 changed files with 233 additions and 89 deletions
@@ -47,7 +47,7 @@ import java.io.InputStream;
public class BitmapCropTask extends AsyncTask<Integer, Void, Boolean> {
public interface OnBitmapCroppedHandler {
public void onBitmapCropped(byte[] imageBytes);
public void onBitmapCropped(byte[] imageBytes, Rect cropHint);
}
public interface OnEndCropHandler {
@@ -171,29 +171,42 @@ public class BitmapCropTask extends AsyncTask<Integer, Void, Boolean> {
public boolean cropBitmap(int whichWallpaper) {
boolean failure = false;
WallpaperManager wallpaperManager = null;
if (mSetWallpaper) {
wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
}
if (mSetWallpaper && mNoCrop) {
try {
InputStream is = regenerateInputStream();
if (is != null) {
if (!Utilities.isNycOrAbove()) {
wallpaperManager.setStream(is);
} else {
NycWallpaperUtils.setStream(mContext, is, null, true, whichWallpaper);
}
Utils.closeSilently(is);
}
setWallpaper(is, null, whichWallpaper);
Utils.closeSilently(is);
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
failure = true;
}
return !failure;
} else if (mSetWallpaper && Utilities.isNycOrAbove()
&& mRotation == 0 && mOutWidth > 0 && mOutHeight > 0) {
Rect hint = new Rect();
mCropBounds.roundOut(hint);
InputStream is = null;
try {
is = regenerateInputStream();
if (is == null) {
Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
failure = true;
return false;
}
WallpaperManager.getInstance(mContext).suggestDesiredDimensions(mOutWidth, mOutHeight);
setWallpaper(is, hint, whichWallpaper);
if (mOnBitmapCroppedHandler != null) {
mOnBitmapCroppedHandler.onBitmapCropped(null, hint);
}
failure = false;
} catch (IOException e) {
Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
} finally {
Utils.closeSilently(is);
}
} else {
// Find crop bounds (scaled to original image size)
Rect roundedTrueCrop = new Rect();
@@ -222,7 +235,6 @@ public class BitmapCropTask extends AsyncTask<Integer, Void, Boolean> {
mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
inverseRotateMatrix.mapRect(mCropBounds);
mCropBounds.offset(bounds.x/2, bounds.y/2);
}
mCropBounds.roundOut(roundedTrueCrop);
@@ -369,18 +381,13 @@ public class BitmapCropTask extends AsyncTask<Integer, Void, Boolean> {
ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
if (crop.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
// If we need to set to the wallpaper, set it
if (mSetWallpaper && wallpaperManager != null) {
if (mSetWallpaper) {
try {
byte[] outByteArray = tmpOut.toByteArray();
if (!Utilities.isNycOrAbove()) {
wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
} else {
NycWallpaperUtils.setStream(mContext,
new ByteArrayInputStream(outByteArray), null, true,
whichWallpaper);
}
setWallpaper(new ByteArrayInputStream(outByteArray), null, whichWallpaper);
if (mOnBitmapCroppedHandler != null) {
mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
mOnBitmapCroppedHandler.onBitmapCropped(outByteArray,
new Rect(0, 0, crop.getWidth(), crop.getHeight()));
}
} catch (IOException e) {
Log.w(LOGTAG, "cannot write stream to wallpaper", e);
@@ -409,4 +416,12 @@ public class BitmapCropTask extends AsyncTask<Integer, Void, Boolean> {
mOnEndCropHandler.run(cropSucceeded);
}
}
private void setWallpaper(InputStream in, Rect crop, int whichWallpaper) throws IOException {
if (!Utilities.isNycOrAbove()) {
WallpaperManager.getInstance(mContext.getApplicationContext()).setStream(in);
} else {
NycWallpaperUtils.setStream(mContext, in, crop, true, whichWallpaper);
}
}
}
@@ -19,6 +19,7 @@ package com.android.launcher3;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -148,12 +149,19 @@ public class CropView extends TiledImageView implements OnScaleGestureListener
updateMinScale(w, h, mRenderer.source, false);
}
public void setScale(float scale) {
public void setScaleAndCenter(float scale, float x, float y) {
synchronized (mLock) {
mRenderer.scale = scale;
mCenterX = x;
mCenterY = y;
updateCenter();
}
}
public float getScale() {
return mRenderer.scale;
}
private void updateMinScale(int w, int h, TileSource source, boolean resetScale) {
synchronized (mLock) {
if (resetScale) {
@@ -189,17 +197,6 @@ 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();
@@ -222,6 +219,10 @@ public class CropView extends TiledImageView implements OnScaleGestureListener
mRenderer.centerY = Math.round(mCenterY);
}
public PointF getCenter() {
return new PointF(mCenterX, mCenterY);
}
public void setTouchEnabled(boolean enabled) {
mTouchEnabled = enabled;
}
@@ -25,6 +25,8 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
@@ -33,9 +35,14 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import com.android.launcher3.WallpaperCropActivity.CropViewScaleAndOffsetProvider;
import com.android.photos.views.TiledImageRenderer.TileSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -48,15 +55,42 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
public static class SavedWallpaperTile extends WallpaperPickerActivity.FileWallpaperInfo {
private int mDbId;
public SavedWallpaperTile(int dbId, File target, Drawable thumb) {
// three floats representing scale, centerX and centerY of the crop view in order.
private Float[] mExtras;
public SavedWallpaperTile(int dbId, File target, Drawable thumb, Float[] extras) {
super(target, thumb);
mDbId = dbId;
mExtras = extras != null && extras.length == 3 ? extras : null;
}
@Override
public void onDelete(WallpaperPickerActivity a) {
a.getSavedImages().deleteImage(mDbId);
}
@Override
protected CropViewScaleAndOffsetProvider getCropViewScaleAndOffsetProvider() {
if (mExtras != null) {
return new CropViewScaleAndOffsetProvider() {
@Override
public void updateCropView(WallpaperCropActivity a, TileSource src) {
a.mCropView.setScaleAndCenter(mExtras[0], mExtras[1], mExtras[2]);
}
};
}
return null;
}
@Override
public void onSave(final WallpaperPickerActivity a) {
if (mExtras == null) {
super.onSave(a);
} else {
boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
a.cropImageAndSetWallpaper(Uri.fromFile(mFile), null, true, shouldFadeOutOnFinish);
}
}
}
public SavedWallpaperImages(Context context) {
@@ -74,7 +108,8 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
Cursor result = db.query(ImageDb.TABLE_NAME,
new String[] { ImageDb.COLUMN_ID,
ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME,
ImageDb.COLUMN_IMAGE_FILENAME}, // cols to return
ImageDb.COLUMN_IMAGE_FILENAME,
ImageDb.COLUMN_EXTRAS}, // cols to return
null, // select query
null, // args to select query
null,
@@ -88,9 +123,25 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
Bitmap thumb = BitmapFactory.decodeFile(file.getAbsolutePath());
if (thumb != null) {
Float[] extras = null;
String extraStr = result.getString(3);
if (extraStr != null) {
String[] parts = extraStr.split(",");
extras = new Float[parts.length];
for (int i = 0; i < parts.length; i++) {
try {
extras[i] = Float.parseFloat(parts[i]);
} catch (Exception e) {
extras = null;
break;
}
}
}
mImages.add(new SavedWallpaperTile(result.getInt(0),
new File(mContext.getFilesDir(), result.getString(2)),
new BitmapDrawable(thumb)));
new BitmapDrawable(thumb), extras));
}
}
result.close();
@@ -155,34 +206,55 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
public void writeImage(Bitmap thumbnail, byte[] imageBytes) {
try {
File imageFile = File.createTempFile("wallpaper", "", mContext.getFilesDir());
FileOutputStream imageFileStream =
mContext.openFileOutput(imageFile.getName(), Context.MODE_PRIVATE);
imageFileStream.write(imageBytes);
imageFileStream.close();
File thumbFile = File.createTempFile("wallpaperthumb", "", mContext.getFilesDir());
FileOutputStream thumbFileStream =
mContext.openFileOutput(thumbFile.getName(), Context.MODE_PRIVATE);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
thumbFileStream.close();
SQLiteDatabase db = mDb.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME, thumbFile.getName());
values.put(ImageDb.COLUMN_IMAGE_FILENAME, imageFile.getName());
db.insert(ImageDb.TABLE_NAME, null, values);
writeImage(thumbnail, new ByteArrayInputStream(imageBytes), null);
} catch (IOException e) {
Log.e(TAG, "Failed writing images to storage " + e);
}
}
public void writeImage(Bitmap thumbnail, Uri uri, Float[] extras) {
try {
writeImage(thumbnail, mContext.getContentResolver().openInputStream(uri), extras);
} catch (IOException e) {
Log.e(TAG, "Failed writing images to storage " + e);
}
}
private void writeImage(Bitmap thumbnail, InputStream in, Float[] extras) throws IOException {
File imageFile = File.createTempFile("wallpaper", "", mContext.getFilesDir());
FileOutputStream imageFileStream =
mContext.openFileOutput(imageFile.getName(), Context.MODE_PRIVATE);
byte[] buf = new byte[4096]; // 4k
int len;
while ((len = in.read(buf)) > 0) {
imageFileStream.write(buf, 0, len);
}
imageFileStream.close();
in.close();
File thumbFile = File.createTempFile("wallpaperthumb", "", mContext.getFilesDir());
FileOutputStream thumbFileStream =
mContext.openFileOutput(thumbFile.getName(), Context.MODE_PRIVATE);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
thumbFileStream.close();
SQLiteDatabase db = mDb.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME, thumbFile.getName());
values.put(ImageDb.COLUMN_IMAGE_FILENAME, imageFile.getName());
if (extras != null) {
values.put(ImageDb.COLUMN_EXTRAS, TextUtils.join(",", extras));
}
db.insert(ImageDb.TABLE_NAME, null, values);
}
static class ImageDb extends SQLiteOpenHelper {
final static int DB_VERSION = 1;
final static int DB_VERSION = 2;
final static String TABLE_NAME = "saved_wallpaper_images";
final static String COLUMN_ID = "id";
final static String COLUMN_IMAGE_THUMBNAIL_FILENAME = "image_thumbnail";
final static String COLUMN_IMAGE_FILENAME = "image";
final static String COLUMN_EXTRAS = "extras";
Context mContext;
@@ -209,15 +281,20 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter {
COLUMN_ID + " INTEGER NOT NULL, " +
COLUMN_IMAGE_THUMBNAIL_FILENAME + " TEXT NOT NULL, " +
COLUMN_IMAGE_FILENAME + " TEXT NOT NULL, " +
COLUMN_EXTRAS + " TEXT, " +
"PRIMARY KEY (" + COLUMN_ID + " ASC) " +
");");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
if (oldVersion == 1) {
// Add extras column
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_EXTRAS + " TEXT;");
} else if (oldVersion != newVersion) {
// Delete all the records; they'll be repopulated as this is a cache
db.execSQL("DELETE FROM " + TABLE_NAME);
onCreate(db);
}
}
}
@@ -29,6 +29,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Build;
@@ -269,13 +270,7 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
mCropView.moveToLeft();
}
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);
req.scaleAndOffsetProvider.updateCropView(this, req.result);
}
// Free last image
@@ -502,8 +497,32 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb
TileSource result;
}
interface CropViewScaleAndOffsetProvider {
float getScale(Point wallpaperSize, RectF crop);
float getParallaxOffset();
public static class CropViewScaleAndOffsetProvider {
public float getScale(Point wallpaperSize, RectF crop) {
return 1f;
}
public float getParallaxOffset() {
return 0.5f;
}
public void updateCropView(WallpaperCropActivity a, TileSource src) {
Point wallpaperSize = WallpaperUtils.getDefaultWallpaperSize(
a.getResources(), a.getWindowManager());
RectF crop = Utils.getMaxCropRect(src.getImageWidth(), src.getImageHeight(),
wallpaperSize.x, wallpaperSize.y, false /* leftAligned */);
float scale = getScale(wallpaperSize, crop);
PointF center = a.mCropView.getCenter();
// Offsets wallpaper preview according to the state it will be displayed in upon
// returning home. Offset ranges from 0 to 1, where 0 is the leftmost parallax and
// 1 is the rightmost.
// Make sure the offset is in the correct range.
float offset = Math.max(0, Math.min(getParallaxOffset(), 1));
float screenWidth = a.mCropView.getWidth() / scale;
center.x = screenWidth / 2 + offset * (crop.width() - screenWidth) + crop.left;
a.mCropView.setScaleAndCenter(scale, center.x, center.y);
}
}
}
@@ -31,10 +31,13 @@ import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -83,6 +86,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
public class WallpaperPickerActivity extends WallpaperCropActivity {
@@ -174,12 +178,45 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
public void onSave(final WallpaperPickerActivity a) {
boolean finishActivityWhenDone = true;
BitmapCropTask.OnBitmapCroppedHandler h = new BitmapCropTask.OnBitmapCroppedHandler() {
public void onBitmapCropped(byte[] imageBytes) {
@Override
public void onBitmapCropped(byte[] imageBytes, Rect hint) {
Bitmap thumb = null;
Point thumbSize = getDefaultThumbnailSize(a.getResources());
// rotation is set to 0 since imageBytes has already been correctly rotated
Bitmap thumb = createThumbnail(
thumbSize, null, null, imageBytes, null, 0, 0, true);
a.getSavedImages().writeImage(thumb, imageBytes);
if (imageBytes != null) {
// rotation is set to 0 since imageBytes has already been correctly rotated
thumb = createThumbnail(
thumbSize, null, null, imageBytes, null, 0, 0, true);
a.getSavedImages().writeImage(thumb, imageBytes);
} else {
try {
// Generate thumb
Point size = getDefaultThumbnailSize(a.getResources());
Rect finalCropped = new Rect();
Utils.getMaxCropRect(hint.width(), hint.height(), size.x, size.y, false)
.roundOut(finalCropped);
finalCropped.offset(hint.left, hint.top);
InputStream in = a.getContentResolver().openInputStream(mUri);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(in, true);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = finalCropped.width() / size.x;
thumb = decoder.decodeRegion(finalCropped, options);
decoder.recycle();
Utils.closeSilently(in);
if (thumb != null) {
thumb = Bitmap.createScaledBitmap(thumb, size.x, size.y, true);
}
} catch (IOException e) { }
PointF center = a.mCropView.getCenter();
Float[] extras = new Float[] {
a.mCropView.getScale(),
center.x,
center.y
};
a.getSavedImages().writeImage(thumb, mUri, extras);
}
}
};
boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
@@ -196,7 +233,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
public static class FileWallpaperInfo extends WallpaperTileInfo {
private File mFile;
protected File mFile;
public FileWallpaperInfo(File target, Drawable thumb) {
mFile = target;
@@ -207,7 +244,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
a.setWallpaperButtonEnabled(false);
final BitmapRegionTileSource.UriBitmapSource bitmapSource =
new BitmapRegionTileSource.UriBitmapSource(a.getContext(), Uri.fromFile(mFile));
a.setCropViewTileSource(bitmapSource, false, true, null, new Runnable() {
a.setCropViewTileSource(bitmapSource, false, true, getCropViewScaleAndOffsetProvider(),
new Runnable() {
@Override
public void run() {
@@ -217,6 +255,11 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
}
});
}
protected CropViewScaleAndOffsetProvider getCropViewScaleAndOffsetProvider() {
return null;
}
@Override
public void onSave(WallpaperPickerActivity a) {
boolean shouldFadeOutOnFinish = a.getWallpaperParallaxOffset() == 0f;
@@ -303,18 +346,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity {
LoadRequest req = new LoadRequest();
req.moveToLeft = false;
req.touchEnabled = false;
req.scaleAndOffsetProvider = new CropViewScaleAndOffsetProvider() {
@Override
public float getScale(Point wallpaperSize, RectF crop) {
return 1f;
}
@Override
public float getParallaxOffset() {
return 0.5f;
}
};
req.scaleAndOffsetProvider = new CropViewScaleAndOffsetProvider();
req.result = new DrawableTileSource(a.getContext(),
defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE);
a.onLoadRequestComplete(req, true);