Merge remote-tracking branch 'upstream/develop' into resizedImages
authortobiasKaminsky <tobias@kaminsky.me>
Wed, 1 Jul 2015 17:16:42 +0000 (19:16 +0200)
committertobiasKaminsky <tobias@kaminsky.me>
Wed, 1 Jul 2015 17:16:42 +0000 (19:16 +0200)
1  2 
AndroidManifest.xml
owncloud-android-library
src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
src/com/owncloud/android/files/FileOperationsHelper.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/ui/preview/PreviewImageActivity.java
src/com/owncloud/android/ui/preview/PreviewImageFragment.java
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java

diff --combined AndroidManifest.xml
              android:name=".providers.FileContentProvider"
              android:authorities="@string/authority"
              android:enabled="true"
 -            android:exported="false"
 +            android:exported="true"
              android:label="@string/sync_string_files"
              android:syncable="true" >
          </provider>
  
 +        <provider
 +            android:name=".ui.adapter.DiskLruImageCacheFileProvider"
 +            android:authorities="com.owncloud.imageCache.provider">
 +        </provider>
 +
          <activity
              android:name=".authentication.AuthenticatorActivity"
              android:exported="true"
          <service android:name=".files.services.FileUploader" />
          <service android:name=".media.MediaService" />
          
-         <activity android:name=".ui.activity.PinCodeActivity" />
+         <activity android:name=".ui.activity.PassCodeActivity" />
          <activity android:name=".ui.activity.ConflictsResolveActivity"/>
          <activity android:name=".ui.activity.GenericExplanationActivity"/>
          <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
diff --combined owncloud-android-library
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit 9e761387a0b406402684571f28c36c2d6d2b6301
 -Subproject commit f5fbca24becbb01660abe2a7013c1b536ea8a301
++Subproject commit d5aa05bc0ca126626536e035459a33b13eeaf0fd
  package com.owncloud.android.datamodel;
  
  import java.io.File;
+ import java.io.InputStream;
  import java.lang.ref.WeakReference;
  
  import org.apache.commons.httpclient.HttpStatus;
  import org.apache.commons.httpclient.methods.GetMethod;
  
  import android.accounts.Account;
 +import android.accounts.AccountManager;
 +import android.content.Context;
  import android.content.res.Resources;
  import android.graphics.Bitmap;
  import android.graphics.Bitmap.CompressFormat;
  import android.graphics.BitmapFactory;
 +import android.graphics.Point;
  import android.graphics.drawable.BitmapDrawable;
  import android.graphics.drawable.Drawable;
  import android.media.ThumbnailUtils;
  import android.net.Uri;
  import android.os.AsyncTask;
 +import android.view.Display;
 +import android.view.View;
 +import android.view.WindowManager;
  import android.widget.ImageView;
 +import android.widget.ProgressBar;
  
  import com.owncloud.android.MainApp;
  import com.owncloud.android.R;
+ import com.owncloud.android.authentication.AccountUtils;
  import com.owncloud.android.lib.common.OwnCloudAccount;
  import com.owncloud.android.lib.common.OwnCloudClient;
  import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
- import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
  import com.owncloud.android.lib.common.utils.Log_OC;
  import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  import com.owncloud.android.ui.adapter.DiskLruImageCache;
@@@ -66,8 -60,7 +67,7 @@@ public class ThumbnailsCacheManager 
      private static final String TAG = ThumbnailsCacheManager.class.getSimpleName();
      
      private static final String CACHE_FOLDER = "thumbnailCache";
-     private static final String MINOR_SERVER_VERSION_FOR_THUMBS = "7.8.0";
-     
      private static final Object mThumbnailsDiskCacheLock = new Object();
      private static DiskLruImageCache mThumbnailCache = null;
      private static boolean mThumbnailCacheStarting = true;
@@@ -76,7 -69,6 +76,6 @@@
      private static final CompressFormat mCompressFormat = CompressFormat.JPEG;
      private static final int mCompressQuality = 70;
      private static OwnCloudClient mClient = null;
-     private static String mServerVersion = null;
  
      public static Bitmap mDefaultImg = 
              BitmapFactory.decodeResource(
              while (mThumbnailCacheStarting) {
                  try {
                      mThumbnailsDiskCacheLock.wait();
-                 } catch (InterruptedException e) {}
+                 } catch (InterruptedException e) {
+                     Log_OC.e(TAG, "Wait in mThumbnailsDiskCacheLock was interrupted", e);
+                 }
              }
              if (mThumbnailCache != null) {
-                 return (Bitmap) mThumbnailCache.getBitmap(key);
+                 return mThumbnailCache.getBitmap(key);
              }
          }
          return null;
  
      public static class ThumbnailGenerationTask extends AsyncTask<Object, Void, Bitmap> {
          private final WeakReference<ImageView> mImageViewReference;
 +        private WeakReference<ProgressBar> mProgressWheelRef;
          private static Account mAccount;
          private Object mFile;
 +        private Boolean mIsThumbnail;
          private FileDataStorageManager mStorageManager;
  
 -
          public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager,
                                         Account account) {
              // Use a WeakReference to ensure the ImageView can be garbage collected
              mAccount = account;
          }
  
 +        public ThumbnailGenerationTask(ImageView imageView, FileDataStorageManager storageManager,
 +                                       Account account, ProgressBar progressWheel) {
 +        this(imageView, storageManager, account);
 +        mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
 +        }
 +
          public ThumbnailGenerationTask(ImageView imageView) {
              // Use a WeakReference to ensure the ImageView can be garbage collected
              mImageViewReference = new WeakReference<ImageView>(imageView);
  
              try {
                  if (mAccount != null) {
-                     AccountManager accountMgr = AccountManager.get(MainApp.getAppContext());
-                     mServerVersion = accountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);
                      OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount,
                              MainApp.getAppContext());
                      mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                  }
  
                  mFile = params[0];
 +                mIsThumbnail = (Boolean) params[1];
 +
                  
                  if (mFile instanceof OCFile) {
 -                    thumbnail = doOCFileInBackground();
 +                    thumbnail = doOCFileInBackground(mIsThumbnail);
                  }  else if (mFile instanceof File) {
 -                    thumbnail = doFileInBackground();
 -                //} else {  do nothing
 +                    thumbnail = doFileInBackground(mIsThumbnail);
 +                } else {
 +                    // do nothing
                  }
  
                  }catch(Throwable t){
                  bitmap = null;
              }
  
