OSDN Git Service

Temporary handling when running out of heap in filtershow.
authorRuben Brunk <rubenbrunk@google.com>
Thu, 21 Feb 2013 06:45:55 +0000 (22:45 -0800)
committerRuben Brunk <rubenbrunk@google.com>
Thu, 21 Feb 2013 20:55:46 +0000 (12:55 -0800)
Bug: 8233895
Change-Id: Id078d2a4b387127c0d230bc5d9de4590f0e9f72b

src/com/android/gallery3d/filtershow/cache/ImageLoader.java
src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java

index 698992a..42e72e6 100644 (file)
@@ -91,6 +91,7 @@ public class ImageLoader {
     public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
     public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
 
+    private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5;
     private Context mContext = null;
     private Uri mUri = null;
 
@@ -406,28 +407,97 @@ public class ImageLoader {
 
     public static Bitmap loadMutableBitmap(Context context, Uri sourceUri) {
         BitmapFactory.Options options = new BitmapFactory.Options();
+        return loadMutableBitmap(context, sourceUri, options);
+    }
+
+    public static Bitmap loadMutableBitmap(Context context, Uri sourceUri,
+            BitmapFactory.Options options) {
         // TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
         // exist)
         options.inMutable = true;
 
+        Bitmap bitmap = decodeUriWithBackouts(context, sourceUri, options);
+        if (bitmap == null) {
+            return null;
+        }
+        int orientation = ImageLoader.getOrientation(context, sourceUri);
+        bitmap = ImageLoader.rotateToPortrait(bitmap, orientation);
+        return bitmap;
+    }
+
+    public static Bitmap decodeUriWithBackouts(Context context, Uri sourceUri,
+            BitmapFactory.Options options) {
+        boolean noBitmap = true;
+        int num_tries = 0;
+        InputStream is = getInputStream(context, sourceUri);
+
+        if (options.inSampleSize < 1) {
+            options.inSampleSize = 1;
+        }
+        // Stopgap fix for low-memory devices.
+        Bitmap bmap = null;
+        while (noBitmap) {
+            if (is == null) {
+                return null;
+            }
+            try {
+                // Try to decode, downsample if low-memory.
+                bmap = BitmapFactory.decodeStream(is, null, options);
+                noBitmap = false;
+            } catch (java.lang.OutOfMemoryError e) {
+                // Try 5 times before failing for good.
+                if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
+                    throw e;
+                }
+                is = null;
+                bmap = null;
+                System.gc();
+                is = getInputStream(context, sourceUri);
+                options.inSampleSize *= 2;
+            }
+        }
+        Utils.closeSilently(is);
+        return bmap;
+    }
+
+    private static InputStream getInputStream(Context context, Uri sourceUri) {
         InputStream is = null;
-        Bitmap bitmap = null;
         try {
             is = context.getContentResolver().openInputStream(sourceUri);
-            bitmap = BitmapFactory.decodeStream(is, null, options);
         } catch (FileNotFoundException e) {
             Log.w(LOGTAG, "could not load bitmap ", e);
-            is = null;
-            bitmap = null;
-        } finally {
             Utils.closeSilently(is);
+            is = null;
         }
-        if (bitmap == null) {
-            return null;
+        return is;
+    }
+
+    public static Bitmap decodeResourceWithBackouts(Resources res, BitmapFactory.Options options,
+            int id) {
+        boolean noBitmap = true;
+        int num_tries = 0;
+        if (options.inSampleSize < 1) {
+            options.inSampleSize = 1;
         }
-        int orientation = ImageLoader.getOrientation(context, sourceUri);
-        bitmap = ImageLoader.rotateToPortrait(bitmap, orientation);
-        return bitmap;
+        // Stopgap fix for low-memory devices.
+        Bitmap bmap = null;
+        while (noBitmap) {
+            try {
+                // Try to decode, downsample if low-memory.
+                bmap = BitmapFactory.decodeResource(
+                        res, id, options);
+                noBitmap = false;
+            } catch (java.lang.OutOfMemoryError e) {
+                // Try 5 times before failing for good.
+                if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
+                    throw e;
+                }
+                bmap = null;
+                System.gc();
+                options.inSampleSize *= 2;
+            }
+        }
+        return bmap;
     }
 
     public void returnFilteredResult(ImagePreset preset,
@@ -451,13 +521,36 @@ public class ImageLoader {
                 if (param == null || mUri == null) {
                     return null;
                 }
-                Bitmap bitmap = loadMutableBitmap(mContext, mUri);
-                if (bitmap == null) {
-                    Log.w(LOGTAG, "Failed to save image!");
-                    return null;
+                BitmapFactory.Options options = new BitmapFactory.Options();
+                boolean noBitmap = true;
+                int num_tries = 0;
+                if (options.inSampleSize < 1) {
+                    options.inSampleSize = 1;
                 }
-                bitmap = param.applyGeometry(bitmap);
-                return param.apply(bitmap);
+                Bitmap bitmap = null;
+                // Stopgap fix for low-memory devices.
+                while (noBitmap) {
+                    try {
+                        // Try to do bitmap operations, downsample if low-memory
+                        bitmap = loadMutableBitmap(mContext, mUri, options);
+                        if (bitmap == null) {
+                            Log.w(LOGTAG, "Failed to save image!");
+                            return null;
+                        }
+                        bitmap = param.applyGeometry(bitmap);
+                        bitmap = param.apply(bitmap);
+                        noBitmap = false;
+                    } catch (java.lang.OutOfMemoryError e) {
+                        // Try 5 times before failing for good.
+                        if (++num_tries >= 5) {
+                            throw e;
+                        }
+                        bitmap = null;
+                        System.gc();
+                        options.inSampleSize *= 2;
+                    }
+                }
+                return bitmap;
             }
         };
 
index e378fe2..89cfa6b 100644 (file)
@@ -22,6 +22,7 @@ import android.content.Context;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Environment;
@@ -173,37 +174,52 @@ public class SaveCopyTask extends AsyncTask<ImagePreset, Void, Uri> {
         }
         ImagePreset preset = params[0];
         InputStream is = null;
-        try {
-            Bitmap bitmap = ImageLoader.loadMutableBitmap(context, sourceUri);
-            if (bitmap == null) {
-                return null;
-            }
-            bitmap = preset.applyGeometry(bitmap);
-            bitmap = preset.apply(bitmap);
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        boolean noBitmap = true;
+        int num_tries = 0;
+        // Stopgap fix for low-memory devices.
+        while(noBitmap) {
+            try {
+                // Try to do bitmap operations, downsample if low-memory
+                Bitmap bitmap = ImageLoader.loadMutableBitmap(context, sourceUri, options);
+                if (bitmap == null) {
+                    return null;
+                }
+                bitmap = preset.applyGeometry(bitmap);
+                bitmap = preset.apply(bitmap);
 
-            Object xmp = null;
-            if (preset.isPanoramaSafe()) {
-                is = context.getContentResolver().openInputStream(sourceUri);
-                xmp =  XmpUtilHelper.extractXMPMeta(is);
-            }
-            ExifData exif = getExifData(sourceUri);
-            if (exif != null) {
-                exif.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, System.currentTimeMillis(),
-                        TimeZone.getDefault());
-                // Since the image has been modified, set the orientation to normal.
-                exif.addTag(ExifTag.TAG_ORIENTATION).setValue(ExifTag.Orientation.TOP_LEFT);
+                Object xmp = null;
+                if (preset.isPanoramaSafe()) {
+                    is = context.getContentResolver().openInputStream(sourceUri);
+                    xmp =  XmpUtilHelper.extractXMPMeta(is);
+                }
+                ExifData exif = getExifData(sourceUri);
+                if (exif != null) {
+                    exif.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, System.currentTimeMillis(),
+                            TimeZone.getDefault());
+                    // Since the image has been modified, set the orientation to normal.
+                    exif.addTag(ExifTag.TAG_ORIENTATION).setValue(ExifTag.Orientation.TOP_LEFT);
+                }
+                saveBitmap(bitmap, this.destinationFile, xmp, exif);
+                bitmap.recycle();
+                noBitmap = false;
+            } catch (FileNotFoundException ex) {
+                Log.w(LOGTAG, "Failed to save image!", ex);
+                return null;
+            } catch (java.lang.OutOfMemoryError e) {
+                // Try 5 times before failing for good.
+                if (++num_tries >= 5) {
+                    throw e;
+                }
+                System.gc();
+                options.inSampleSize *= 2;
+            } finally {
+                Utils.closeSilently(is);
             }
-            saveBitmap(bitmap, this.destinationFile, xmp, exif);
-
-            Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
-            bitmap.recycle();
-            return uri;
-        } catch (FileNotFoundException ex) {
-            Log.w(LOGTAG, "Failed to save image!", ex);
-            return null;
-        } finally {
-            Utils.closeSilently(is);
         }
+        Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
+        return uri;
+
     }
 
     @Override