From e612775922ec9f8cc4e5cb976bc62b3312a3de0e Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 21 Jul 2015 17:01:26 -0700 Subject: resolved conflicts for merge of 13ef17a3 to mnc-dr-dev b/22609402 Change-Id: I140cf972d57e14737a6f91c0b4a8ec6c7ff1af2b --- .../android/launcher3/WallpaperCropActivity.java | 793 +++++---------------- 1 file changed, 182 insertions(+), 611 deletions(-) (limited to 'WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java') diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java index fa8ec64c2..f2bb50944 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.annotation.TargetApi; import android.app.ActionBar; import android.app.Activity; import android.app.WallpaperManager; @@ -25,42 +26,41 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Canvas; import android.graphics.Matrix; -import android.graphics.Paint; import android.graphics.Point; -import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; -import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; import android.util.Log; import android.view.Display; import android.view.View; -import android.view.WindowManager; import android.widget.Toast; +import com.android.gallery3d.common.BitmapCropTask; +import com.android.gallery3d.common.BitmapUtils; import com.android.gallery3d.common.Utils; -import com.android.gallery3d.exif.ExifInterface; +import com.android.launcher3.base.BaseActivity; +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.BitmapRegionTileSource.BitmapSource.InBitmapProvider; +import com.android.photos.views.TiledImageRenderer.TileSource; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; -public class WallpaperCropActivity extends Activity { +public class WallpaperCropActivity extends BaseActivity implements Handler.Callback { private static final String LOGTAG = "Launcher3.CropActivity"; - protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width"; - protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height"; - private static final int DEFAULT_COMPRESS_QUALITY = 90; + protected static final String WALLPAPER_WIDTH_KEY = WallpaperUtils.WALLPAPER_WIDTH_KEY; + protected static final String WALLPAPER_HEIGHT_KEY = WallpaperUtils.WALLPAPER_HEIGHT_KEY; + /** * The maximum bitmap size we allow to be returned through the intent. * Intents have a maximum of 1MB in total size. However, the Bitmap seems to @@ -69,17 +69,31 @@ public class WallpaperCropActivity extends Activity { * array instead of a Bitmap instance to avoid overhead. */ public static final int MAX_BMAP_IN_INTENT = 750000; - private static final float WALLPAPER_SCREENS_SPAN = 2f; + public static final float WALLPAPER_SCREENS_SPAN = WallpaperUtils.WALLPAPER_SCREENS_SPAN; - protected static Point sDefaultWallpaperSize; + private static final int MSG_LOAD_IMAGE = 1; protected CropView mCropView; + protected View mProgressView; protected Uri mUri; protected View mSetWallpaperButton; + private HandlerThread mLoaderThread; + private Handler mLoaderHandler; + @Thunk LoadRequest mCurrentLoadRequest; + private byte[] mTempStorageForDecoding = new byte[16 * 1024]; + // A weak-set of reusable bitmaps + @Thunk Set mReusableBitmaps = + Collections.newSetFromMap(new WeakHashMap()); + @Override - protected void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + mLoaderThread = new HandlerThread("wallpaper_loader"); + mLoaderThread.start(); + mLoaderHandler = new Handler(mLoaderThread.getLooper(), this); + init(); if (!enableRotation()) { setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT); @@ -90,6 +104,7 @@ public class WallpaperCropActivity extends Activity { setContentView(R.layout.wallpaper_cropper); mCropView = (CropView) findViewById(R.id.cropView); + mProgressView = findViewById(R.id.loading); Intent cropIntent = getIntent(); final Uri imageUri = cropIntent.getData(); @@ -116,13 +131,12 @@ public class WallpaperCropActivity extends Activity { // Load image in background final BitmapRegionTileSource.UriBitmapSource bitmapSource = - new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024); + new BitmapRegionTileSource.UriBitmapSource(getContext(), imageUri); mSetWallpaperButton.setEnabled(false); Runnable onLoad = new Runnable() { public void run() { if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) { - Toast.makeText(WallpaperCropActivity.this, - getString(R.string.wallpaper_load_fail), + Toast.makeText(getContext(), R.string.wallpaper_load_fail, Toast.LENGTH_LONG).show(); finish(); } else { @@ -130,188 +144,163 @@ public class WallpaperCropActivity extends Activity { } } }; - setCropViewTileSource(bitmapSource, true, false, onLoad); + setCropViewTileSource(bitmapSource, true, false, null, onLoad); } @Override - protected void onDestroy() { + public void onDestroy() { if (mCropView != null) { mCropView.destroy(); } + if (mLoaderThread != null) { + mLoaderThread.quit(); + } super.onDestroy(); } - public void setCropViewTileSource( - final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, - final boolean moveToLeft, final Runnable postExecute) { - final Context context = WallpaperCropActivity.this; - final View progressView = findViewById(R.id.loading); - final AsyncTask loadBitmapTask = new AsyncTask() { - protected Void doInBackground(Void...args) { - if (!isCancelled()) { - try { - bitmapSource.loadInBackground(); - } catch (SecurityException securityException) { - if (isDestroyed()) { - // Temporarily granted permissions are revoked when the activity - // finishes, potentially resulting in a SecurityException here. - // Even though {@link #isDestroyed} might also return true in different - // situations where the configuration changes, we are fine with - // catching these cases here as well. - cancel(false); - } else { - // otherwise it had a different cause and we throw it further - throw securityException; + /** + * This is called on {@link #mLoaderThread} + */ + @Override + public boolean handleMessage(Message msg) { + if (msg.what == MSG_LOAD_IMAGE) { + final LoadRequest req = (LoadRequest) msg.obj; + try { + req.src.loadInBackground(new InBitmapProvider() { + + @Override + public Bitmap forPixelCount(int count) { + Bitmap bitmapToReuse = null; + // Find the smallest bitmap that satisfies the pixel count limit + synchronized (mReusableBitmaps) { + int currentBitmapSize = Integer.MAX_VALUE; + for (Bitmap b : mReusableBitmaps) { + int bitmapSize = b.getWidth() * b.getHeight(); + if ((bitmapSize >= count) && (bitmapSize < currentBitmapSize)) { + bitmapToReuse = b; + currentBitmapSize = bitmapSize; + } + } + + if (bitmapToReuse != null) { + mReusableBitmaps.remove(bitmapToReuse); + } } + return bitmapToReuse; } + }); + } catch (SecurityException securityException) { + if (isActivityDestroyed()) { + // Temporarily granted permissions are revoked when the activity + // finishes, potentially resulting in a SecurityException here. + // Even though {@link #isDestroyed} might also return true in different + // situations where the configuration changes, we are fine with + // catching these cases here as well. + return true; + } else { + // otherwise it had a different cause and we throw it further + throw securityException; } - return null; } - protected void onPostExecute(Void arg) { - if (!isCancelled()) { - progressView.setVisibility(View.INVISIBLE); - if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { - mCropView.setTileSource( - new BitmapRegionTileSource(context, bitmapSource), null); - mCropView.setTouchEnabled(touchEnabled); - if (moveToLeft) { - mCropView.moveToLeft(); - } + + req.result = new BitmapRegionTileSource(getContext(), req.src, mTempStorageForDecoding); + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (req == mCurrentLoadRequest) { + onLoadRequestComplete(req, + req.src.getLoadingState() == BitmapSource.State.LOADED); + } else { + addReusableBitmap(req.result); } } - if (postExecute != null) { - postExecute.run(); - } - } - }; - // We don't want to show the spinner every time we load an image, because that would be - // annoying; instead, only start showing the spinner if loading the image has taken - // longer than 1 sec (ie 1000 ms) - progressView.postDelayed(new Runnable() { - public void run() { - if (loadBitmapTask.getStatus() != AsyncTask.Status.FINISHED) { - progressView.setVisibility(View.VISIBLE); - } - } - }, 1000); - loadBitmapTask.execute(); - } - - public boolean enableRotation() { - return getResources().getBoolean(R.bool.allow_rotation); + }); + return true; + } + return false; } - public static String getSharedPreferencesKey() { - return LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY; + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + protected boolean isActivityDestroyed() { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) + && isDestroyed(); } - // As a ratio of screen height, the total distance we want the parallax effect to span - // horizontally - private static float wallpaperTravelToScreenWidthRatio(int width, int height) { - float aspectRatio = width / (float) height; - - // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width - // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width - // We will use these two data points to extrapolate how much the wallpaper parallax effect - // to span (ie travel) at any aspect ratio: - - final float ASPECT_RATIO_LANDSCAPE = 16/10f; - final float ASPECT_RATIO_PORTRAIT = 10/16f; - final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; - final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; - - // To find out the desired width at different aspect ratios, we use the following two - // formulas, where the coefficient on x is the aspect ratio (width/height): - // (16/10)x + y = 1.5 - // (10/16)x + y = 1.2 - // We solve for x and y and end up with a final formula: - final float x = - (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / - (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); - final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; - return x * aspectRatio + y; + @Thunk void addReusableBitmap(TileSource src) { + synchronized (mReusableBitmaps) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT + && src instanceof BitmapRegionTileSource) { + Bitmap preview = ((BitmapRegionTileSource) src).getBitmap(); + if (preview != null && preview.isMutable()) { + mReusableBitmaps.add(preview); + } + } + } } - static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) { - if (sDefaultWallpaperSize == null) { - Point minDims = new Point(); - Point maxDims = new Point(); - windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); - - int maxDim = Math.max(maxDims.x, maxDims.y); - int minDim = Math.max(minDims.x, minDims.y); - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { - Point realSize = new Point(); - windowManager.getDefaultDisplay().getRealSize(realSize); - maxDim = Math.max(realSize.x, realSize.y); - minDim = Math.min(realSize.x, realSize.y); + protected void onLoadRequestComplete(LoadRequest req, boolean success) { + mCurrentLoadRequest = null; + if (success) { + TileSource oldSrc = mCropView.getTileSource(); + mCropView.setTileSource(req.result, null); + mCropView.setTouchEnabled(req.touchEnabled); + if (req.moveToLeft) { + mCropView.moveToLeft(); + } + if (req.scaleProvider != null) { + mCropView.setScale(req.scaleProvider.getScale(req.result)); } - // We need to ensure that there is enough extra space in the wallpaper - // for the intended parallax effects - final int defaultWidth, defaultHeight; - if (isScreenLarge(res)) { - defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); - defaultHeight = maxDim; - } else { - defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); - defaultHeight = maxDim; + // Free last image + if (oldSrc != null) { + // Call yield instead of recycle, as we only want to free GL resource. + // We can still reuse the bitmap for decoding any other image. + oldSrc.getPreview().yield(); } - sDefaultWallpaperSize = new Point(defaultWidth, defaultHeight); + addReusableBitmap(oldSrc); } - return sDefaultWallpaperSize; + if (req.postExecute != null) { + req.postExecute.run(); + } + mProgressView.setVisibility(View.GONE); } - public static int getRotationFromExif(String path) { - return getRotationFromExifHelper(path, null, 0, null, null); - } + public final void setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled, + boolean moveToLeft, CropViewScaleProvider scaleProvider, Runnable postExecute) { + final LoadRequest req = new LoadRequest(); + req.moveToLeft = moveToLeft; + req.src = bitmapSource; + req.touchEnabled = touchEnabled; + req.postExecute = postExecute; + req.scaleProvider = scaleProvider; + mCurrentLoadRequest = req; - public static int getRotationFromExif(Context context, Uri uri) { - return getRotationFromExifHelper(null, null, 0, context, uri); - } + // Remove any pending requests + mLoaderHandler.removeMessages(MSG_LOAD_IMAGE); + Message.obtain(mLoaderHandler, MSG_LOAD_IMAGE, req).sendToTarget(); - public static int getRotationFromExif(Resources res, int resId) { - return getRotationFromExifHelper(null, res, resId, null, null); + // We don't want to show the spinner every time we load an image, because that would be + // annoying; instead, only start showing the spinner if loading the image has taken + // longer than 1 sec (ie 1000 ms) + mProgressView.postDelayed(new Runnable() { + public void run() { + if (mCurrentLoadRequest == req) { + mProgressView.setVisibility(View.VISIBLE); + } + } + }, 1000); } - private static int getRotationFromExifHelper( - String path, Resources res, int resId, Context context, Uri uri) { - ExifInterface ei = new ExifInterface(); - InputStream is = null; - BufferedInputStream bis = null; - try { - if (path != null) { - ei.readExif(path); - } else if (uri != null) { - is = context.getContentResolver().openInputStream(uri); - bis = new BufferedInputStream(is); - ei.readExif(bis); - } else { - is = res.openRawResource(resId); - bis = new BufferedInputStream(is); - ei.readExif(bis); - } - Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); - if (ori != null) { - return ExifInterface.getRotationForOrientationValue(ori.shortValue()); - } - } catch (IOException e) { - Log.w(LOGTAG, "Getting exif data failed", e); - } catch (NullPointerException e) { - // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid - Log.w(LOGTAG, "Getting exif data failed", e); - } finally { - Utils.closeSilently(bis); - Utils.closeSilently(is); - } - return 0; + + public boolean enableRotation() { + return getResources().getBoolean(R.bool.allow_rotation); } protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) { - int rotation = getRotationFromExif(this, uri); + int rotation = BitmapUtils.getRotationFromExif(getContext(), uri); BitmapCropTask cropTask = new BitmapCropTask( - this, uri, null, rotation, 0, 0, true, false, null); + getContext(), uri, null, rotation, 0, 0, true, false, null); final Point bounds = cropTask.getImageBounds(); Runnable onEndCrop = new Runnable() { public void run() { @@ -331,11 +320,11 @@ public class WallpaperCropActivity extends Activity { Resources res, int resId, final boolean finishActivityWhenDone) { // crop this image and scale it down to the default wallpaper size for // this device - int rotation = getRotationFromExif(res, resId); + int rotation = BitmapUtils.getRotationFromExif(res, resId); Point inSize = mCropView.getSourceDimensions(); - Point outSize = getDefaultWallpaperSize(getResources(), + Point outSize = WallpaperUtils.getDefaultWallpaperSize(getResources(), getWindowManager()); - RectF crop = getMaxCropRect( + RectF crop = Utils.getMaxCropRect( inSize.x, inSize.y, outSize.x, outSize.y, false); Runnable onEndCrop = new Runnable() { public void run() { @@ -348,18 +337,14 @@ public class WallpaperCropActivity extends Activity { } } }; - BitmapCropTask cropTask = new BitmapCropTask(this, res, resId, + BitmapCropTask cropTask = new BitmapCropTask(getContext(), res, resId, crop, rotation, outSize.x, outSize.y, true, false, onEndCrop); cropTask.execute(); } - private static boolean isScreenLarge(Resources res) { - Configuration config = res.getConfiguration(); - return config.smallestScreenWidthDp >= 720; - } - + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) protected void cropImageAndSetWallpaper(Uri uri, - OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) { + BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) { boolean centerCrop = getResources().getBoolean(R.bool.center_crop); // Get the crop boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; @@ -370,7 +355,7 @@ public class WallpaperCropActivity extends Activity { d.getSize(displaySize); boolean isPortrait = displaySize.x < displaySize.y; - Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(), + Point defaultWallpaperSize = WallpaperUtils.getDefaultWallpaperSize(getResources(), getWindowManager()); // Get the crop RectF cropRect = mCropView.getCrop(); @@ -444,7 +429,7 @@ public class WallpaperCropActivity extends Activity { } } }; - BitmapCropTask cropTask = new BitmapCropTask(this, uri, + BitmapCropTask cropTask = new BitmapCropTask(getContext(), uri, cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop); if (onBitmapCroppedHandler != null) { cropTask.setOnBitmapCropped(onBitmapCroppedHandler); @@ -452,375 +437,9 @@ public class WallpaperCropActivity extends Activity { cropTask.execute(); } - public interface OnBitmapCroppedHandler { - public void onBitmapCropped(byte[] imageBytes); - } - - protected static class BitmapCropTask extends AsyncTask { - Uri mInUri = null; - Context mContext; - String mInFilePath; - byte[] mInImageBytes; - int mInResId = 0; - RectF mCropBounds = null; - int mOutWidth, mOutHeight; - int mRotation; - String mOutputFormat = "jpg"; // for now - boolean mSetWallpaper; - boolean mSaveCroppedBitmap; - Bitmap mCroppedBitmap; - Runnable mOnEndRunnable; - Resources mResources; - OnBitmapCroppedHandler mOnBitmapCroppedHandler; - boolean mNoCrop; - - public BitmapCropTask(Context c, String filePath, - RectF cropBounds, int rotation, int outWidth, int outHeight, - boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { - mContext = c; - mInFilePath = filePath; - init(cropBounds, rotation, - outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); - } - - public BitmapCropTask(byte[] imageBytes, - RectF cropBounds, int rotation, int outWidth, int outHeight, - boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { - mInImageBytes = imageBytes; - init(cropBounds, rotation, - outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); - } - - public BitmapCropTask(Context c, Uri inUri, - RectF cropBounds, int rotation, int outWidth, int outHeight, - boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { - mContext = c; - mInUri = inUri; - init(cropBounds, rotation, - outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); - } - - public BitmapCropTask(Context c, Resources res, int inResId, - RectF cropBounds, int rotation, int outWidth, int outHeight, - boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { - mContext = c; - mInResId = inResId; - mResources = res; - init(cropBounds, rotation, - outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); - } - - private void init(RectF cropBounds, int rotation, int outWidth, int outHeight, - boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { - mCropBounds = cropBounds; - mRotation = rotation; - mOutWidth = outWidth; - mOutHeight = outHeight; - mSetWallpaper = setWallpaper; - mSaveCroppedBitmap = saveCroppedBitmap; - mOnEndRunnable = onEndRunnable; - } - - public void setOnBitmapCropped(OnBitmapCroppedHandler handler) { - mOnBitmapCroppedHandler = handler; - } - - public void setNoCrop(boolean value) { - mNoCrop = value; - } - - public void setOnEndRunnable(Runnable onEndRunnable) { - mOnEndRunnable = onEndRunnable; - } - - // Helper to setup input stream - private InputStream regenerateInputStream() { - if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { - Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + - "image byte array given"); - } else { - try { - if (mInUri != null) { - return new BufferedInputStream( - mContext.getContentResolver().openInputStream(mInUri)); - } else if (mInFilePath != null) { - return mContext.openFileInput(mInFilePath); - } else if (mInImageBytes != null) { - return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes)); - } else { - return new BufferedInputStream(mResources.openRawResource(mInResId)); - } - } catch (FileNotFoundException e) { - Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); - } - } - return null; - } - - public Point getImageBounds() { - InputStream is = regenerateInputStream(); - if (is != null) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(is, null, options); - Utils.closeSilently(is); - if (options.outWidth != 0 && options.outHeight != 0) { - return new Point(options.outWidth, options.outHeight); - } - } - return null; - } - - public void setCropBounds(RectF cropBounds) { - mCropBounds = cropBounds; - } - - public Bitmap getCroppedBitmap() { - return mCroppedBitmap; - } - public boolean cropBitmap() { - boolean failure = false; - - - WallpaperManager wallpaperManager = null; - if (mSetWallpaper) { - wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext()); - } - - - if (mSetWallpaper && mNoCrop) { - try { - InputStream is = regenerateInputStream(); - if (is != null) { - wallpaperManager.setStream(is); - Utils.closeSilently(is); - } - } catch (IOException e) { - Log.w(LOGTAG, "cannot write stream to wallpaper", e); - failure = true; - } - return !failure; - } else { - // Find crop bounds (scaled to original image size) - Rect roundedTrueCrop = new Rect(); - Matrix rotateMatrix = new Matrix(); - Matrix inverseRotateMatrix = new Matrix(); - - Point bounds = getImageBounds(); - if (mRotation > 0) { - rotateMatrix.setRotate(mRotation); - inverseRotateMatrix.setRotate(-mRotation); - - mCropBounds.roundOut(roundedTrueCrop); - mCropBounds = new RectF(roundedTrueCrop); - - if (bounds == null) { - Log.w(LOGTAG, "cannot get bounds for image"); - failure = true; - return false; - } - - float[] rotatedBounds = new float[] { bounds.x, bounds.y }; - rotateMatrix.mapPoints(rotatedBounds); - rotatedBounds[0] = Math.abs(rotatedBounds[0]); - rotatedBounds[1] = Math.abs(rotatedBounds[1]); - - mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2); - inverseRotateMatrix.mapRect(mCropBounds); - mCropBounds.offset(bounds.x/2, bounds.y/2); - - } - - mCropBounds.roundOut(roundedTrueCrop); - - if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) { - Log.w(LOGTAG, "crop has bad values for full size image"); - failure = true; - return false; - } - - // See how much we're reducing the size of the image - int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth, - roundedTrueCrop.height() / mOutHeight)); - // Attempt to open a region decoder - BitmapRegionDecoder decoder = null; - InputStream is = null; - try { - is = regenerateInputStream(); - if (is == null) { - Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString()); - failure = true; - return false; - } - decoder = BitmapRegionDecoder.newInstance(is, false); - Utils.closeSilently(is); - } catch (IOException e) { - Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); - } finally { - Utils.closeSilently(is); - is = null; - } - - Bitmap crop = null; - if (decoder != null) { - // Do region decoding to get crop bitmap - BitmapFactory.Options options = new BitmapFactory.Options(); - if (scaleDownSampleSize > 1) { - options.inSampleSize = scaleDownSampleSize; - } - crop = decoder.decodeRegion(roundedTrueCrop, options); - decoder.recycle(); - } - - if (crop == null) { - // BitmapRegionDecoder has failed, try to crop in-memory - is = regenerateInputStream(); - Bitmap fullSize = null; - if (is != null) { - BitmapFactory.Options options = new BitmapFactory.Options(); - if (scaleDownSampleSize > 1) { - options.inSampleSize = scaleDownSampleSize; - } - fullSize = BitmapFactory.decodeStream(is, null, options); - Utils.closeSilently(is); - } - if (fullSize != null) { - // Find out the true sample size that was used by the decoder - scaleDownSampleSize = bounds.x / fullSize.getWidth(); - mCropBounds.left /= scaleDownSampleSize; - mCropBounds.top /= scaleDownSampleSize; - mCropBounds.bottom /= scaleDownSampleSize; - mCropBounds.right /= scaleDownSampleSize; - mCropBounds.roundOut(roundedTrueCrop); - - // Adjust values to account for issues related to rounding - if (roundedTrueCrop.width() > fullSize.getWidth()) { - // Adjust the width - roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth(); - } - if (roundedTrueCrop.right > fullSize.getWidth()) { - // Adjust the left value - int adjustment = roundedTrueCrop.left - - Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width()); - roundedTrueCrop.left -= adjustment; - roundedTrueCrop.right -= adjustment; - } - if (roundedTrueCrop.height() > fullSize.getHeight()) { - // Adjust the height - roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight(); - } - if (roundedTrueCrop.bottom > fullSize.getHeight()) { - // Adjust the top value - int adjustment = roundedTrueCrop.top - - Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height()); - roundedTrueCrop.top -= adjustment; - roundedTrueCrop.bottom -= adjustment; - } - - crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, - roundedTrueCrop.top, roundedTrueCrop.width(), - roundedTrueCrop.height()); - } - } - - if (crop == null) { - Log.w(LOGTAG, "cannot decode file: " + mInUri.toString()); - failure = true; - return false; - } - if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) { - float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() }; - rotateMatrix.mapPoints(dimsAfter); - dimsAfter[0] = Math.abs(dimsAfter[0]); - dimsAfter[1] = Math.abs(dimsAfter[1]); - - if (!(mOutWidth > 0 && mOutHeight > 0)) { - mOutWidth = Math.round(dimsAfter[0]); - mOutHeight = Math.round(dimsAfter[1]); - } - - RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]); - RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight); - - Matrix m = new Matrix(); - if (mRotation == 0) { - m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); - } else { - Matrix m1 = new Matrix(); - m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f); - Matrix m2 = new Matrix(); - m2.setRotate(mRotation); - Matrix m3 = new Matrix(); - m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f); - Matrix m4 = new Matrix(); - m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); - - Matrix c1 = new Matrix(); - c1.setConcat(m2, m1); - Matrix c2 = new Matrix(); - c2.setConcat(m4, m3); - m.setConcat(c2, c1); - } - - Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), - (int) returnRect.height(), Bitmap.Config.ARGB_8888); - if (tmp != null) { - Canvas c = new Canvas(tmp); - Paint p = new Paint(); - p.setFilterBitmap(true); - c.drawBitmap(crop, m, p); - crop = tmp; - } - } - - if (mSaveCroppedBitmap) { - mCroppedBitmap = crop; - } - - // Get output compression format - CompressFormat cf = - convertExtensionToCompressFormat(getFileExtension(mOutputFormat)); - - // Compress to byte array - ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); - if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) { - // If we need to set to the wallpaper, set it - if (mSetWallpaper && wallpaperManager != null) { - try { - byte[] outByteArray = tmpOut.toByteArray(); - wallpaperManager.setStream(new ByteArrayInputStream(outByteArray)); - if (mOnBitmapCroppedHandler != null) { - mOnBitmapCroppedHandler.onBitmapCropped(outByteArray); - } - } catch (IOException e) { - Log.w(LOGTAG, "cannot write stream to wallpaper", e); - failure = true; - } - } - } else { - Log.w(LOGTAG, "cannot compress bitmap"); - failure = true; - } - } - return !failure; // True if any of the operations failed - } - - @Override - protected Boolean doInBackground(Void... params) { - return cropBitmap(); - } - - @Override - protected void onPostExecute(Boolean result) { - if (mOnEndRunnable != null) { - mOnEndRunnable.run(); - } - } - } - protected void updateWallpaperDimensions(int width, int height) { - String spKey = getSharedPreferencesKey(); - SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); + String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY; + SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); SharedPreferences.Editor editor = sp.edit(); if (width != 0 && height != 0) { editor.putInt(WALLPAPER_WIDTH_KEY, width); @@ -830,69 +449,21 @@ public class WallpaperCropActivity extends Activity { editor.remove(WALLPAPER_HEIGHT_KEY); } editor.commit(); - - suggestWallpaperDimension(getResources(), - sp, getWindowManager(), WallpaperManager.getInstance(this), true); - } - - static public void suggestWallpaperDimension(Resources res, - final SharedPreferences sharedPrefs, - WindowManager windowManager, - final WallpaperManager wallpaperManager, boolean fallBackToDefaults) { - final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager); - // If we have saved a wallpaper width/height, use that instead - - int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, -1); - int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, -1); - - if (savedWidth == -1 || savedHeight == -1) { - if (!fallBackToDefaults) { - return; - } else { - savedWidth = defaultWallpaperSize.x; - savedHeight = defaultWallpaperSize.y; - } - } - - if (savedWidth != wallpaperManager.getDesiredMinimumWidth() || - savedHeight != wallpaperManager.getDesiredMinimumHeight()) { - wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight); - } + WallpaperUtils.suggestWallpaperDimension(getResources(), + sp, getWindowManager(), WallpaperManager.getInstance(getContext()), true); } - protected static RectF getMaxCropRect( - int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) { - RectF cropRect = new RectF(); - // Get a crop rect that will fit this - if (inWidth / (float) inHeight > outWidth / (float) outHeight) { - cropRect.top = 0; - cropRect.bottom = inHeight; - cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2; - cropRect.right = inWidth - cropRect.left; - if (leftAligned) { - cropRect.right -= cropRect.left; - cropRect.left = 0; - } - } else { - cropRect.left = 0; - cropRect.right = inWidth; - cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2; - cropRect.bottom = inHeight - cropRect.top; - } - return cropRect; - } + static class LoadRequest { + BitmapSource src; + boolean touchEnabled; + boolean moveToLeft; + Runnable postExecute; + CropViewScaleProvider scaleProvider; - protected static CompressFormat convertExtensionToCompressFormat(String extension) { - return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG; + TileSource result; } - protected static String getFileExtension(String requestFormat) { - String outputFormat = (requestFormat == null) - ? "jpg" - : requestFormat; - outputFormat = outputFormat.toLowerCase(); - return (outputFormat.equals("png") || outputFormat.equals("gif")) - ? "png" // We don't support gif compression. - : "jpg"; + interface CropViewScaleProvider { + float getScale(TileSource src); } } -- cgit v1.2.3