-             if (mImageViewReference != null && bitmap != null) {
+             if (bitmap != null) {
                  final ImageView imageView = mImageViewReference.get();
                  final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
-                 if (this == bitmapWorkerTask && imageView != null) {
+                 if (this == bitmapWorkerTask) {
                      String tagId = "";
                      if (mFile instanceof OCFile){
                          tagId = String.valueOf(((OCFile)mFile).getFileId());
                      } else if (mFile instanceof File){
-                         tagId = String.valueOf(((File)mFile).hashCode());
+                         tagId = String.valueOf(mFile.hashCode());
                      }
                      if (String.valueOf(imageView.getTag()).equals(tagId)) {
 +                        if (mProgressWheelRef != null) {
 +                            final ProgressBar progressWheel = mProgressWheelRef.get();
 +                            if (progressWheel != null) {
 +                                progressWheel.setVisibility(View.GONE);
 +                            }
 +                        }
                          imageView.setImageBitmap(bitmap);
 +                        imageView.setVisibility(View.VISIBLE);
                      }
                  }
              }
           * @param imageKey: thumb key
           * @param bitmap:   image for extracting thumbnail
           * @param path:     image path
 -         * @param px:       thumbnail dp
 +         * @param pxW:       thumbnail width
 +         * @param pxH:       thumbnail height
           * @return Bitmap
           */
 -        private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int px){
 +        private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, int pxW, int pxH){
  
 -            Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
 +            Bitmap thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
  
              // Rotate image, obeying exif tag
              thumbnail = BitmapUtils.rotateImage(thumbnail,path);
          private int getThumbnailDimension(){
              // Converts dp to pixel
              Resources r = MainApp.getAppContext().getResources();
-             return (int) Math.round(r.getDimension(R.dimen.file_icon_size_grid));
+             return Math.round(r.getDimension(R.dimen.file_icon_size_grid));
          }
  
 -        private Bitmap doOCFileInBackground() {
 +        private Point getScreenDimension(){
 +            WindowManager wm = (WindowManager) MainApp.getAppContext().getSystemService(Context.WINDOW_SERVICE);
 +            Display display = wm.getDefaultDisplay();
 +            Point test = new Point();
 +            display.getSize(test);
 +            return test;
 +        }
 +
 +        private Bitmap doOCFileInBackground(Boolean isThumbnail) {
 +            Bitmap thumbnail = null;
              OCFile file = (OCFile)mFile;
  
 -            final String imageKey = String.valueOf(file.getRemoteId());
 +            // distinguish between thumbnail and resized image
 +            String temp = String.valueOf(file.getRemoteId());
 +            if (isThumbnail){
 +                temp = "t" + temp;
 +            } else {
 +                temp = "r" + temp;
 +            }
 +
 +            final String imageKey = temp;
  
              // Check disk cache in background thread
 -            Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
 +            thumbnail = getBitmapFromDiskCache(imageKey);
  
              // Not found in disk cache
              if (thumbnail == null || file.needsUpdateThumbnail()) {
 -
 -                int px = getThumbnailDimension();
 +                int pxW = 0;
 +                int pxH = 0;
 +                if (mIsThumbnail) {
 +                    pxW = pxH = getThumbnailDimension();
 +                } else {
 +                    Point p = getScreenDimension();
 +                    pxW = p.x;
 +                    pxH = p.y;
 +                }
  
                  if (file.isDown()) {
                      Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
 -                            file.getStoragePath(), px, px);
 +                            file.getStoragePath(), pxW, pxH);
  
                      if (bitmap != null) {
 -                        thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), px);
 +                        thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
  
                          file.setNeedsUpdateThumbnail(false);
                          mStorageManager.saveFile(file);
  
                  } else {
                      // Download thumbnail from server
-                     if (mClient != null && mServerVersion != null) {
-                         OwnCloudVersion serverOCVersion = new OwnCloudVersion(mServerVersion);
-                         if (serverOCVersion.compareTo(
-                                 new OwnCloudVersion(MINOR_SERVER_VERSION_FOR_THUMBS)) >= 0) {
+                     OwnCloudVersion serverOCVersion = AccountUtils.getServerVersion(mAccount);
+                     if (mClient != null && serverOCVersion != null) {
+                         if (serverOCVersion.supportsRemoteThumbnails()) {
                              try {
-                                 int status = -1;
                                  String uri = mClient.getBaseUri() + "" +
                                          "/index.php/apps/files/api/v1/thumbnail/" +
 -                                        px + "/" + px + Uri.encode(file.getRemotePath(), "/");
 +                                        pxW + "/" + pxH + Uri.encode(file.getRemotePath(), "/");
                                  Log_OC.d("Thumbnail", "URI: " + uri);
                                  GetMethod get = new GetMethod(uri);
-                                 status = mClient.executeMethod(get);
+                                 int status = mClient.executeMethod(get);
                                  if (status == HttpStatus.SC_OK) {
 -                                    thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
+ //                                    byte[] bytes = get.getResponseBody();
+ //                                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
+ //                                            bytes.length);
+                                     InputStream inputStream = get.getResponseBodyAsStream();
+                                     Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
-                                     Log_OC.d("Thumbnail", type + " size of " + file.getRemotePath() + ": " + bytes.length);
++                                    thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
 +                                    byte[] bytes = get.getResponseBody();
 +
 +                                    String type = "";
 +                                    if (mIsThumbnail){
 +                                        type = "Thumbnail";
 +                                    } else {
 +                                        type = "Resized image";
 +                                    }
-                                     Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
-                                             bytes.length);
++                                    Log_OC.d("Thumbnail",
++                                            type + " size of " + file.getRemotePath()
++                                                 + ": " + bytes.length);
 +
++                                    // bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
 +
 +                                    if (mIsThumbnail) {
 +                                        thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
 +                                    } else {
 +                                        thumbnail = bitmap;
 +                                    }
  
                                      // Add thumbnail to cache
                                      if (thumbnail != null) {
  
          }
  
 -        private Bitmap doFileInBackground() {
 +        private Bitmap doFileInBackground(Boolean mIsThumbnail) {
 +            Bitmap thumbnail = null;
              File file = (File)mFile;
  
              final String imageKey = String.valueOf(file.hashCode());
  
              // Check disk cache in background thread
 -            Bitmap thumbnail = getBitmapFromDiskCache(imageKey);
 +            thumbnail = getBitmapFromDiskCache(imageKey);
  
              // Not found in disk cache
              if (thumbnail == null) {
 -
 -                int px = getThumbnailDimension();
 +                int pxW = 0;
 +                int pxH = 0;
 +                if (mIsThumbnail) {
 +                    pxW = pxH = getThumbnailDimension();
 +                } else {
 +                    Point p = getScreenDimension();
 +                    pxW = p.x;
 +                    pxH = p.y;
 +                }
  
                  Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
 -                        file.getAbsolutePath(), px, px);
 +                        file.getAbsolutePath(), pxW, pxH);
  
                  if (bitmap != null) {
 -                    thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
 +                    thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), pxW, pxH);
                  }
              }
              return thumbnail;
@@@ -24,36 -24,25 +24,35 @@@ package com.owncloud.android.files
  import org.apache.http.protocol.HTTP;
  
  import android.accounts.Account;
- import android.accounts.AccountManager;
  import android.content.Intent;
 +import android.graphics.Bitmap;
  import android.net.Uri;
  import android.support.v4.app.DialogFragment;
  import android.webkit.MimeTypeMap;
  import android.widget.Toast;
  
 +import com.owncloud.android.MainApp;
  import com.owncloud.android.R;
+ import com.owncloud.android.authentication.AccountUtils;
  import com.owncloud.android.datamodel.OCFile;
 +import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
  
- import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
  import com.owncloud.android.lib.common.network.WebdavUtils;
  import com.owncloud.android.lib.common.utils.Log_OC;
  import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  import com.owncloud.android.services.OperationsService;
  import com.owncloud.android.ui.activity.FileActivity;
 +import com.owncloud.android.ui.adapter.DiskLruImageCacheFileProvider;
  import com.owncloud.android.ui.dialog.ShareLinkToDialog;
  
 +import java.io.ByteArrayOutputStream;
 +import java.io.File;
 +import java.io.FileNotFoundException;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +
  /**
   *
   */
@@@ -80,19 -69,25 +79,25 @@@ public class FileOperationsHelper 
              
              Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
              intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-             intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+             intentForSavedMimeType.setFlags(
+                     Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+             );
              
              Intent intentForGuessedMimeType = null;
              if (storagePath.lastIndexOf('.') >= 0) {
-                 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                 String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+                         storagePath.substring(storagePath.lastIndexOf('.') + 1)
+                 );
                  if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
                      intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
                      intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
-                     intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                     intentForGuessedMimeType.setFlags(
+                             Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                     );
                  }
              }
              
-             Intent chooserIntent = null;
+             Intent chooserIntent;
              if (intentForGuessedMimeType != null) {
                  chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
              } else {
              
          } else {
              // Show a Message
-             Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+             Toast t = Toast.makeText(
+                     mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
+             );
              t.show();
          }
      }
       */
      public boolean isSharedSupported() {
          if (mFileActivity.getAccount() != null) {
-             AccountManager accountManager = AccountManager.get(mFileActivity);
-             String version = accountManager.getUserData(mFileActivity.getAccount(), Constants.KEY_OC_VERSION);
-             return (new OwnCloudVersion(version)).isSharedSupported();
+             OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+             return (serverVersion != null && serverVersion.isSharedSupported());
          }
          return false;
      }
              Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
          }
      }
 +
 +    public void sendCachedImage(OCFile file) {
 +        if (file != null) {
 +            Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
 +            // set MimeType
 +            sendIntent.setType(file.getMimetype());
 +//            sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + "/#" + file.getRemoteId() + "#" + file.getFileName()));
 +            sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + DiskLruImageCacheFileProvider.AUTHORITY + file.getRemotePath()));
 +            sendIntent.putExtra(Intent.ACTION_SEND, true);      // Send Action
 +
 +            // Show dialog, without the own app
 +            String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
 +            DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
 +            chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
 +        } else {
 +            Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
 +        }
 +    }
      
      
      public void syncFile(OCFile file) {
          mWaitingForOpId = waitingForOpId;
      }
      
