Better condition
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewImageFragment.java
index 4dd5c43..938abf7 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc. 
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -53,8 +56,9 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
-import com.owncloud.android.utils.TouchImageViewCustom;
+import com.owncloud.android.utils.BitmapUtils;
 
+import third_parties.michaelOrtiz.TouchImageViewCustom;
 
 
 /**
@@ -63,8 +67,6 @@ import com.owncloud.android.utils.TouchImageViewCustom;
  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
  * 
  * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
- * 
- * @author David A. Velasco
  */
 public class PreviewImageFragment extends FileFragment {
 
@@ -82,6 +84,8 @@ public class PreviewImageFragment extends FileFragment {
     private static final String TAG = PreviewImageFragment.class.getSimpleName();
 
     private boolean mIgnoreFirstSavedState;
+    
+    private LoadBitmapTask mLoadBitmapTask = null;
 
     
     /**
@@ -190,12 +194,22 @@ public class PreviewImageFragment extends FileFragment {
     public void onStart() {
         super.onStart();
         if (getFile() != null) {
-           BitmapLoader bl = new BitmapLoader(mImageView, mMessageView, mProgressWheel);
-           bl.execute(new String[]{getFile().getStoragePath()});
+           mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel);
+           mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()});
         }
     }
     
     
+    @Override
+    public void onStop() {
+        Log_OC.d(TAG, "onStop starts");
+        if (mLoadBitmapTask != null) {
+            mLoadBitmapTask.cancel(true);
+            mLoadBitmapTask = null;
+        }
+        super.onStop();
+    }
+    
     /**
      * {@inheritDoc}
      */
@@ -315,6 +329,8 @@ public class PreviewImageFragment extends FileFragment {
         if (mBitmap != null) {
             mBitmap.recycle();
             System.gc();
+                // putting this in onStop() is just the same; the fragment is always destroyed by the ViewPager
+                // when swipes further than the valid offset, and onStop() is never called before than that
         }
         super.onDestroy();
     }
@@ -329,7 +345,7 @@ public class PreviewImageFragment extends FileFragment {
     }
     
     
-    private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
+    private class LoadBitmapTask extends AsyncTask<String, Void, Bitmap> {
 
         /**
          * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
@@ -365,7 +381,7 @@ public class PreviewImageFragment extends FileFragment {
          * 
          * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
          */
-        public BitmapLoader(ImageViewCustom imageView, TextView messageView, ProgressBar progressWheel) {
+        public LoadBitmapTask(ImageViewCustom imageView, TextView messageView, ProgressBar progressWheel) {
             mImageViewRef = new WeakReference<ImageViewCustom>(imageView);
             mMessageViewRef = new WeakReference<TextView>(messageView);
             mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
@@ -377,45 +393,75 @@ public class PreviewImageFragment extends FileFragment {
             Bitmap result = null;
             if (params.length != 1) return result;
             String storagePath = params[0];
+            InputStream is = null;
             try {
 
+                if (isCancelled()) return result;
+                
                 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))));
+                    // Decode file into a bitmap in real size for being able to make zoom on the image
+                    is = new FlushedInputStream(new BufferedInputStream(new FileInputStream(picture)));
+                    result = BitmapFactory.decodeStream(is);
                 }
 
+                if (isCancelled()) return result;
+                
                 if (result == null) {
                     mErrorMessageId = R.string.preview_image_error_unknown_format;
                     Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                } else {
+                    // Rotate image, obeying exif tag.
+                    result = BitmapUtils.rotateImage(result, storagePath);
                 }
                 
             } catch (OutOfMemoryError e) {
-                Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
+                Log_OC.w(TAG, "Out of memory rendering file " + storagePath + " in full size; scaling down");
 
-                // If out of memory error when loading image, try to load it scaled
+                if (isCancelled()) return result;
+                
+                // If out of memory error when loading or rotating 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);
+                } else {
+                    // Rotate scaled image, obeying exif tag
+                    result = BitmapUtils.rotateImage(result, storagePath);
                 }
                     
             } catch (NoSuchFieldError e) {
                 mErrorMessageId = R.string.common_error_unknown;
-                Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
+                Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " 
+                                + storagePath, e);
                     
             } catch (Throwable t) {
                 mErrorMessageId = R.string.common_error_unknown;
                 Log_OC.e(TAG, "Unexpected error loading " + getFile().getStoragePath(), t);
                 
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                        Log_OC.e(TAG, "Unexpected exception closing stream; trying to continue ", e);
+                    }
+                }
             }
+            
             return result;
         }
         
         @Override
+        protected void onCancelled(Bitmap result) {
+            if (result != null) {
+                result.recycle();
+            }
+        }
+
+        @Override
         protected void onPostExecute(Bitmap result) {
             hideProgressWheel();
             if (result != null) {
@@ -423,18 +469,21 @@ public class PreviewImageFragment extends FileFragment {
             } else {
                 showErrorMessage();
             }
+            if (mBitmap != null && mBitmap != result)  {
+                // unused bitmap, release it! (just in case)
+                result.recycle();
+            }
         }
-
+        
         @SuppressLint("InlinedApi")
         private void showLoadedImage(Bitmap result) {
             if (mImageViewRef != null) {
                 final ImageViewCustom imageView = mImageViewRef.get();
                 if (imageView != null) {
-                    imageView.setBitmap(result);
                     imageView.setImageBitmap(result);
                     imageView.setVisibility(View.VISIBLE);
-                    mBitmap  = result;
-                } // else , silently finish, the fragment was destroyed
+                    mBitmap  = result;  // needs to be kept for recycling when not useful
+                }
             }
             if (mMessageViewRef != null) {
                 final TextView messageView = mMessageViewRef.get();