diff options
author | Michael Jurka <mikejurka@google.com> | 2013-10-16 18:23:56 -0700 |
---|---|---|
committer | Danesh M <daneshm90@gmail.com> | 2014-06-05 23:03:34 -0700 |
commit | 967bfefcbd73b2a3b312df444cbbe4059b7b0574 (patch) | |
tree | ade61f7d9e8b7839dbd157e572b1a5a2c5cd1a74 | |
parent | 4cb760d60c6f96d6a778cd17c6507562b98388a7 (diff) | |
download | android_packages_apps_Trebuchet-967bfefcbd73b2a3b312df444cbbe4059b7b0574.tar.gz android_packages_apps_Trebuchet-967bfefcbd73b2a3b312df444cbbe4059b7b0574.tar.bz2 android_packages_apps_Trebuchet-967bfefcbd73b2a3b312df444cbbe4059b7b0574.zip |
Load images on a bg thread
Bug: 11134758
Change-Id: Ie789a2fcb2024832ac104cd9cdbc3602abee85ee
-rw-r--r-- | res/layout/wallpaper_cropper.xml | 2 | ||||
-rw-r--r-- | res/layout/wallpaper_picker.xml | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/SavedWallpaperImages.java | 10 | ||||
-rw-r--r-- | src/com/android/launcher3/WallpaperCropActivity.java | 44 | ||||
-rw-r--r-- | src/com/android/launcher3/WallpaperPickerActivity.java | 55 | ||||
-rw-r--r-- | src/com/android/photos/BitmapRegionTileSource.java | 236 |
6 files changed, 260 insertions, 89 deletions
diff --git a/res/layout/wallpaper_cropper.xml b/res/layout/wallpaper_cropper.xml index 3a3d98a69..abb860898 100644 --- a/res/layout/wallpaper_cropper.xml +++ b/res/layout/wallpaper_cropper.xml @@ -32,7 +32,7 @@ android:visibility="invisible" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:layout_centerInParent="true" android:indeterminate="true" android:indeterminateOnly="true" android:background="@android:color/transparent" /> diff --git a/res/layout/wallpaper_picker.xml b/res/layout/wallpaper_picker.xml index 0492b7bd9..620ce1fa1 100644 --- a/res/layout/wallpaper_picker.xml +++ b/res/layout/wallpaper_picker.xml @@ -38,7 +38,7 @@ android:visibility="invisible" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" + android:layout_centerInParent="true" android:indeterminate="true" android:indeterminateOnly="true" android:background="@android:color/transparent" /> diff --git a/src/com/android/launcher3/SavedWallpaperImages.java b/src/com/android/launcher3/SavedWallpaperImages.java index c19692b9a..086d08580 100644 --- a/src/com/android/launcher3/SavedWallpaperImages.java +++ b/src/com/android/launcher3/SavedWallpaperImages.java @@ -60,13 +60,9 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter { public void onClick(WallpaperPickerActivity a) { String imageFilename = a.getSavedImages().getImageFilename(mDbId); File file = new File(a.getFilesDir(), imageFilename); - CropView v = a.getCropView(); - int rotation = WallpaperCropActivity.getRotationFromExif(file.getAbsolutePath()); - a.getDefaultWallpaperView().setVisibility(View.INVISIBLE); - v.setTileSource( - new BitmapRegionTileSource(a, file.getAbsolutePath(), 1024, rotation), null); - v.moveToLeft(); - v.setTouchEnabled(false); + BitmapRegionTileSource.FilePathBitmapSource bitmapSource = + new BitmapRegionTileSource.FilePathBitmapSource(file.getAbsolutePath(), 1024); + a.setCropViewTileSource(bitmapSource, false, true); } @Override public void onSave(WallpaperPickerActivity a) { diff --git a/src/com/android/launcher3/WallpaperCropActivity.java b/src/com/android/launcher3/WallpaperCropActivity.java index 30ec340b1..29e8c972a 100644 --- a/src/com/android/launcher3/WallpaperCropActivity.java +++ b/src/com/android/launcher3/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() { diff --git a/src/com/android/launcher3/WallpaperPickerActivity.java b/src/com/android/launcher3/WallpaperPickerActivity.java index bed272365..37ff1be16 100644 --- a/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/src/com/android/launcher3/WallpaperPickerActivity.java @@ -42,6 +42,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LevelListDrawable; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; @@ -137,11 +138,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } @Override public void onClick(WallpaperPickerActivity a) { - CropView v = a.getCropView(); - int rotation = WallpaperCropActivity.getRotationFromExif(a, mUri); - a.getDefaultWallpaperView().setVisibility(View.INVISIBLE); - v.setTileSource(new BitmapRegionTileSource(a, mUri, 1024, rotation), null); - v.setTouchEnabled(true); + a.setCropViewTileSource( + new BitmapRegionTileSource.UriBitmapSource(a, mUri, 1024), true, false); } @Override public void onSave(final WallpaperPickerActivity a) { @@ -179,9 +177,10 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } @Override public void onClick(WallpaperPickerActivity a) { - int rotation = WallpaperCropActivity.getRotationFromExif(mResources, mResId); - BitmapRegionTileSource source = new BitmapRegionTileSource( - mResources, a, mResId, 1024, rotation); + BitmapRegionTileSource.ResourceBitmapSource bitmapSource = + new BitmapRegionTileSource.ResourceBitmapSource(mResources, mResId, 1024); + bitmapSource.loadInBackground(); + BitmapRegionTileSource source = new BitmapRegionTileSource(a, bitmapSource); CropView v = a.getCropView(); a.getDefaultWallpaperView().setVisibility(View.INVISIBLE); v.setTileSource(source, null); @@ -532,6 +531,12 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } }; } + @Override + public void setCropViewTileSource(final BitmapRegionTileSource.BitmapSource bitmapSource, + final boolean touchEnabled, boolean moveToLeft) { + getDefaultWallpaperView().setVisibility(View.INVISIBLE); + super.setCropViewTileSource(bitmapSource, touchEnabled, moveToLeft); + } private void initializeScrollForRtl() { final HorizontalScrollView scroll = @@ -727,26 +732,34 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } } - private void addTemporaryWallpaperTile(Uri uri) { + private void addTemporaryWallpaperTile(final Uri uri) { mTempWallpaperTiles.add(uri); // Add a tile for the image picked from Gallery FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater(). inflate(R.layout.wallpaper_picker_item, mWallpapersView, false); setWallpaperItemPaddingToZero(pickedImageThumbnail); + mWallpapersView.addView(pickedImageThumbnail, 0); // Load the thumbnail - ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image); - Point defaultSize = getDefaultThumbnailSize(this.getResources()); - int rotation = WallpaperCropActivity.getRotationFromExif(this, uri); - Bitmap thumb = createThumbnail(defaultSize, this, uri, null, null, 0, rotation, false); - if (thumb != null) { - image.setImageBitmap(thumb); - Drawable thumbDrawable = image.getDrawable(); - thumbDrawable.setDither(true); - } else { - Log.e(TAG, "Error loading thumbnail for uri=" + uri); - } - mWallpapersView.addView(pickedImageThumbnail, 0); + final ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image); + final Point defaultSize = getDefaultThumbnailSize(this.getResources()); + final Context context = this; + new AsyncTask<Void, Bitmap, Bitmap>() { + protected Bitmap doInBackground(Void...args) { + int rotation = WallpaperCropActivity.getRotationFromExif(context, uri); + return createThumbnail(defaultSize, context, uri, null, null, 0, rotation, false); + + } + protected void onPostExecute(Bitmap thumb) { + if (thumb != null) { + image.setImageBitmap(thumb); + Drawable thumbDrawable = image.getDrawable(); + thumbDrawable.setDither(true); + } else { + Log.e(TAG, "Error loading thumbnail for uri=" + uri); + } + } + }.execute(); UriWallpaperInfo info = new UriWallpaperInfo(uri); pickedImageThumbnail.setTag(info); diff --git a/src/com/android/photos/BitmapRegionTileSource.java b/src/com/android/photos/BitmapRegionTileSource.java index 5f6401868..74284b236 100644 --- a/src/com/android/photos/BitmapRegionTileSource.java +++ b/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; @@ -55,6 +57,175 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { // 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 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; int mHeight; @@ -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); |