-     
+     /**
+      *  @return 'True' if the server doesn't need to check forbidden characters
+      */
+     public boolean isVersionWithForbiddenCharacters() {
+         if (mFileActivity.getAccount() != null) {
+             OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+             return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
+         }
+         return false;
+     }
  }
@@@ -158,17 -158,22 +158,22 @@@ public class FileListListAdapter extend
              viewType = ViewType.GRID_ITEM;\r
          }\r
  \r
-         // Create View\r
-         switch (viewType){\r
-             case GRID_IMAGE:\r
-                 view = inflator.inflate(R.layout.grid_image, null);\r
-                 break;\r
-             case GRID_ITEM:\r
-                 view = inflator.inflate(R.layout.grid_item, null);\r
-                 break;\r
-             case LIST_ITEM:\r
-                 view = inflator.inflate(R.layout.list_item, null);\r
-                 break;\r
+         // create view only if differs, otherwise reuse\r
+         if (convertView == null || (convertView != null && convertView.getTag() != viewType)) {\r
+             switch (viewType) {\r
+                 case GRID_IMAGE:\r
+                     view = inflator.inflate(R.layout.grid_image, null);\r
+                     view.setTag(ViewType.GRID_IMAGE);\r
+                     break;\r
+                 case GRID_ITEM:\r
+                     view = inflator.inflate(R.layout.grid_item, null);\r
+                     view.setTag(ViewType.GRID_ITEM);\r
+                     break;\r
+                 case LIST_ITEM:\r
+                     view = inflator.inflate(R.layout.list_item, null);\r
+                     view.setTag(ViewType.LIST_ITEM);\r
+                     break;\r
+             }\r
          }\r
  \r
          view.invalidate();\r
                                      task\r
                                      );\r
                              fileIcon.setImageDrawable(asyncDrawable);\r
 -                            task.execute(file);\r
 +                            task.execute(file, true);\r
                          }\r
                      }\r
                  } else {\r
       * @param updatedStorageManager     Optional updated storage manager; used to replace \r
       *                                  mStorageManager if is different (and not NULL)\r
       */\r
-     public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {\r
+     public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager\r
+             /*, boolean onlyOnDevice*/) {\r
          mFile = directory;\r
          if (updatedStorageManager != null && updatedStorageManager != mStorageManager) {\r
              mStorageManager = updatedStorageManager;\r
              mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
          }\r
          if (mStorageManager != null) {\r
-             mFiles = mStorageManager.getFolderContent(mFile);\r
+             // TODO Enable when "On Device" is recovered ?\r
+             mFiles = mStorageManager.getFolderContent(mFile/*, onlyOnDevice*/);\r
              mFilesOrig.clear();\r
              mFilesOrig.addAll(mFiles);\r
              \r
@@@ -36,10 -36,13 +36,13 @@@ import android.widget.AdapterView
  import android.widget.AdapterView.AdapterContextMenuInfo;
  
  import com.owncloud.android.R;
+ import com.owncloud.android.authentication.AccountUtils;
  import com.owncloud.android.datamodel.FileDataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.files.FileMenuFilter;
  import com.owncloud.android.lib.common.utils.Log_OC;
+ import com.owncloud.android.lib.resources.status.OwnCloudVersion;
+ import com.owncloud.android.ui.activity.FileActivity;
  import com.owncloud.android.ui.activity.FileDisplayActivity;
  import com.owncloud.android.ui.activity.FolderPickerActivity;
  import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
@@@ -54,7 -57,7 +57,7 @@@ import com.owncloud.android.utils.FileS
  /**
   * A Fragment that lists all files and folders in a given path.
   * 
-  * TODO refactorize to get rid of direct dependency on FileDisplayActivity
+  * TODO refactor to get rid of direct dependency on FileDisplayActivity
   */
  public class OCFileListFragment extends ExtendedListFragment {
      
@@@ -68,8 -71,6 +71,6 @@@
              
      private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
  
-     private final static Double THUMBNAIL_THRESHOLD = 0.5;
      private FileFragment.ContainerActivity mContainerActivity;
     
      private OCFile mFile = null;
@@@ -77,7 -78,8 +78,8 @@@
      private boolean mJustFolders;
      
      private OCFile mTargetFile;
+     
+    
      
      /**
       * {@inheritDoc}
          mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
          mAdapter = new FileListListAdapter(
                  mJustFolders,
-                 getSherlockActivity(),
+                 getActivity(),
                  mContainerActivity
                  );
          setListAdapter(mAdapter);
                  moveCount++;
              }   // exit is granted because storageManager.getFileByPath("/") never returns null
              mFile = parentDir;
-             
-             listDirectory(mFile);
+             // TODO Enable when "On Device" is recovered ?
+             listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/);
  
              onRefresh(false);
              
          if (file != null) {
              if (file.isFolder()) { 
                  // update state and view of this fragment
-                 listDirectory(file);
+                 // TODO Enable when "On Device" is recovered ?
+                 listDirectory(file/*, MainApp.getOnlyOnDevice()*/);
                  // then, notify parent activity to let it update its state and view
                  mContainerActivity.onBrowsedDownTo(file);
                  // save index and top position
                          mContainerActivity.getFileOperationsHelper().openFile(file);
                      }
                      
 -                } else {
 -                    // automatic download, preview on finish
 -                    ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file);
                  }
 -                    
              }
              
          } else {
          boolean allowContextualActions = 
                  (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); 
          if (allowContextualActions) {
-             MenuInflater inflater = getSherlockActivity().getMenuInflater();
+             MenuInflater inflater = getActivity().getMenuInflater();
              inflater.inflate(R.menu.file_actions_menu, menu);
              AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
              OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
                      targetFile,
                      mContainerActivity.getStorageManager().getAccount(),
                      mContainerActivity,
-                     getSherlockActivity()
+                     getActivity()
                  );
                  mf.filter(menu);
              }
                   
              /// TODO break this direct dependency on FileDisplayActivity... if possible
              MenuItem item = menu.findItem(R.id.action_open_file_with);
