Merge pull request #740 from owncloud/revert-669-master
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewImageFragment.java
index b3a806e..4dd5c43 100644 (file)
  */
 package com.owncloud.android.ui.preview;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.ref.WeakReference;
 
 import android.accounts.Account;
@@ -23,9 +29,12 @@ import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+import android.graphics.Point;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.support.v4.app.FragmentStatePagerAdapter;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -305,6 +314,7 @@ public class PreviewImageFragment extends FileFragment {
     public void onDestroy() {
         if (mBitmap != null) {
             mBitmap.recycle();
+            System.gc();
         }
         super.onDestroy();
     }
@@ -368,8 +378,14 @@ public class PreviewImageFragment extends FileFragment {
             if (params.length != 1) return result;
             String storagePath = params[0];
             try {
-                //Decode file into a bitmap in real size for being able to make zoom on the image
-                result = BitmapFactory.decodeFile(storagePath);
+
+                File picture = new File(storagePath);
+
+                if (picture != null) {
+                    //Decode file into a bitmap in real size for being able to make zoom on the image
+                    result = BitmapFactory.decodeStream(new FlushedInputStream
+                            (new BufferedInputStream(new FileInputStream(picture))));
+                }
 
                 if (result == null) {
                     mErrorMessageId = R.string.preview_image_error_unknown_format;
@@ -377,8 +393,15 @@ public class PreviewImageFragment extends FileFragment {
                 }
                 
             } catch (OutOfMemoryError e) {
-                mErrorMessageId = R.string.preview_image_error_unknown_format;
                 Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
+
+                // If out of memory error when loading image, try to load it scaled
+                result = loadScaledImage(storagePath);
+
+                if (result == null) {
+                    mErrorMessageId = R.string.preview_image_error_unknown_format;
+                    Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                }
                     
             } catch (NoSuchFieldError e) {
                 mErrorMessageId = R.string.common_error_unknown;
@@ -471,4 +494,84 @@ public class PreviewImageFragment extends FileFragment {
     public TouchImageViewCustom getImageView() {
         return mImageView;
     }
+
+    static class FlushedInputStream extends FilterInputStream {
+        public FlushedInputStream(InputStream inputStream) {
+        super(inputStream);
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            long totalBytesSkipped = 0L;
+            while (totalBytesSkipped < n) {
+                long bytesSkipped = in.skip(n - totalBytesSkipped);
+                if (bytesSkipped == 0L) {
+                      int byteValue = read();
+                      if (byteValue < 0) {
+                          break;  // we reached EOF
+                      } else {
+                          bytesSkipped = 1; // we read one byte
+                      }
+               }
+               totalBytesSkipped += bytesSkipped;
+            }
+            return totalBytesSkipped;
+        }
+    }
+
+    /**
+     * Load image scaled
+     * @param storagePath: path of the image
+     * @return Bitmap
+     */
+    @SuppressWarnings("deprecation")
+    private Bitmap loadScaledImage(String storagePath) {
+
+        Log_OC.d(TAG, "Loading image scaled");
+
+        // set desired options that will affect the size of the bitmap
+        BitmapFactory.Options options = new Options();
+        options.inScaled = true;
+        options.inPurgeable = true;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+            options.inPreferQualityOverSpeed = false;
+        }
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            options.inMutable = false;
+        }
+        // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(storagePath, options);
+
+        int width = options.outWidth;
+        int height = options.outHeight;
+        int scale = 1;
+
+        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        Point size = new Point();
+        int screenWidth;
+        int screenHeight;
+        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
+            display.getSize(size);
+            screenWidth = size.x;
+            screenHeight = size.y;
+        } else {
+            screenWidth = display.getWidth();
+            screenHeight = display.getHeight();
+        }
+
+        if (width > screenWidth) {
+            // second try to scale down the image , this time depending upon the screen size 
+            scale = (int) Math.floor((float)width / screenWidth);
+        }
+        if (height > screenHeight) {
+            scale = Math.max(scale, (int) Math.floor((float)height / screenHeight));
+        }
+        options.inSampleSize = scale;
+
+        // really load the bitmap
+        options.inJustDecodeBounds = false; // the next decodeFile call will be real
+        return BitmapFactory.decodeFile(storagePath, options);
+
+    }
 }