diff options
author | Michael Jurka <mikejurka@google.com> | 2013-10-29 04:56:17 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-10-29 04:56:17 -0700 |
commit | 160e8aa6a5188d363866c00526f28704fc61233f (patch) | |
tree | b989d64489a574184971dded56298c27e04c150b /packages | |
parent | 45895d743dc3c0d37a097e83b1d46095ac5e2db0 (diff) | |
parent | 2b5297a40024e9cf136919d3ea0e88cb4ccfa27c (diff) | |
download | frameworks_base-160e8aa6a5188d363866c00526f28704fc61233f.zip frameworks_base-160e8aa6a5188d363866c00526f28704fc61233f.tar.gz frameworks_base-160e8aa6a5188d363866c00526f28704fc61233f.tar.bz2 |
am 2b5297a4: Merge "Load wallpaper images on a bg thread" into klp-dev
* commit '2b5297a40024e9cf136919d3ea0e88cb4ccfa27c':
Load wallpaper images on a bg thread
Diffstat (limited to 'packages')
-rw-r--r-- | packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java | 238 | ||||
-rw-r--r-- | packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java | 44 |
2 files changed, 222 insertions, 60 deletions
diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java index 5f64018..b5774f4 100644 --- a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java +++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java @@ -31,11 +31,13 @@ import android.os.Build.VERSION_CODES; import android.util.Log; import com.android.gallery3d.common.BitmapUtils; +import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.glrenderer.BasicTexture; import com.android.gallery3d.glrenderer.BitmapTexture; import com.android.photos.views.TiledImageRenderer; import java.io.BufferedInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -53,7 +55,176 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { private static final int GL_SIZE_LIMIT = 2048; // This must be no larger than half the size of the GL_SIZE_LIMIT // due to decodePreview being allowed to be up to 2x the size of the target - private static final int MAX_PREVIEW_SIZE = 1024; + public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; + + public static abstract class BitmapSource { + private BitmapRegionDecoder mDecoder; + private Bitmap mPreview; + private int mPreviewSize; + private int mRotation; + public BitmapSource(int previewSize) { + mPreviewSize = previewSize; + } + public void loadInBackground() { + ExifInterface ei = new ExifInterface(); + if (readExif(ei)) { + Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); + if (ori != null) { + mRotation = ExifInterface.getRotationForOrientationValue(ori.shortValue()); + } + } + mDecoder = loadBitmapRegionDecoder(); + int width = mDecoder.getWidth(); + int height = mDecoder.getHeight(); + if (mPreviewSize != 0) { + int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inPreferredConfig = Bitmap.Config.ARGB_8888; + opts.inPreferQualityOverSpeed = true; + + float scale = (float) previewSize / Math.max(width, height); + opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale); + opts.inJustDecodeBounds = false; + mPreview = loadPreviewBitmap(opts); + } + } + + public BitmapRegionDecoder getBitmapRegionDecoder() { + return mDecoder; + } + + public Bitmap getPreviewBitmap() { + return mPreview; + } + + public int getPreviewSize() { + return mPreviewSize; + } + + public int getRotation() { + return mRotation; + } + + public abstract boolean readExif(ExifInterface ei); + public abstract BitmapRegionDecoder loadBitmapRegionDecoder(); + public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); + } + + public static class FilePathBitmapSource extends BitmapSource { + private String mPath; + public FilePathBitmapSource(String path, int previewSize) { + super(previewSize); + mPath = path; + } + @Override + public BitmapRegionDecoder loadBitmapRegionDecoder() { + try { + return BitmapRegionDecoder.newInstance(mPath, true); + } catch (IOException e) { + Log.w("BitmapRegionTileSource", "getting decoder failed", e); + return null; + } + } + @Override + public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { + return BitmapFactory.decodeFile(mPath, options); + } + @Override + public boolean readExif(ExifInterface ei) { + try { + ei.readExif(mPath); + return true; + } catch (IOException e) { + Log.w("BitmapRegionTileSource", "getting decoder failed", e); + return false; + } + } + } + + public static class UriBitmapSource extends BitmapSource { + private Context mContext; + private Uri mUri; + public UriBitmapSource(Context context, Uri uri, int previewSize) { + super(previewSize); + mContext = context; + mUri = uri; + } + private InputStream regenerateInputStream() throws FileNotFoundException { + InputStream is = mContext.getContentResolver().openInputStream(mUri); + return new BufferedInputStream(is); + } + @Override + public BitmapRegionDecoder loadBitmapRegionDecoder() { + try { + return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); + } catch (FileNotFoundException e) { + Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); + return null; + } catch (IOException e) { + Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); + return null; + } + } + @Override + public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { + try { + return BitmapFactory.decodeStream(regenerateInputStream(), null, options); + } catch (FileNotFoundException e) { + Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); + return null; + } + } + @Override + public boolean readExif(ExifInterface ei) { + try { + ei.readExif(regenerateInputStream()); + return true; + } catch (FileNotFoundException e) { + Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); + return false; + } catch (IOException e) { + Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); + return false; + } + } + } + + public static class ResourceBitmapSource extends BitmapSource { + private Resources mRes; + private int mResId; + public ResourceBitmapSource(Resources res, int resId, int previewSize) { + super(previewSize); + mRes = res; + mResId = resId; + } + private InputStream regenerateInputStream() { + InputStream is = mRes.openRawResource(mResId); + return new BufferedInputStream(is); + } + @Override + public BitmapRegionDecoder loadBitmapRegionDecoder() { + try { + return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); + } catch (IOException e) { + Log.e("BitmapRegionTileSource", "Error reading resource", e); + return null; + } + } + @Override + public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { + return BitmapFactory.decodeResource(mRes, mResId, options); + } + @Override + public boolean readExif(ExifInterface ei) { + try { + ei.readExif(regenerateInputStream()); + return true; + } catch (IOException e) { + Log.e("BitmapRegionTileSource", "Error reading resource", e); + return false; + } + } + } BitmapRegionDecoder mDecoder; int mWidth; @@ -68,50 +239,23 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { private BitmapFactory.Options mOptions; private Canvas mCanvas; - public BitmapRegionTileSource(Context context, String path, int previewSize, int rotation) { - this(null, context, path, null, 0, previewSize, rotation); - } - - public BitmapRegionTileSource(Context context, Uri uri, int previewSize, int rotation) { - this(null, context, null, uri, 0, previewSize, rotation); - } - - public BitmapRegionTileSource(Resources res, - Context context, int resId, int previewSize, int rotation) { - this(res, context, null, null, resId, previewSize, rotation); - } - - private BitmapRegionTileSource(Resources res, - Context context, String path, Uri uri, int resId, int previewSize, int rotation) { + public BitmapRegionTileSource(Context context, BitmapSource source) { mTileSize = TiledImageRenderer.suggestedTileSize(context); - mRotation = rotation; - try { - if (path != null) { - mDecoder = BitmapRegionDecoder.newInstance(path, true); - } else if (uri != null) { - InputStream is = context.getContentResolver().openInputStream(uri); - BufferedInputStream bis = new BufferedInputStream(is); - mDecoder = BitmapRegionDecoder.newInstance(bis, true); - } else { - InputStream is = res.openRawResource(resId); - BufferedInputStream bis = new BufferedInputStream(is); - mDecoder = BitmapRegionDecoder.newInstance(bis, true); - } - mWidth = mDecoder.getWidth(); - mHeight = mDecoder.getHeight(); - } catch (IOException e) { - Log.w("BitmapRegionTileSource", "ctor failed", e); - } + mRotation = source.getRotation(); + mDecoder = source.getBitmapRegionDecoder(); + mWidth = mDecoder.getWidth(); + mHeight = mDecoder.getHeight(); mOptions = new BitmapFactory.Options(); mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; mOptions.inPreferQualityOverSpeed = true; mOptions.inTempStorage = new byte[16 * 1024]; + int previewSize = source.getPreviewSize(); if (previewSize != 0) { previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE); // Although this is the same size as the Bitmap that is likely already // loaded, the lifecycle is different and interactions are on a different // thread. Thus to simplify, this source will decode its own bitmap. - Bitmap preview = decodePreview(res, context, path, uri, resId, previewSize); + Bitmap preview = decodePreview(source, previewSize); if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { mPreview = new BitmapTexture(preview); } else { @@ -215,33 +359,15 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { * Note that the returned bitmap may have a long edge that's longer * than the targetSize, but it will always be less than 2x the targetSize */ - private Bitmap decodePreview( - Resources res, Context context, String file, Uri uri, int resId, int targetSize) { - float scale = (float) targetSize / Math.max(mWidth, mHeight); - mOptions.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale); - mOptions.inJustDecodeBounds = false; - - Bitmap result = null; - if (file != null) { - result = BitmapFactory.decodeFile(file, mOptions); - } else if (uri != null) { - try { - InputStream is = context.getContentResolver().openInputStream(uri); - BufferedInputStream bis = new BufferedInputStream(is); - result = BitmapFactory.decodeStream(bis, null, mOptions); - } catch (IOException e) { - Log.w("BitmapRegionTileSource", "getting preview failed", e); - } - } else { - result = BitmapFactory.decodeResource(res, resId, mOptions); - } + private Bitmap decodePreview(BitmapSource source, int targetSize) { + Bitmap result = source.getPreviewBitmap(); if (result == null) { return null; } // We need to resize down if the decoder does not support inSampleSize // or didn't support the specified inSampleSize (some decoders only do powers of 2) - scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight())); + float scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight())); if (scale <= 0.5) { result = BitmapUtils.resizeBitmapByScale(result, scale, true); diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java index 1209e56..220f567 100644 --- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java @@ -37,7 +37,6 @@ import android.graphics.RectF; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.util.FloatMath; import android.util.Log; import android.view.Display; import android.view.View; @@ -96,9 +95,6 @@ public class WallpaperCropActivity extends Activity { return; } - int rotation = getRotationFromExif(this, imageUri); - mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, rotation), null); - mCropView.setTouchEnabled(true); // Action bar // Show the custom action bar view final ActionBar actionBar = getActionBar(); @@ -111,6 +107,46 @@ public class WallpaperCropActivity extends Activity { cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone); } }); + + // Load image in background + setCropViewTileSource( + new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024), true, false); + } + + public void setCropViewTileSource(final BitmapRegionTileSource.BitmapSource bitmapSource, + final boolean touchEnabled, final boolean moveToLeft) { + final Context context = WallpaperCropActivity.this; + final View progressView = findViewById(R.id.loading); + final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() { + protected Void doInBackground(Void...args) { + if (!isCancelled()) { + bitmapSource.loadInBackground(); + } + return null; + } + protected void onPostExecute(Void arg) { + if (!isCancelled()) { + progressView.setVisibility(View.INVISIBLE); + mCropView.setTileSource( + new BitmapRegionTileSource(context, bitmapSource), null); + mCropView.setTouchEnabled(touchEnabled); + if (moveToLeft) { + mCropView.moveToLeft(); + } + } + } + }; + // 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() { |