-             FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).getSecondFragment();
+             FileFragment frag = ((FileDisplayActivity)getActivity()).getSecondFragment();
              if (frag != null && frag instanceof FileDetailFragment && 
                      frag.getFile().getFileId() == targetFile.getFileId()) {
                  item = menu.findItem(R.id.action_see_details);
      /**
       * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
       */
-     public void listDirectory(){
+     public void listDirectory(/*boolean onlyOnDevice*/){
          listDirectory(null);
+         // TODO Enable when "On Device" is recovered ?
+         // listDirectory(null, onlyOnDevice);
+     }
+     
+     public void refreshDirectory(){
+         // TODO Enable when "On Device" is recovered ?
+         listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/);
      }
      
      /**
       * 
       * @param directory File to be listed
       */
-     public void listDirectory(OCFile directory) {
+     public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) {
          FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
          if (storageManager != null) {
  
                  directory = storageManager.getFileById(directory.getParentId());
              }
  
-             mAdapter.swapDirectory(directory, storageManager);
+             // TODO Enable when "On Device" is recovered ?
+             mAdapter.swapDirectory(directory, storageManager/*, onlyOnDevice*/);
              if (mFile == null || !mFile.equals(directory)) {
                  mCurrentListView.setSelection(0);
              }
              setFooterText(generateFooterText(filesCount, foldersCount));
  
              // decide grid vs list view
-             if (((double)imagesCount / (double)filesCount) >= THUMBNAIL_THRESHOLD) {
+             OwnCloudVersion version = AccountUtils.getServerVersion(
+                     ((FileActivity)mContainerActivity).getAccount());
+             if (version != null && version.supportsRemoteThumbnails() &&
+                 imagesCount > 0 && imagesCount == filesCount) {
                  switchToGridView();
              } else {
                  switchToListView();
      public void sortBySize(boolean descending) {
          mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
      }  
+     
+    
+     
  }
@@@ -8,7 -8,7 +8,7 @@@
   *   it under the terms of the GNU General Public License version 2,
   *   as published by the Free Software Foundation.
   *
-  *   This program is distributed in the hope that it will be useful,
+  *   This program is distributed in the hd that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
@@@ -26,19 -26,19 +26,19 @@@ import android.content.Context
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.ServiceConnection;
- import android.content.SharedPreferences;
  import android.os.Build;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.IBinder;
  import android.os.Message;
- import android.preference.PreferenceManager;
+ import android.support.v4.view.GravityCompat;
  import android.support.v4.view.ViewPager;
+ import android.support.v4.widget.DrawerLayout;
+ import android.support.v7.app.ActionBar;
+ import android.view.MenuItem;
  import android.view.View;
+ import android.view.Window;
  
- import com.actionbarsherlock.app.ActionBar;
- import com.actionbarsherlock.view.MenuItem;
- import com.actionbarsherlock.view.Window;
  import com.ortiz.touch.ExtendedViewPager;
  import com.owncloud.android.R;
  import com.owncloud.android.authentication.AccountUtils;
@@@ -58,7 -58,6 +58,6 @@@ import com.owncloud.android.operations.
  import com.owncloud.android.operations.UnshareLinkOperation;
  import com.owncloud.android.ui.activity.FileActivity;
  import com.owncloud.android.ui.activity.FileDisplayActivity;
- import com.owncloud.android.ui.activity.PinCodeActivity;
  import com.owncloud.android.ui.fragment.FileFragment;
  import com.owncloud.android.utils.DisplayUtils;
  
@@@ -66,9 -65,9 +65,9 @@@
  /**
   *  Holds a swiping galley where image files contained in an ownCloud directory are shown
   */
- public class PreviewImageActivity extends FileActivity implements 
-  FileFragment.ContainerActivity,
- ViewPager.OnPageChangeListener, OnRemoteOperationListener {
+ public class PreviewImageActivity extends FileActivity implements
+         FileFragment.ContainerActivity,
        ViewPager.OnPageChangeListener, OnRemoteOperationListener {
      
      public static final int DIALOG_SHORT_WAIT = 0;
  
      
      private View mFullScreenAnchorView;
      
-     
      @Override
      protected void onCreate(Bundle savedInstanceState) {
+         requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
          super.onCreate(savedInstanceState);
  
-         requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
          setContentView(R.layout.preview_image_activity);
-         
+         // Navigation Drawer
+         initDrawer();
+         // ActionBar
          ActionBar actionBar = getSupportActionBar();
          actionBar.setIcon(DisplayUtils.getSeasonalIconId());
-         actionBar.setDisplayHomeAsUpEnabled(true);
+         updateActionBarTitleAndHomeButton(null);
          actionBar.hide();
-         
-         // PIN CODE request
-         if (getIntent().getExtras() != null && savedInstanceState == null && fromNotification()) {
-             requestPinCode();
-         }
  
          // Make sure we're running on Honeycomb or higher to use FullScreen and
          // Immersive Mode
              mFullScreenAnchorView = getWindow().getDecorView();
              // to keep our UI controls visibility in line with system bars
              // visibility
-             mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+             mFullScreenAnchorView.setOnSystemUiVisibilityChangeListener
+                     (new View.OnSystemUiVisibilityChangeListener() {
                  @SuppressLint("InlinedApi")
                  @Override
                  public void onSystemUiVisibilityChange(int flags) {
                      ActionBar actionBar = getSupportActionBar();
                      if (visible) {
                          actionBar.show();
+                         mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
                      } else {
                          actionBar.hide();
+                         mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                      }
                  }
              });
  
      private void initViewPager() {
          // get parent from path
-         String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
+         String parentPath = getFile().getRemotePath().substring(0,
+                 getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
          OCFile parentFolder = getStorageManager().getFileByPath(parentPath);
          if (parentFolder == null) {
              // should not be necessary
              parentFolder = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
          }
-         mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), getStorageManager());
+         // TODO Enable when "On Device" is recovered ?
+         mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(),
+                 parentFolder, getAccount(), getStorageManager()/*, MainApp.getOnlyOnDevice()*/);
          mViewPager = (ExtendedViewPager) findViewById(R.id.fragmentPager);
-         int position = mHasSavedPosition ? mSavedPosition : mPreviewImagePagerAdapter.getFilePosition(getFile());
+         int position = mHasSavedPosition ? mSavedPosition :
+                 mPreviewImagePagerAdapter.getFilePosition(getFile());
          position = (position >= 0) ? position : 0;
          mViewPager.setAdapter(mPreviewImagePagerAdapter); 
          mViewPager.setOnPageChangeListener(this);
          mViewPager.setCurrentItem(position);
          if (position == 0 && !getFile().isDown()) {
-             // this is necessary because mViewPager.setCurrentItem(0) just after setting the adapter does not result in a call to #onPageSelected(0) 
+             // this is necessary because mViewPager.setCurrentItem(0) just after setting the
+             // adapter does not result in a call to #onPageSelected(0)
              mRequestWaitingForBinder = true;
          }
      }
      }
      
      
-     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+                                               RemoteOperationResult result) {
          if (result.isSuccess()) {
              OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
              if (file != null) {
              
      }
      
-     private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+     private void onCreateShareOperationFinish(CreateShareOperation operation,
+                                               RemoteOperationResult result) {
          if (result.isSuccess()) {
              OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
              if (file != null) {
          @Override
          public void onServiceConnected(ComponentName component, IBinder service) {
                  
-             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+             if (component.equals(new ComponentName(PreviewImageActivity.this,
+                     FileDownloader.class))) {
                  mDownloaderBinder = (FileDownloaderBinder) service;
                  if (mRequestWaitingForBinder) {
                      mRequestWaitingForBinder = false;
-                     Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder");
+                     Log_OC.d(TAG, "Simulating reselection of current page after connection " +
+                             "of download binder");
                      onPageSelected(mViewPager.getCurrentItem());
                  }
  
-             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+             } else if (component.equals(new ComponentName(PreviewImageActivity.this,
+                     FileUploader.class))) {
                  Log_OC.d(TAG, "Upload service connected");
                  mUploaderBinder = (FileUploaderBinder) service;
              } else {
  
          @Override
          public void onServiceDisconnected(ComponentName component) {
-             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+             if (component.equals(new ComponentName(PreviewImageActivity.this,
+                     FileDownloader.class))) {
                  Log_OC.d(TAG, "Download service suddenly disconnected");
                  mDownloaderBinder = null;
-             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
+             } else if (component.equals(new ComponentName(PreviewImageActivity.this,
+                     FileUploader.class))) {
                  Log_OC.d(TAG, "Upload service suddenly disconnected");
                  mUploaderBinder = null;
              }
          
          switch(item.getItemId()){
          case android.R.id.home:
-             backToDisplayActivity();
+             if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
+                 mDrawerLayout.closeDrawer(GravityCompat.START);
+             } else {
+                 backToDisplayActivity();
+             }
              returnValue = true;
              break;
          default:
      @Override
      protected void onResume() {
          super.onResume();
-         //Log_OC.e(TAG, "ACTIVITY, ONRESUME");
          mDownloadFinishReceiver = new DownloadFinishReceiver();
          
          IntentFilter filter = new IntentFilter(FileDownloader.getDownloadFinishMessage());
  
      @Override
      protected void onPostResume() {
-         //Log_OC.e(TAG, "ACTIVITY, ONPOSTRESUME");
          super.onPostResume();
      }
      
      @Override
      public void onPause() {
-         unregisterReceiver(mDownloadFinishReceiver);
-         mDownloadFinishReceiver = null;
+         if (mDownloadFinishReceiver != null){
+             unregisterReceiver(mDownloadFinishReceiver);
+             mDownloadFinishReceiver = null;
+         }
+         
          super.onPause();
      }
      
          Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
          showDetailsIntent.setAction(FileDisplayActivity.ACTION_DETAILS);
          showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, file);
-         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT,
+                 AccountUtils.getCurrentOwnCloudAccount(this));
          startActivity(showDetailsIntent);
          int pos = mPreviewImagePagerAdapter.getFilePosition(file);
          file = mPreviewImagePagerAdapter.getFileAt(pos);
      }
  
      /**
-      * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
+      * This method will be invoked when a new page becomes selected. Animation is not necessarily
+      * complete.
       * 
-      *  @param  Position        Position index of the new selected page
+      *  @param  position        Position index of the new selected page
       */
      @Override
      public void onPageSelected(int position) {
          } else {
              OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); 
              getSupportActionBar().setTitle(currentFile.getFileName());
+             mDrawerToggle.setDrawerIndicatorEnabled(false);
 -            if (!currentFile.isDown()) {
 -                if (!mPreviewImagePagerAdapter.pendingErrorAt(position)) {
 -                    requestForDownload(currentFile);
 -                }
 -            }
 -
++            
              // Call to reset image zoom to initial state
              ((PreviewImagePagerAdapter) mViewPager.getAdapter()).resetZoom();
          }
       * Called when the scroll state changes. Useful for discovering when the user begins dragging, 
       * when the pager is automatically settling to the current page. when it is fully stopped/idle.
       * 
-      * @param   State       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
+      * @param   state       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
       */
      @Override
      public void onPageScrollStateChanged(int state) {
      }
  
      /**
-      * This method will be invoked when the current page is scrolled, either as part of a programmatically 
-      * initiated smooth scroll or a user initiated touch scroll.
+      * This method will be invoked when the current page is scrolled, either as part of a
+      * programmatically initiated smooth scroll or a user initiated touch scroll.
       * 
       * @param   position                Position index of the first page currently being displayed. 
-      *                                  Page position+1 will be visible if positionOffset is nonzero.
+      *                                  Page position+1 will be visible if positionOffset is
+      *                                  nonzero.
       *                                  
-      * @param   positionOffset          Value from [0, 1) indicating the offset from the page at position.
+      * @param   positionOffset          Value from [0, 1) indicating the offset from the page
+      *                                  at position.
       * @param   positionOffsetPixels    Value in pixels indicating the offset from position. 
       */
      @Override
  
                  OCFile file = getStorageManager().getFileByPath(downloadedRemotePath);
                  int position = mPreviewImagePagerAdapter.getFilePosition(file);
-                 boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
-                 //boolean isOffscreen =  Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit();
+                 boolean downloadWasFine = intent.getBooleanExtra(
+                         FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
+                 //boolean isOffscreen =  Math.abs((mViewPager.getCurrentItem() - position))
+                 // <= mViewPager.getOffscreenPageLimit();
                  
-                 if (position >= 0 && intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) {
+                 if (position >= 0 &&
+                         intent.getAction().equals(FileDownloader.getDownloadFinishMessage())) {
                      if (downloadWasFine) {
                          mPreviewImagePagerAdapter.updateFile(position, file);   
                          
                      } else {
                          mPreviewImagePagerAdapter.updateWithDownloadError(position);
                      }
-                     mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation of new fragments
+                     mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation
+                                                                         // of new fragments
                      
                  } else {
                      Log_OC.d(TAG, "Download finished, but the fragment is offscreen");
              ActionBar actionBar = getSupportActionBar();
              if (!actionBar.isShowing()) {
                  actionBar.show();
+                 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
  
              } else {
                  actionBar.hide();
+                 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
  
              }
  
              }
          }
      }
-     
-     
-     /**
-      * Launch an intent to request the PIN code to the user before letting him use the app
-      */
-     private void requestPinCode() {
-         boolean pinStart = false;
-         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-         pinStart = appPrefs.getBoolean("set_pincode", false);
-         if (pinStart) {
-             Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
-             i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "PreviewImageActivity");
-             startActivity(i);
-         }
-     }
  
      @Override
      public void onBrowsedDownTo(OCFile folder) {
          return false;
      }
  
+     @Override
+     public void allFilesOption(){
+         backToDisplayActivity();
+         super.allFilesOption();
+     }
  }
   */
  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;
  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.Menu;
+ import android.view.MenuInflater;
+ import android.view.MenuItem;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.view.ViewGroup;
@@@ -46,43 -40,39 +40,43 @@@ import android.widget.ImageView
  import android.widget.ProgressBar;
  import android.widget.TextView;
  
- import com.actionbarsherlock.view.Menu;
- import com.actionbarsherlock.view.MenuInflater;
- import com.actionbarsherlock.view.MenuItem;
 +import com.owncloud.android.MainApp;
  import com.owncloud.android.R;
  import com.owncloud.android.datamodel.OCFile;
 +import com.owncloud.android.datamodel.ThumbnailsCacheManager;
  import com.owncloud.android.files.FileMenuFilter;
  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.BitmapUtils;
+ import com.owncloud.android.utils.DisplayUtils;
  
  import third_parties.michaelOrtiz.TouchImageViewCustom;
  
  
  /**
   * This fragment shows a preview of a downloaded image.
+  *
+  * Trying to get an instance with a NULL {@link OCFile} will produce an
+  * {@link IllegalStateException}.
   * 
-  * 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.
+  * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on
+  * instantiation too.
   */
  public class PreviewImageFragment extends FileFragment {
  
      public static final String EXTRA_FILE = "FILE";
-     public static final String EXTRA_ACCOUNT = "ACCOUNT";
  
-     private View mView;
-     private Account mAccount;
+     private static final String ARG_FILE = "FILE";
+     private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST";
      private TouchImageViewCustom mImageView;
      private TextView mMessageView;
      private ProgressBar mProgressWheel;
  
 +    private Boolean mShowResizedImage = false;
 +
      public Bitmap mBitmap = null;
      
      private static final String TAG = PreviewImageFragment.class.getSimpleName();
      
      private LoadBitmapTask mLoadBitmapTask = null;
  
-     
      /**
-      * Creates a fragment to preview an image.
-      * 
-      * When 'imageFile' or 'ocAccount' are null
-      * 
-      * @param fileToDetail              An {@link OCFile} to preview as an image in the fragment
-      * @param ocAccount                 An ownCloud account; needed to start downloads
-      * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution 
+      * Public factory method to create a new fragment that previews an image.
+      *
+      * Android strongly recommends keep the empty constructor of fragments as the only public
+      * constructor, and
+      * use {@link #setArguments(Bundle)} to set the needed arguments.
+      *
+      * This method hides to client objects the need of doing the construction in two steps.
+      *
+      * @param imageFile                 An {@link OCFile} to preview as an image in the fragment
+      * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of
+      *                                  {@link FragmentStatePagerAdapter}
+      *                                  ; TODO better solution
       */
-     public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState, boolean showResizedImage) {
-         super(fileToDetail);
-         mAccount = ocAccount;
-         mShowResizedImage = showResizedImage;
-         mIgnoreFirstSavedState = ignoreFirstSavedState;
 -    public static PreviewImageFragment newInstance(OCFile imageFile, boolean ignoreFirstSavedState){
++    public static PreviewImageFragment newInstance(OCFile imageFile, boolean ignoreFirstSavedState,
++            boolean showResizedImage){
+         PreviewImageFragment frag = new PreviewImageFragment();
++        frag.mShowResizedImage = showResizedImage;
+         Bundle args = new Bundle();
+         args.putParcelable(ARG_FILE, imageFile);
+         args.putBoolean(ARG_IGNORE_FIRST, ignoreFirstSavedState);
+         frag.setArguments(args);
+         return frag;
      }
      
      
      /**
       *  Creates an empty fragment for image previews.
       * 
-      *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+      *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
+      *  (for instance, when the device is turned a aside).
       * 
-      *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+      *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
+      *  construction
       */
      public PreviewImageFragment() {
-         super();
-         mAccount = null;
          mIgnoreFirstSavedState = false;
      }
      
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
+         Bundle args = getArguments();
+         setFile((OCFile)args.getParcelable(ARG_FILE));
+             // TODO better in super, but needs to check ALL the class extending FileFragment;
+             // not right now
+         mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST);
          setHasOptionsMenu(true);
      }
      
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
              Bundle savedInstanceState) {
          super.onCreateView(inflater, container, savedInstanceState);
-         mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
-         mImageView = (TouchImageViewCustom) mView.findViewById(R.id.image);
+         View view = inflater.inflate(R.layout.preview_image_fragment, container, false);
+         mImageView = (TouchImageViewCustom) view.findViewById(R.id.image);
          mImageView.setVisibility(View.GONE);
          mImageView.setOnClickListener(new OnClickListener() {
              @Override
              }
  
          });
-         mMessageView = (TextView)mView.findViewById(R.id.message);
+         mMessageView = (TextView)view.findViewById(R.id.message);
          mMessageView.setVisibility(View.GONE);
-         mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel);
+         mProgressWheel = (ProgressBar)view.findViewById(R.id.progressWheel);
          mProgressWheel.setVisibility(View.VISIBLE);
-         return mView;
+         return view;
      }
  
      /**
          super.onActivityCreated(savedInstanceState);
          if (savedInstanceState != null) {
              if (!mIgnoreFirstSavedState) {
-                 OCFile file = (OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+                 OCFile file = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
                  setFile(file);
-                 mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
              } else {
                  mIgnoreFirstSavedState = false;
              }
          if (getFile() == null) {
              throw new IllegalStateException("Instanced with a NULL OCFile");
          }
-         if (mAccount == null) {
-             throw new IllegalStateException("Instanced with a NULL ownCloud Account");
 -        if (!getFile().isDown()) {
 -            throw new IllegalStateException("There is no local file to preview");
--        }
      }
          
  
      public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          outState.putParcelable(PreviewImageFragment.EXTRA_FILE, getFile());
-         outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
      }
      
  
      public void onStart() {
          super.onStart();
          if (getFile() != null) {
 -            mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel);
 -            //mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()});
 -            mLoadBitmapTask.execute(getFile().getStoragePath());
 +            mImageView.setTag(getFile().getFileId());
 +
 +            if (mShowResizedImage){
 +                Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
 +                        String.valueOf("r" + getFile().getRemoteId())
 +                );
 +
 +                if (thumbnail != null && !getFile().needsUpdateThumbnail()){
 +                    mProgressWheel.setVisibility(View.GONE);
 +                    mImageView.setImageBitmap(thumbnail);
-                     mImageView.setBitmap(thumbnail);
 +                    mImageView.setVisibility(View.VISIBLE);
 +                    mBitmap  = thumbnail;
 +                } else {
 +                // generate new Thumbnail
 +                    if (ThumbnailsCacheManager.cancelPotentialWork(getFile(), mImageView)) {
 +                        final ThumbnailsCacheManager.ThumbnailGenerationTask task =
 +                                new ThumbnailsCacheManager.ThumbnailGenerationTask(
-                                         mImageView, mContainerActivity.getStorageManager(), mAccount, mProgressWheel
-                                 );
++                                        mImageView, mContainerActivity.getStorageManager(),
++                                        mContainerActivity.getStorageManager().getAccount(),
++                                        mProgressWheel);
 +                        if (thumbnail == null) {
 +                            thumbnail = ThumbnailsCacheManager.mDefaultImg;
 +                        }
 +                        final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =
 +                                new ThumbnailsCacheManager.AsyncDrawable(
 +                                        MainApp.getAppContext().getResources(),
 +                                        thumbnail,
 +                                        task
 +                                );
 +                        mImageView.setImageDrawable(asyncDrawable);
 +                        task.execute(getFile(), false);
 +                    }
 +            }
 +            } else {
 +                mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel);
-                 mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()});
++                mLoadBitmapTask.execute(getFile().getStoragePath());
 +            }
          }
      }
      
      
      @Override
      public void onStop() {
-         super.onStop();
+         Log_OC.d(TAG, "onStop starts");
          if (mLoadBitmapTask != null) {
              mLoadBitmapTask.cancel(true);
              mLoadBitmapTask = null;
          }
-         
+         super.onStop();
      }
      
      /**
                  getFile(),
                  mContainerActivity.getStorageManager().getAccount(),
                  mContainerActivity,
-                 getSherlockActivity()
+                 getActivity()
              );
              mf.filter(menu);
          }
                  return true;
              }
              case R.id.action_send_file: {
 -                mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
 -                return true;
 +                if (getFile().isImage() && !getFile().isDown()){
 +                    mContainerActivity.getFileOperationsHelper().sendCachedImage(getFile());
 +                    return true;
 +                } else {
 +                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
 +                    return true;
 +                }
              }
              case R.id.action_sync_file: {
                  mContainerActivity.getFileOperationsHelper().syncFile(getFile());
          if (mBitmap != null) {
              mBitmap.recycle();
              System.gc();
+                 // putting this in onStop() is just the same; the fragment is always destroyed by
+                 // {@link FragmentStatePagerAdapter} when the fragment in swiped further than the
+                 // valid offscreen distance, and onStop() is never called before than that
          }
          super.onDestroy();
      }
  
          /**
           * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
-          * 
-          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          *
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+          * memory before the load finishes.
           */
          private final WeakReference<ImageViewCustom> mImageViewRef;
  
          /**
           * Weak reference to the target {@link TextView} where error messages will be written.
-          * 
-          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          *
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+          * memory before the load finishes.
           */
          private final WeakReference<TextView> mMessageViewRef;
  
          /**
           * Weak reference to the target {@link ProgressBar} shown while the load is in progress.
           * 
-          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from
+          * memory before the load finishes.
           */
          private final WeakReference<ProgressBar> mProgressWheelRef;
  
           * 
           * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
           */
-         public LoadBitmapTask(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);
          @Override
          protected Bitmap doInBackground(String... params) {
              Bitmap result = null;
-             if (params.length != 1) return result;
+             if (params.length != 1) return null;
              String storagePath = params[0];
              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))));
