From 64774df4524d5b9e8b23356316bafe6e1fdd2f21 Mon Sep 17 00:00:00 2001 From: Michael Jurka Date: Tue, 29 Oct 2013 15:50:06 +0100 Subject: Make wallpaper picker/cropper more robust - don't crash if image passed to wallpaper picker is invalid - close input streams correctly Bug: 11413915 Bug: 11380658 Bug: 11362731 Change-Id: I973e6bdc532d24a64efd6d174e89fdac626d7ee3 --- src/com/android/photos/BitmapRegionTileSource.java | 109 +++++++++++++-------- 1 file changed, 69 insertions(+), 40 deletions(-) (limited to 'src/com/android/photos/BitmapRegionTileSource.java') diff --git a/src/com/android/photos/BitmapRegionTileSource.java b/src/com/android/photos/BitmapRegionTileSource.java index b5774f40a..b85caaa1c 100644 --- a/src/com/android/photos/BitmapRegionTileSource.java +++ b/src/com/android/photos/BitmapRegionTileSource.java @@ -31,6 +31,7 @@ import android.os.Build.VERSION_CODES; import android.util.Log; import com.android.gallery3d.common.BitmapUtils; +import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.glrenderer.BasicTexture; import com.android.gallery3d.glrenderer.BitmapTexture; @@ -62,10 +63,12 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { private Bitmap mPreview; private int mPreviewSize; private int mRotation; + public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; + private State mState = State.NOT_LOADED; public BitmapSource(int previewSize) { mPreviewSize = previewSize; } - public void loadInBackground() { + public boolean loadInBackground() { ExifInterface ei = new ExifInterface(); if (readExif(ei)) { Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); @@ -74,21 +77,32 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } 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); + if (mDecoder == null) { + mState = State.ERROR_LOADING; + return false; + } else { + 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); + } + mState = State.LOADED; + return true; } } + public State getLoadingState() { + return mState; + } + public BitmapRegionDecoder getBitmapRegionDecoder() { return mDecoder; } @@ -156,7 +170,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { - return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); + InputStream is = regenerateInputStream(); + BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance(is, false); + Utils.closeSilently(is); + return regionDecoder; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; @@ -168,7 +185,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { try { - return BitmapFactory.decodeStream(regenerateInputStream(), null, options); + InputStream is = regenerateInputStream(); + Bitmap b = BitmapFactory.decodeStream(is, null, options); + Utils.closeSilently(is); + return b; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; @@ -177,13 +197,15 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { - ei.readExif(regenerateInputStream()); + InputStream is = regenerateInputStream(); + ei.readExif(is); + Utils.closeSilently(is); 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); + Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; } } @@ -204,7 +226,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { - return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); + InputStream is = regenerateInputStream(); + BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance(is, true); + Utils.closeSilently(is); + return regionDecoder; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); return null; @@ -217,7 +242,9 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { - ei.readExif(regenerateInputStream()); + InputStream is = regenerateInputStream(); + ei.readExif(is); + Utils.closeSilently(is); return true; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); @@ -243,27 +270,29 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { mTileSize = TiledImageRenderer.suggestedTileSize(context); 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(source, previewSize); - if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { - mPreview = new BitmapTexture(preview); - } else { - Log.w(TAG, String.format( - "Failed to create preview of apropriate size! " - + " in: %dx%d, out: %dx%d", - mWidth, mHeight, - preview.getWidth(), preview.getHeight())); + if (mDecoder != null) { + 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(source, previewSize); + if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) { + mPreview = new BitmapTexture(preview); + } else { + Log.w(TAG, String.format( + "Failed to create preview of apropriate size! " + + " in: %dx%d, out: %dx%d", + mWidth, mHeight, + preview.getWidth(), preview.getHeight())); + } } } } -- cgit v1.2.3