summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Jurka <mikejurka@google.com>2013-10-16 18:23:56 -0700
committerMichael Jurka <mikejurka@google.com>2013-10-21 14:51:49 -0700
commit862f7e395004b00d871cbe507fd5f2a70c797ef7 (patch)
treec8372d4947e06cd8591bd590a2820c97c12ac76b
parent4f98332b98bbe95cb0574e51ef1514bade9a5e76 (diff)
downloadandroid_packages_apps_Trebuchet-862f7e395004b00d871cbe507fd5f2a70c797ef7.tar.gz
android_packages_apps_Trebuchet-862f7e395004b00d871cbe507fd5f2a70c797ef7.tar.bz2
android_packages_apps_Trebuchet-862f7e395004b00d871cbe507fd5f2a70c797ef7.zip
Load images on a bg thread
Bug: 11134758 Change-Id: Ie789a2fcb2024832ac104cd9cdbc3602abee85ee
-rw-r--r--res/layout/wallpaper_cropper.xml2
-rw-r--r--res/layout/wallpaper_picker.xml2
-rw-r--r--src/com/android/launcher3/SavedWallpaperImages.java10
-rw-r--r--src/com/android/launcher3/WallpaperCropActivity.java44
-rw-r--r--src/com/android/launcher3/WallpaperPickerActivity.java55
-rw-r--r--src/com/android/photos/BitmapRegionTileSource.java236
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 2ad92181d..9c6ee6ec0 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;
@@ -133,11 +134,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) {
@@ -175,9 +173,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);
@@ -528,6 +527,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 =
@@ -687,26 +692,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);