-                 }
+                 int maxDownScale = 3;   // could be a parameter passed to doInBackground(...)
+                 Point screenSize = DisplayUtils.getScreenSize(getActivity());
+                 int minWidth = screenSize.x;
+                 int minHeight = screenSize.y;
+                 for (int i = 0; i < maxDownScale && result == null; i++) {
+                     if (isCancelled()) return null;
+                     try {
+                         result = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth,
+                                 minHeight);
+                         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);
+                             break;
+                         } else {
+                             // Rotate image, obeying exif tag.
+                             result = BitmapUtils.rotateImage(result, storagePath);
+                         }
  
-                 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) {
+                         mErrorMessageId = R.string.common_error_out_memory;
+                         if (i < maxDownScale - 1) {
+                             Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
+                                     " ; scaling down");
+                             minWidth = minWidth / 2;
+                             minHeight = minHeight / 2;
+                         } else {
+                             Log_OC.w(TAG, "Out of memory rendering file " + storagePath +
+                                     " ; failing");
+                         }
+                         if (result != null) {
+                             result.recycle();
+                         }
+                         result = null;
+                     }
                  }
-                 
-             } catch (OutOfMemoryError e) {
-                 Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
  
-                 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 " 
              } else {
                  showErrorMessage();
              }
+             if (result != 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
-             }
-             if (mMessageViewRef != null) {
-                 final TextView messageView = mMessageViewRef.get();
-                 if (messageView != null) {
-                     messageView.setVisibility(View.GONE);
-                 } // else , silently finish, the fragment was destroyed
+             final ImageViewCustom imageView = mImageViewRef.get();
+             if (imageView != null) {
+                 Log_OC.d(TAG, "Showing image with resolution " + result.getWidth() + "x" +
+                         result.getHeight());
+                 imageView.setImageBitmap(result);
+                 imageView.setVisibility(View.VISIBLE);
+                 mBitmap  = result;  // needs to be kept for recycling when not useful
              }
+             final TextView messageView = mMessageViewRef.get();
+             if (messageView != null) {
+                 messageView.setVisibility(View.GONE);
+             } // else , silently finish, the fragment was destroyed
          }
          
          private void showErrorMessage() {
-             if (mImageViewRef != null) {
-                 final ImageView imageView = mImageViewRef.get();
-                 if (imageView != null) {
-                     // shows the default error icon
-                     imageView.setVisibility(View.VISIBLE);
-                 } // else , silently finish, the fragment was destroyed
-             }
-             if (mMessageViewRef != null) {
-                 final TextView messageView = mMessageViewRef.get();
-                 if (messageView != null) {
-                     messageView.setText(mErrorMessageId);
-                     messageView.setVisibility(View.VISIBLE);
-                 } // else , silently finish, the fragment was destroyed
-             }
+             final ImageView imageView = mImageViewRef.get();
+             if (imageView != null) {
+                 // shows the default error icon
+                 imageView.setVisibility(View.VISIBLE);
+             } // else , silently finish, the fragment was destroyed
+             final TextView messageView = mMessageViewRef.get();
+             if (messageView != null) {
+                 messageView.setText(mErrorMessageId);
+                 messageView.setVisibility(View.VISIBLE);
+             } // else , silently finish, the fragment was destroyed
          }
          
          private void hideProgressWheel() {
-             if (mProgressWheelRef != null) {
-                 final ProgressBar progressWheel = mProgressWheelRef.get();
-                 if (progressWheel != null) {
-                     progressWheel.setVisibility(View.GONE);
-                 }
+             final ProgressBar progressWheel = mProgressWheelRef.get();
+             if (progressWheel != null) {
+                 progressWheel.setVisibility(View.GONE);
              }
          }
          
      }
  
      /**
-      * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
+      * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment}
+      * to be previewed.
       * 
       * @param file      File to test if can be previewed.
       * @return          'True' if the file can be handled by the fragment.
          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);
-     }
  }
@@@ -19,8 -19,6 +19,6 @@@
   */
  package com.owncloud.android.ui.preview;
  
- import java.util.Collections;
- import java.util.Comparator;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
@@@ -29,7 -27,6 +27,7 @@@ import java.util.Set
  import java.util.Vector;
  
  import android.accounts.Account;
 +import android.graphics.Bitmap;
  import android.support.v4.app.Fragment;
  import android.support.v4.app.FragmentManager;
  import android.support.v4.app.FragmentStatePagerAdapter;
@@@ -37,8 -34,6 +35,8 @@@ import android.view.ViewGroup
  
  import com.owncloud.android.datamodel.FileDataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
 +import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 +import com.owncloud.android.ui.adapter.FileListListAdapter;
  import com.owncloud.android.ui.fragment.FileFragment;
  import com.owncloud.android.utils.FileStorageUtils;
  
@@@ -60,11 -55,14 +58,14 @@@ public class PreviewImagePagerAdapter e
      /**
       * Constructor.
       * 
-      * @param fragmentManager   {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter. 
+      * @param fragmentManager   {@link FragmentManager} instance that will handle
+      *                          the {@link Fragment}s provided by the adapter.
       * @param parentFolder      Folder where images will be searched for.
       * @param storageManager    Bridge to database.
       */
-     public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, FileDataStorageManager storageManager) {
+     public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder,
+                                     Account account, FileDataStorageManager storageManager /*,
+                                     boolean onlyOnDevice*/) {
          super(fragmentManager);
          
          if (fragmentManager == null) {
@@@ -79,7 -77,8 +80,8 @@@
  
          mAccount = account;
          mStorageManager = storageManager;
-         mImageFiles = mStorageManager.getFolderImages(parentFolder); 
+         // TODO Enable when "On Device" is recovered ?
+         mImageFiles = mStorageManager.getFolderImages(parentFolder/*, false*/);
          
          mImageFiles = FileStorageUtils.sortFolder(mImageFiles);
          
          OCFile file = mImageFiles.get(i);
          Fragment fragment = null;
          if (file.isDown()) {
-             fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)), false);
+             fragment = PreviewImageFragment.newInstance(file,
 -                    mObsoletePositions.contains(Integer.valueOf(i)));
++                    mObsoletePositions.contains(Integer.valueOf(i)), false);
+             
          } else if (mDownloadErrors.contains(Integer.valueOf(i))) {
-             fragment = new FileDownloadFragment(file, mAccount, true);
+             fragment = FileDownloadFragment.newInstance(file, mAccount, true);
              ((FileDownloadFragment)fragment).setError(true);
              mDownloadErrors.remove(Integer.valueOf(i));
 -            
          } else {
-          fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)), true);
 -            fragment = FileDownloadFragment.newInstance(
 -                    file, mAccount, mObsoletePositions.contains(Integer.valueOf(i))
 -            );
++            fragment = PreviewImageFragment.newInstance(file,
++                    mObsoletePositions.contains(Integer.valueOf(i)), true);
          }
          mObsoletePositions.remove(Integer.valueOf(i));
          return fragment;