Merge remote-tracking branch 'remotes/upstream/master' into resizedImagesMaster
authortobiasKaminsky <tobias@kaminsky.me>
Thu, 5 Nov 2015 21:04:57 +0000 (22:04 +0100)
committertobiasKaminsky <tobias@kaminsky.me>
Thu, 5 Nov 2015 21:04:57 +0000 (22:04 +0100)
1  2 
AndroidManifest.xml
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

diff --combined AndroidManifest.xml
@@@ -1,5 -1,5 +1,5 @@@
  <?xml version="1.0" encoding="utf-8"?>
- <!-- 
+ <!--
    ownCloud Android client application
  
    Copyright (C) 2012  Bartek Przybylski
  
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-  -->
- <manifest package="com.owncloud.android"
-     android:versionCode="10700100"
-     android:versionName="1.7.1" xmlns:android="http://schemas.android.com/apk/res/android">
+ -->
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="com.owncloud.android"
+     android:versionCode="10800000"
+     android:versionName="1.8.0" >
+     <uses-sdk
+         android:minSdkVersion="14"
+         android:targetSdkVersion="22" />
  
      <uses-permission android:name="android.permission.GET_ACCOUNTS" />
      <uses-permission android:name="android.permission.USE_CREDENTIALS" />
      <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
      <uses-permission android:name="android.permission.BROADCAST_STICKY" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-     <uses-permission android:name="android.permission.WAKE_LOCK"/>
-     
-     <uses-sdk
-         android:minSdkVersion="8"
-         android:targetSdkVersion="19" />
+     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+     <uses-permission android:name="android.permission.WAKE_LOCK" />
+     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  
-     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
-     </uses-permission>
+     <android:uses-permission android:name="android.permission.READ_PHONE_STATE" />
+     <android:uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  
      <application
          android:name=".MainApp"
          android:icon="@drawable/icon"
          android:label="@string/app_name"
-         android:theme="@style/Theme.ownCloud"
+         android:theme="@style/Theme.ownCloud" >
          <activity
              android:name=".ui.activity.FileDisplayActivity"
-             android:label="@string/app_name"
-             >
+             android:label="@string/app_name" >
              <intent-filter>
                  <action android:name="android.intent.action.MAIN" />
                  <category android:name="android.intent.category.LAUNCHER" />
              </intent-filter>
          </activity>
-         <activity android:name=".ui.activity.UploadFilesActivity">
-         </activity>
+         <activity android:name=".ui.activity.UploadFilesActivity" />
          <activity android:name=".ui.activity.Uploader" >
              <intent-filter>
-                 <action android:name="android.intent.action.SEND" >
-                 </action>
+                 <action android:name="android.intent.action.SEND" />
  
-                 <category android:name="android.intent.category.DEFAULT" >
-                 </category>
+                 <category android:name="android.intent.category.DEFAULT" />
  
-                 <data android:mimeType="*/*" >
-                 </data>
+                 <data android:mimeType="*/*" />
              </intent-filter>
              <intent-filter>
-                 <action android:name="android.intent.action.SEND_MULTIPLE" >
-                 </action>
+                 <action android:name="android.intent.action.SEND_MULTIPLE" />
  
-                 <category android:name="android.intent.category.DEFAULT" >
-                 </category>
-                 <data android:mimeType="*/*" >
-                 </data>
+                 <category android:name="android.intent.category.DEFAULT" />
  
-                       </intent-filter>
+                 <data android:mimeType="*/*" />
+             </intent-filter>
          </activity>
          <activity
              android:name=".ui.activity.Preferences"
              android:theme="@style/Theme.ownCloud" >
          </activity>
-         <activity     
-             android:name=".ui.preview.PreviewImageActivity" 
-             />
-                       
-         <activity     
+         <activity
+             android:name=".ui.preview.PreviewImageActivity"
+             android:theme="@style/Theme.ownCloud.Overlay" />
+         <activity
              android:name=".ui.preview.PreviewVideoActivity"
-                       android:label="@string/app_name"
-                       android:theme="@style/Theme.ownCloud.Fullscreen" 
-                       >
-               </activity>        
+             android:label="@string/app_name"
+             android:theme="@style/Theme.ownCloud.Fullscreen" />
  
          <service
              android:name=".authentication.AccountAuthenticatorService"
-             android:exported="true">
-             <intent-filter  android:priority="100">
+             android:exported="true" >
+             <intent-filter android:priority="100" >
                  <action android:name="android.accounts.AccountAuthenticator" />
              </intent-filter>
  
          </service>
          <service
              android:name=".syncadapter.FileSyncService"
-             android:exported="true" 
-             >
+             android:exported="true" >
              <intent-filter>
                  <action android:name="android.content.SyncAdapter" />
              </intent-filter>
              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>
+             android:syncable="true" />
+         <provider
+             android:name=".providers.UsersAndGroupsSearchProvider"
+             android:authorities="com.owncloud.android.providers.UsersAndGroupsSearchProvider"
+             android:enabled="true"
+             android:exported="false"
+             android:label="@string/search_users_and_groups_hint" />
  
 +        <provider
 +            android:name=".ui.adapter.DiskLruImageCacheFileProvider"
 +            android:authorities="com.owncloud.imageCache.provider"
 +            android:exported="true">
 +        </provider>
 +
          <activity
              android:name=".authentication.AuthenticatorActivity"
              android:exported="true"
-             android:theme="@style/Theme.ownCloud.noActionBar" 
-             android:launchMode="singleTask">
+             android:launchMode="singleTask"
+             android:theme="@style/Theme.ownCloud.noActionBar" >
              <intent-filter>
                  <action android:name="android.intent.action.VIEW" />
                  <category android:name="android.intent.category.DEFAULT" />
                  <category android:name="android.intent.category.BROWSABLE" />
                  <data android:scheme="@string/oauth2_redirect_scheme" />
              </intent-filter>
              <intent-filter>
                  <action android:name="com.owncloud.android.workaround.accounts.CREATE" />
                  <category android:name="android.intent.category.DEFAULT" />
              </intent-filter>
          </activity>
          <service android:name=".files.services.FileDownloader" />
          <service android:name=".files.services.FileUploader" />
          <service android:name=".media.MediaService" />
-         
          <activity android:name=".ui.activity.PassCodeActivity" />
-         <activity android:name=".ui.activity.ConflictsResolveActivity"/>
-         <activity android:name=".ui.activity.GenericExplanationActivity"/>
-         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
-         
-         <activity android:name=".ui.activity.LogHistoryActivity"/>
-         
-         <receiver android:name=".files.InstantUploadBroadcastReceiver">
+         <activity android:name=".ui.activity.ConflictsResolveActivity" />
+         <activity android:name=".ui.activity.GenericExplanationActivity" />
+         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity" />
+         <activity android:name=".ui.activity.LogHistoryActivity" />
+         <receiver android:name=".files.InstantUploadBroadcastReceiver" >
              <intent-filter>
                  <!-- unofficially supported by many Android phones but not by HTC devices: -->
                  <action android:name="com.android.camera.NEW_PICTURE" />
-                 <!-- officially supported since Android 4.0 (SDK 14, works even for HTC devices): --> 
+                 <!-- officially supported since Android 4.0 (SDK 14, works even for HTC devices): -->
                  <action android:name="android.hardware.action.NEW_PICTURE" />
                  <data android:mimeType="image/*" />
              </intent-filter>
              <intent-filter>
                  <action android:name="android.hardware.action.NEW_VIDEO" />
                  <data android:mimeType="video/*" />
              </intent-filter>
              <intent-filter>
-                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
              </intent-filter>
          </receiver>
-         <receiver android:name=".files.BootupBroadcastReceiver">
+         <receiver android:name=".files.BootupBroadcastReceiver" >
              <intent-filter>
-                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
+                 <action android:name="android.intent.action.BOOT_COMPLETED" />
              </intent-filter>
          </receiver>
-         <service android:name=".services.observer.FileObserverService"/>
-         
-               <activity
-                       android:name=".ui.activity.CopyToClipboardActivity"
-                       android:label="@string/copy_link"
-                       android:icon="@drawable/copy_link"/>
-         <activity 
-                       android:name=".ui.activity.FolderPickerActivity"
-                       android:label="@string/app_name"/>
-         <activity 
-                       android:name=".ui.activity.UploadPathActivity"
-                       android:label="@string/app_name"/>
-         
+         <service android:name=".services.observer.FileObserverService" />
+         <activity
+             android:name=".ui.activity.CopyToClipboardActivity"
+             android:icon="@drawable/copy_link"
+             android:label="@string/copy_link" />
+         <activity
+             android:name=".ui.activity.FolderPickerActivity"
+             android:label="@string/app_name" />
+         <activity
+             android:name=".ui.activity.UploadPathActivity"
+             android:label="@string/app_name" />
+         <activity
+             android:name=".ui.activity.ShareActivity"
+             android:label="@string/share_dialog_title"
+             android:theme="@style/Theme.ownCloud.Dialog"
+             android:launchMode="singleTop"
+             android:windowSoftInputMode="adjustResize" >
+             <intent-filter>
+                 <action android:name="android.intent.action.SEARCH" />
+             </intent-filter>
+             <meta-data android:name="android.app.searchable"
+                        android:resource="@xml/users_and_groups_searchable"/>
+         </activity>
      </application>
  
  </manifest>
@@@ -29,23 -29,18 +29,25 @@@ import org.apache.commons.httpclient.Ht
  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.Canvas;
  import android.graphics.drawable.BitmapDrawable;
+ import android.graphics.drawable.ColorDrawable;
  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;
@@@ -79,8 -74,8 +81,8 @@@ public class ThumbnailsCacheManager 
  
      public static Bitmap mDefaultImg = 
              BitmapFactory.decodeResource(
-                     MainApp.getAppContext().getResources(), 
-                     DisplayUtils.getFileTypeIconId("image/png", "default.png")
+                     MainApp.getAppContext().getResources(),
+                     R.drawable.file_image
              );
  
      
  
      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);
                  }
  
                  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){
          }
  
          protected void onPostExecute(Bitmap bitmap){
-             if (isCancelled()) {
-                 bitmap = null;
-             }
              if (bitmap != null) {
                  final ImageView imageView = mImageViewReference.get();
                  final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
                          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);
              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 temp = BitmapUtils.decodeSampledBitmapFromFile(
 -                            file.getStoragePath(), px, px);
 -                    Bitmap bitmap = ThumbnailUtils.extractThumbnail(temp, px, px);
 +                    Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(
 +                            file.getStoragePath(), pxW, pxH);
  
                      if (bitmap != null) {
 -                            bitmap = handlePNG(bitmap, px);
+                         // Handle PNG
+                         if (file.getMimetype().equalsIgnoreCase("image/png")) {
 -                        thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), px);
++                            bitmap = handlePNG(bitmap, pxW);
+                         }
 +                        thumbnail = addThumbnailToCache(imageKey, bitmap, file.getStoragePath(), pxW, pxH);
  
                          file.setNeedsUpdateThumbnail(false);
                          mStorageManager.saveFile(file);
                              try {
                                  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);
                                  int status = mClient.executeMethod(get);
                                  if (status == HttpStatus.SC_OK) {
- //                                    byte[] bytes = get.getResponseBody();
- //                                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
- //                                            bytes.length);
                                      InputStream inputStream = get.getResponseBodyAsStream();
                                      Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
 -                                    thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px);
 +                                    thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
 +                                    byte[] bytes = get.getResponseBody();
 +
 +                                    if (mIsThumbnail) {
 +                                        thumbnail = ThumbnailUtils.extractThumbnail(bitmap, pxW, pxH);
 +                                    } else {
 +                                        thumbnail = bitmap;
 +                                    }
  
 -                                        thumbnail = handlePNG(thumbnail, px);
+                                     // Handle PNG
+                                     if (file.getMimetype().equalsIgnoreCase("image/png")) {
++                                        thumbnail = handlePNG(thumbnail, pxW);
+                                     }
                                      // Add thumbnail to cache
                                      if (thumbnail != null) {
                                          addBitmapToCache(imageKey, thumbnail);
  
          }
  
 -        private Bitmap doFileInBackground() {
+         private Bitmap handlePNG(Bitmap bitmap, int px){
+             Bitmap resultBitmap = Bitmap.createBitmap(px,
+                     px,
+                     Bitmap.Config.ARGB_8888);
+             Canvas c = new Canvas(resultBitmap);
+             c.drawColor(MainApp.getAppContext().getResources().
+                     getColor(R.color.background_color));
+             c.drawBitmap(bitmap, 0, 0, null);
+             return resultBitmap;
+         }
 +        private Bitmap doFileInBackground(Boolean mIsThumbnail) {
              File file = (File)mFile;
  
 -            final String imageKey = String.valueOf(file.hashCode());
 +            // distinguish between thumbnail and resized image
 +            String temp = String.valueOf(file.hashCode());
 +            if (mIsThumbnail){
 +                temp = "t" + temp;
 +            } else {
 +                temp = "r" + temp;
 +            }
 +
 +            final String imageKey = temp;
  
              // Check disk cache in background thread
              Bitmap 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;
              if (bitmapData == null || bitmapData != file) {
                  // Cancel previous task
                  bitmapWorkerTask.cancel(true);
+                 Log_OC.v(TAG, "Cancelled generation of thumbnail for a reused imageView");
              } else {
                  // The same work is already in progress
                  return false;
  
  package com.owncloud.android.files;
  
- import org.apache.http.protocol.HTTP;
  import android.accounts.Account;
+ import android.content.ActivityNotFoundException;
+ import android.content.Context;
  import android.content.Intent;
 +import android.graphics.Bitmap;
+ import android.content.pm.PackageManager;
+ import android.content.pm.ResolveInfo;
  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.network.WebdavUtils;
  import com.owncloud.android.lib.common.utils.Log_OC;
+ import com.owncloud.android.lib.resources.shares.ShareType;
  import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  import com.owncloud.android.services.OperationsService;
+ import com.owncloud.android.services.observer.FileObserverService;
  import com.owncloud.android.ui.activity.FileActivity;
 +import com.owncloud.android.ui.adapter.DiskLruImageCacheFileProvider;
+ import com.owncloud.android.ui.activity.ShareActivity;
  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;
 +
+ import org.apache.http.protocol.HTTP;
+ import java.util.List;
  /**
   *
   */
  public class FileOperationsHelper {
  
      private static final String TAG = FileOperationsHelper.class.getName();
-     
-     private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG"; 
+     private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
  
      protected FileActivity mFileActivity = null;
  
      /// Identifier of operation in progress which result shouldn't be lost 
      private long mWaitingForOpId = Long.MAX_VALUE;
-     
      public FileOperationsHelper(FileActivity fileActivity) {
          mFileActivity = fileActivity;
      }
          if (file != null) {
              String storagePath = file.getStoragePath();
              String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-             
              Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
-             intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
+             intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath),
+                     file.getMimetype());
              intentForSavedMimeType.setFlags(
                      Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
              );
                  );
                  if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
                      intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
-                     intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
+                     intentForGuessedMimeType.
+                             setDataAndType(Uri.parse("file://"+ encodedStoragePath),
+                                     guessedMimeType);
                      intentForGuessedMimeType.setFlags(
-                             Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                             Intent.FLAG_GRANT_READ_URI_PERMISSION |
+                                     Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                      );
                  }
              }
-             
-             Intent chooserIntent;
+             Intent openFileWithIntent;
              if (intentForGuessedMimeType != null) {
-                 chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
+                 openFileWithIntent = intentForGuessedMimeType;
              } else {
-                 chooserIntent = Intent.createChooser(intentForSavedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
+                 openFileWithIntent = intentForSavedMimeType;
              }
-             
-             mFileActivity.startActivity(chooserIntent);
-             
+             List<ResolveInfo> launchables = mFileActivity.getPackageManager().
+                     queryIntentActivities(openFileWithIntent, PackageManager.GET_INTENT_FILTERS);
+             if(launchables != null && launchables.size() > 0) {
+                 try {
+                     mFileActivity.startActivity(
+                             Intent.createChooser(
+                                     openFileWithIntent, mFileActivity.getString(R.string.actionbar_open_with)
+                             )
+                     );
+                 } catch (ActivityNotFoundException anfe) {
+                     showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
+                 }
+             } else {
+                 showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
+             }
          } else {
              Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
          }
      }
-     
-     
+     /**
+      * Displays a toast stating that no application could be found to open the file.
+      *
+      * @param context the context to be able to show a toast.
+      */
+     private void showNoAppForFileTypeToast(Context context) {
+         Toast.makeText(context,
+                 R.string.file_list_no_app_for_file_type, Toast.LENGTH_SHORT)
+                 .show();
+     }
      public void shareFileWithLink(OCFile file) {
-         
          if (isSharedSupported()) {
              if (file != null) {
                  String link = "https://fake.url";
                  Intent intent = createShareWithLinkIntent(link);
-                 String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
-                 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
+                 String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
+                 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent,
+                         packagesToExclude, file);
                  chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
-                 
              } else {
                  Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
              }
-             
          } else {
              // Show a Message
              Toast t = Toast.makeText(
-                     mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG
+                     mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api),
+                     Toast.LENGTH_LONG
              );
              t.show();
          }
      }
-     
-     
      public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
          
          if (file != null) {
-             mFileActivity.showLoadingDialog();
-             
+             mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                     getString(R.string.wait_a_moment));
              Intent service = new Intent(mFileActivity, OperationsService.class);
-             service.setAction(OperationsService.ACTION_CREATE_SHARE);
+             service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
              service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
              service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
              service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
              Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
          }
      }
-     
-     
      private Intent createShareWithLinkIntent(String link) {
          Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
          intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
          intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
-         return intentToShareLink; 
+         return intentToShareLink;
      }
-     
-     
      /**
-      *  @return 'True' if the server supports the Share API
+      * Helper method to share a file with a know sharee. Starts a request to do it in {@link OperationsService}
+      *
+      * @param file          The file to share.
+      * @param shareeName    Name (user name or group name) of the target sharee.
+      * @param shareType     The share type determines the sharee type.
+      */
+     public void shareFileWithSharee(OCFile file, String shareeName, ShareType shareType) {
+         if (file != null) {
+             // TODO check capability?
+             mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                     getString(R.string.wait_a_moment));
+             Intent service = new Intent(mFileActivity, OperationsService.class);
+             service.setAction(OperationsService.ACTION_CREATE_SHARE_WITH_SHAREE);
+             service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+             service.putExtra(OperationsService.EXTRA_SHARE_WITH, shareeName);
+             service.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
+             mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+         } else {
+             Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
+         }
+     }
+     /**
+      * @return 'True' if the server supports the Share API
       */
      public boolean isSharedSupported() {
          if (mFileActivity.getAccount() != null) {
          }
          return false;
      }
-     
-     
      public void unshareFileWithLink(OCFile file) {
-         
+         // Unshare the file: Create the intent
+         Intent unshareService = new Intent(mFileActivity, OperationsService.class);
+         unshareService.setAction(OperationsService.ACTION_UNSHARE);
+         unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+         unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+         unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, ShareType.PUBLIC_LINK);
+         unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, "");
+         unshareFile(unshareService);
+     }
+     public void unshareFileWithUserOrGroup(OCFile file, ShareType shareType, String userOrGroup){
+         // Unshare the file: Create the intent
+         Intent unshareService = new Intent(mFileActivity, OperationsService.class);
+         unshareService.setAction(OperationsService.ACTION_UNSHARE);
+         unshareService.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+         unshareService.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+         unshareService.putExtra(OperationsService.EXTRA_SHARE_TYPE, shareType);
+         unshareService.putExtra(OperationsService.EXTRA_SHARE_WITH, userOrGroup);
+         unshareFile(unshareService);
+     }
+     private void unshareFile(Intent unshareService){
          if (isSharedSupported()) {
              // Unshare the file
-             Intent service = new Intent(mFileActivity, OperationsService.class);
-             service.setAction(OperationsService.ACTION_UNSHARE);
-             service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
-             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
-             mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
-             
-             mFileActivity.showLoadingDialog();
-             
+             mWaitingForOpId = mFileActivity.getOperationsServiceBinder().
+                     queueNewOperation(unshareService);
+             mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                     getString(R.string.wait_a_moment));
          } 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();
-             
          }
      }
-     
+     /**
+      * Show an instance of {@link ShareType} for sharing or unsharing the {@OCFile} received as parameter.
+      *
+      * @param file  File to share or unshare.
+      */
+     public void showShareFile(OCFile file){
+         Intent intent = new Intent(mFileActivity, ShareActivity.class);
+         intent.putExtra(mFileActivity.EXTRA_FILE, file);
+         intent.putExtra(mFileActivity.EXTRA_ACCOUNT, mFileActivity.getAccount());
+         mFileActivity.startActivity(intent);
+     }
+     /**
+      * @return 'True' if the server supports the Search Users API
+      */
+     public boolean isSearchUsersSupportedSupported() {
+         if (mFileActivity.getAccount() != null) {
+             OwnCloudVersion serverVersion = AccountUtils.getServerVersion(mFileActivity.getAccount());
+             return (serverVersion != null && serverVersion.isSearchUsersSupported());
+         }
+         return false;
+     }
      public void sendDownloadedFile(OCFile file) {
          if (file != null) {
+             String storagePath = file.getStoragePath();
+             String encodedStoragePath = WebdavUtils.encodePath(storagePath);
              Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
              // set MimeType
              sendIntent.setType(file.getMimetype());
-             sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + file.getStoragePath()));
+             sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + encodedStoragePath));
              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);
+             String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
+             DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent,
+                     packagesToExclude, file);
              chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
  
          } else {
          }
      }
  
 +    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");
 +        }
 +    }
 +    
 +    
++
+     /**
+      * Request the synchronization of a file or folder with the OC server, including its contents.
+      *
+      * @param file          The file or folder to synchronize
+      */
      public void syncFile(OCFile file) {
-         
          if (!file.isFolder()){
              Intent intent = new Intent(mFileActivity, OperationsService.class);
              intent.setAction(OperationsService.ACTION_SYNC_FILE);
              intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
              intent.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
              mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(intent);
-             // mFileActivity.showLoadingDialog();
+             mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                     getString(R.string.wait_a_moment));
              
          } else {
              Intent intent = new Intent(mFileActivity, OperationsService.class);
              intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
              intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
              mFileActivity.startService(intent);
+         }
+     }
+     public void toggleFavorite(OCFile file, boolean isFavorite) {
+         file.setFavorite(isFavorite);
+         mFileActivity.getStorageManager().saveFile(file);
+         /// register the OCFile instance in the observer service to monitor local updates
+         Intent observedFileIntent = FileObserverService.makeObservedFileIntent(
+                 mFileActivity,
+                 file,
+                 mFileActivity.getAccount(),
+                 isFavorite);
+         mFileActivity.startService(observedFileIntent);
+         /// immediate content synchronization
+         if (file.isFavorite()) {
+             syncFile(file);
          }
      }
      
          service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
          mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
          
-         mFileActivity.showLoadingDialog();
+         mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                 getString(R.string.wait_a_moment));
      }
  
  
          service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
          mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
          
-         mFileActivity.showLoadingDialog();
+         mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                 getString(R.string.wait_a_moment));
      }
-     
-     
      public void createFolder(String remotePath, boolean createFullPath) {
          // Create Folder
          Intent service = new Intent(mFileActivity, OperationsService.class);
          service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
          mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
          
-         mFileActivity.showLoadingDialog();
+         mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                 getString(R.string.wait_a_moment));
      }
  
      /**
      public void cancelTransference(OCFile file) {
          Account account = mFileActivity.getAccount();
          if (file.isFolder()) {
-             OperationsService.OperationsServiceBinder opsBinder = mFileActivity.getOperationsServiceBinder();
+             OperationsService.OperationsServiceBinder opsBinder =
+                     mFileActivity.getOperationsServiceBinder();
              if (opsBinder != null) {
                  opsBinder.cancel(account, file);
              }
  
          // for both files and folders
          FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
-         FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
          if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
              downloaderBinder.cancel(account, file);
-             // TODO - review why is this here, and solve in a better way
-             // Remove etag for parent, if file is a keep_in_sync
-             if (file.keepInSync()) {
-                 OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
-                 parent.setEtag("");
-                 mFileActivity.getStorageManager().saveFile(parent);
-             }
-         } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
+         }
+         FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
+         if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
              uploaderBinder.cancel(account, file);
          }
      }
  
      /**
       * Start move file operation
-      * @param newfile           File where it is going to be moved
-      * @param currentFile       File with the previous info
+      *
+      * @param newfile     File where it is going to be moved
+      * @param currentFile File with the previous info
       */
      public void moveFile(OCFile newfile, OCFile currentFile) {
          // Move files
          service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
          mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
  
-         mFileActivity.showLoadingDialog();
+         mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                 getString(R.string.wait_a_moment));
      }
  
+     /**
+      * Start copy file operation
+      *
+      * @param newfile     File where it is going to be moved
+      * @param currentFile File with the previous info
+      */
+     public void copyFile(OCFile newfile, OCFile currentFile) {
+         // Copy files
+         Intent service = new Intent(mFileActivity, OperationsService.class);
+         service.setAction(OperationsService.ACTION_COPY_FILE);
+         service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
+         service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
+         service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+         mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
+         mFileActivity.showLoadingDialog(mFileActivity.getApplicationContext().
+                 getString(R.string.wait_a_moment));
+     }
  
      public long getOpIdWaitingFor() {
          return mWaitingForOpId;
      public void setOpIdWaitingFor(long waitingForOpId) {
          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());
+             OwnCloudVersion serverVersion =
+                     AccountUtils.getServerVersion(mFileActivity.getAccount());
              return (serverVersion != null && serverVersion.isVersionWithForbiddenCharacters());
          }
          return false;
@@@ -4,6 -4,7 +4,7 @@@
   *   @author Bartek Przybylski\r
   *   @author Tobias Kaminsky\r
   *   @author David A. Velasco\r
+  *   @author masensio\r
   *   Copyright (C) 2011  Bartek Przybylski\r
   *   Copyright (C) 2015 ownCloud Inc.\r
   *\r
@@@ -54,6 -55,7 +55,7 @@@ import com.owncloud.android.services.Op
  import com.owncloud.android.ui.activity.ComponentsGetter;\r
  import com.owncloud.android.utils.DisplayUtils;\r
  import com.owncloud.android.utils.FileStorageUtils;\r
+ import com.owncloud.android.utils.MimetypeIconUtil;\r
  \r
  \r
  /**\r
@@@ -61,7 -63,6 +63,6 @@@
   * instance.\r
   */\r
  public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
-     private final static String PERMISSION_SHARED_WITH_ME = "S";\r
  \r
      private Context mContext;\r
      private OCFile mFile = null;\r
                  case GRID_IMAGE:\r
                      // sharedIcon\r
                      ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);\r
-                     if (file.isShareByLink()) {\r
+                     if (file.isSharedViaLink()) {\r
+                         sharedIconV.setImageResource(R.drawable.shared_via_link);\r
+                         sharedIconV.setVisibility(View.VISIBLE);\r
+                         sharedIconV.bringToFront();\r
+                     } else if (file.isSharedWithSharee() || file.isSharedWithMe() ) {\r
+                         sharedIconV.setImageResource(R.drawable.shared_via_users);\r
                          sharedIconV.setVisibility(View.VISIBLE);\r
                          sharedIconV.bringToFront();\r
                      } else {\r
                          sharedIconV.setVisibility(View.GONE);\r
                      }\r
  \r
+                     /*ImageView sharedWithMeIcon = (ImageView) view.findViewById(R.id.sharedWithMeIcon);\r
+                     sharedWithMeIcon.bringToFront();*/\r
\r
                      // local state\r
                      ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);\r
                      localStateView.bringToFront();\r
                              mTransferServiceGetter.getFileDownloaderBinder();\r
                      FileUploaderBinder uploaderBinder =\r
                              mTransferServiceGetter.getFileUploaderBinder();\r
-                     boolean downloading = (downloaderBinder != null &&\r
-                             downloaderBinder.isDownloading(mAccount, file));\r
                      OperationsServiceBinder opsBinder =\r
                              mTransferServiceGetter.getOperationsServiceBinder();\r
-                     downloading |= (opsBinder != null &&\r
-                             opsBinder.isSynchronizing(mAccount, file.getRemotePath()));\r
-                     if (downloading) {\r
-                         localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
\r
+                     localStateView.setVisibility(View.INVISIBLE);   // default first\r
\r
+                     if ( //synchronizing\r
+                                 opsBinder != null &&\r
+                                 opsBinder.isSynchronizing(mAccount, file.getRemotePath())\r
+                             ) {\r
+                         localStateView.setImageResource(R.drawable.synchronizing_file_indicator);\r
                          localStateView.setVisibility(View.VISIBLE);\r
-                     } else if (uploaderBinder != null &&\r
-                             uploaderBinder.isUploading(mAccount, file)) {\r
-                         localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
\r
+                     } else if ( // downloading\r
+                                 downloaderBinder != null &&\r
+                                 downloaderBinder.isDownloading(mAccount, file)\r
+                             ) {\r
+                         localStateView.setImageResource(\r
+                                 file.isFolder() ?\r
+                                         R.drawable.synchronizing_file_indicator :\r
+                                         R.drawable.downloading_file_indicator\r
+                         );\r
                          localStateView.setVisibility(View.VISIBLE);\r
\r
+                     } else if ( //uploading\r
+                                 uploaderBinder != null &&\r
+                                 uploaderBinder.isUploading(mAccount, file)\r
+                             ) {\r
+                         localStateView.setImageResource(\r
+                                 file.isFolder() ?\r
+                                         R.drawable.synchronizing_file_indicator :\r
+                                         R.drawable.uploading_file_indicator\r
+                         );\r
+                         localStateView.setVisibility(View.VISIBLE);\r
\r
+                     } else if (file.getEtagInConflict() != null) {   // conflict\r
+                         localStateView.setImageResource(R.drawable.conflict_file_indicator);\r
+                         localStateView.setVisibility(View.VISIBLE);\r
\r
                      } else if (file.isDown()) {\r
                          localStateView.setImageResource(R.drawable.local_file_indicator);\r
                          localStateView.setVisibility(View.VISIBLE);\r
-                     } else {\r
-                         localStateView.setVisibility(View.INVISIBLE);\r
-                     }\r
\r
-                     // share with me icon\r
-                     if (!file.isFolder()) {\r
-                         ImageView sharedWithMeIconV = (ImageView)\r
-                                 view.findViewById(R.id.sharedWithMeIcon);\r
-                         sharedWithMeIconV.bringToFront();\r
-                         if (checkIfFileIsSharedWithMe(file)) {\r
-                             sharedWithMeIconV.setVisibility(View.VISIBLE);\r
-                         } else {\r
-                             sharedWithMeIconV.setVisibility(View.GONE);\r
-                         }\r
                      }\r
  \r
                      break;\r
              \r
              // this if-else is needed even though favorite icon is visible by default\r
              // because android reuses views in listview\r
-             if (!file.keepInSync()) {\r
+             if (!file.isFavorite()) {\r
                  view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);\r
              } else {\r
                  view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE);\r
                  if (file.isImage() && file.getRemoteId() != null){\r
                      // Thumbnail in Cache?\r
                      Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(\r
 -                            String.valueOf(file.getRemoteId())\r
 -                            );\r
 +                            "t" + String.valueOf(file.getRemoteId()));\r
                      if (thumbnail != null && !file.needsUpdateThumbnail()){\r
                          fileIcon.setImageBitmap(thumbnail);\r
                      } else {\r
                                      task\r
                                      );\r
                              fileIcon.setImageDrawable(asyncDrawable);\r
 -                            task.execute(file);\r
 +                            task.execute(file, true);\r
                          }\r
                      }\r
\r
+                     if (file.getMimetype().equalsIgnoreCase("image/png")) {\r
+                         fileIcon.setBackgroundColor(mContext.getResources()\r
+                                 .getColor(R.color.background_color));\r
+                     }\r
\r
\r
                  } else {\r
-                     fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(file.getMimetype(),\r
+                     fileIcon.setImageResource(MimetypeIconUtil.getFileTypeIconId(file.getMimetype(),\r
                              file.getFileName()));\r
                  }\r
  \r
              } else {\r
                  // Folder\r
-                 if (checkIfFileIsSharedWithMe(file)) {\r
-                     fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
-                 } else if (file.isShareByLink()) {\r
-                     // If folder is sharedByLink, icon folder must be changed to\r
-                     // folder-public one\r
-                     fileIcon.setImageResource(R.drawable.folder_public);\r
-                 } else {\r
-                     fileIcon.setImageResource(\r
-                             DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName())\r
-                     );\r
-                 }\r
+                 fileIcon.setImageResource(\r
+                         MimetypeIconUtil.getFolderTypeIconId(\r
+                                 file.isSharedWithMe() || file.isSharedWithSharee(),\r
+                                 file.isSharedViaLink()\r
+                         )\r
+                 );\r
              }\r
          }\r
  \r
          return view;\r
      }\r
  \r
-     /**\r
-      * Local Folder size in human readable format\r
-      * \r
-      * @param path\r
-      *            String\r
-      * @return Size in human readable format\r
-      */\r
-     private String getFolderSizeHuman(String path) {\r
\r
-         File dir = new File(path);\r
\r
-         if (dir.exists()) {\r
-             long bytes = FileStorageUtils.getFolderSize(dir);\r
-             return DisplayUtils.bytesToHumanReadable(bytes);\r
-         }\r
\r
-         return "0 B";\r
-     }\r
\r
-     /**\r
-      * Local Folder size\r
-      * @param dir File\r
-      * @return Size in bytes\r
-      */\r
-     private long getFolderSize(File dir) {\r
-         if (dir.exists()) {\r
-             long result = 0;\r
-             File[] fileList = dir.listFiles();\r
-             for(int i = 0; i < fileList.length; i++) {\r
-                 if(fileList[i].isDirectory()) {\r
-                     result += getFolderSize(fileList[i]);\r
-                 } else {\r
-                     result += fileList[i].length();\r
-                 }\r
-             }\r
-             return result;\r
-         }\r
-         return 0;\r
-     } \r
\r
      @Override\r
      public int getViewTypeCount() {\r
          return 1;\r
      }\r
      \r
      \r
-     /**\r
-      * Check if parent folder does not include 'S' permission and if file/folder\r
-      * is shared with me\r
-      * \r
-      * @param file: OCFile\r
-      * @return boolean: True if it is shared with me and false if it is not\r
-      */\r
-     private boolean checkIfFileIsSharedWithMe(OCFile file) {\r
-         return (mFile.getPermissions() != null \r
-                 && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)\r
-                 && file.getPermissions() != null \r
-                 && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));\r
-     }\r
\r
      public void setSortOrder(Integer order, boolean ascending) {\r
          SharedPreferences.Editor editor = mAppPreferences.edit();\r
          editor.putInt("sortOrder", order);\r
   */
  package com.owncloud.android.ui.fragment;
  
- import java.io.File;
  import android.app.Activity;
  import android.content.Intent;
  import android.os.Bundle;
  import android.support.v4.widget.SwipeRefreshLayout;
  import android.view.ContextMenu;
+ import android.view.Menu;
  import android.view.MenuInflater;
  import android.view.MenuItem;
  import android.view.View;
  import android.widget.AdapterView;
  import android.widget.AdapterView.AdapterContextMenuInfo;
+ import android.widget.PopupMenu;
  
  import com.owncloud.android.R;
  import com.owncloud.android.authentication.AccountUtils;
@@@ -48,31 -48,36 +48,36 @@@ import com.owncloud.android.ui.activity
  import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
  import com.owncloud.android.ui.adapter.FileListListAdapter;
  import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+ import com.owncloud.android.ui.dialog.FileActionsDialogFragment;
  import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
  import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
  import com.owncloud.android.ui.preview.PreviewImageFragment;
  import com.owncloud.android.ui.preview.PreviewMediaFragment;
+ import com.owncloud.android.ui.preview.PreviewTextFragment;
  import com.owncloud.android.utils.FileStorageUtils;
  
+ import java.io.File;
  /**
   * A Fragment that lists all files and folders in a given path.
-  * 
+  *
   * TODO refactor to get rid of direct dependency on FileDisplayActivity
   */
- public class OCFileListFragment extends ExtendedListFragment {
+ public class OCFileListFragment extends ExtendedListFragment
+         implements FileActionsDialogFragment.FileActionsDialogFragmentListener {
      
      private static final String TAG = OCFileListFragment.class.getSimpleName();
  
      private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
              OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
-             
      public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
      public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
-             
      private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
  
      private FileFragment.ContainerActivity mContainerActivity;
-    
      private OCFile mFile = null;
      private FileListListAdapter mAdapter;
      private boolean mJustFolders;
          Log_OC.e(TAG, "onAttach");
          try {
              mContainerActivity = (FileFragment.ContainerActivity) activity;
-             
          } catch (ClassCastException e) {
-             throw new ClassCastException(activity.toString() + " must implement " + 
+             throw new ClassCastException(activity.toString() + " must implement " +
                      FileFragment.ContainerActivity.class.getSimpleName());
          }
          try {
              setOnRefreshListener((OnEnforceableRefreshListener) activity);
              
          } catch (ClassCastException e) {
-             throw new ClassCastException(activity.toString() + " must implement " + 
+             throw new ClassCastException(activity.toString() + " must implement " +
                      SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
          }
      }
  
-     
      @Override
      public void onDetach() {
          setOnRefreshListener(null);
                  mJustFolders,
                  getActivity(),
                  mContainerActivity
-                 );
+         );
          setListAdapter(mAdapter);
  
-         registerForContextMenu();
+         registerLongClickListener();
    }
  
+     private void registerLongClickListener() {
+         getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+             public boolean onItemLongClick(AdapterView<?> arg0, View v,
+                                            int index, long arg3) {
+                 showFileAction(index);
+                 return true;
+             }
+         });
+     }
+     private void showFileAction(int fileIndex) {
+         Bundle args = getArguments();
+         PopupMenu pm = new PopupMenu(getActivity(),null);
+         Menu menu = pm.getMenu();
+         boolean allowContextualActions =
+                 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
+         if (allowContextualActions) {
+             MenuInflater inflater = getActivity().getMenuInflater();
+             inflater.inflate(R.menu.file_actions_menu, menu);
+             OCFile targetFile = (OCFile) mAdapter.getItem(fileIndex);
+             if (mContainerActivity.getStorageManager() != null) {
+                 FileMenuFilter mf = new FileMenuFilter(
+                         targetFile,
+                         mContainerActivity.getStorageManager().getAccount(),
+                         mContainerActivity,
+                         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)getActivity()).getSecondFragment();
+             if (frag != null && frag instanceof FileDetailFragment &&
+                     frag.getFile().getFileId() == targetFile.getFileId()) {
+                 item = menu.findItem(R.id.action_see_details);
+                 if (item != null) {
+                     item.setVisible(false);
+                     item.setEnabled(false);
+                 }
+             }
+             FileActionsDialogFragment dialog = FileActionsDialogFragment.newInstance(menu,
+                     fileIndex, targetFile.getFileName());
+             dialog.setTargetFragment(this, 0);
+             dialog.show(getFragmentManager(), FileActionsDialogFragment.FTAG_FILE_ACTIONS);
+         }
+     }
      /**
       * Saves the current listed folder.
       */
      @Override
-     public void onSaveInstanceState (Bundle outState) {
+     public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          outState.putParcelable(KEY_FILE, mFile);
      }
-     
      /**
       * Call this, when the user presses the up button.
-      * 
-      * Tries to move up the current folder one level. If the parent folder was removed from the 
+      *
+      * Tries to move up the current folder one level. If the parent folder was removed from the
       * database, it continues browsing up until finding an existing folders.
-      * 
+      * <p/>
       * return       Count of folder levels browsed up.
       */
      public int onBrowseUp() {
          OCFile parentDir = null;
          int moveCount = 0;
-         
-         if(mFile != null){
+         if (mFile != null) {
              FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
-             
              String parentPath = null;
              if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
                  parentPath = new File(mFile.getRemotePath()).getParent();
-                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
-                       parentPath + OCFile.PATH_SEPARATOR;
+                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
+                         parentPath + OCFile.PATH_SEPARATOR;
                  parentDir = storageManager.getFileByPath(parentPath);
                  moveCount++;
              } else {
              }
              while (parentDir == null) {
                  parentPath = new File(parentPath).getParent();
-                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
-                       parentPath + OCFile.PATH_SEPARATOR;
+                 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
+                         parentPath + OCFile.PATH_SEPARATOR;
                  parentDir = storageManager.getFileByPath(parentPath);
                  moveCount++;
              }   // exit is granted because storageManager.getFileByPath("/") never returns null
              listDirectory(mFile /*, MainApp.getOnlyOnDevice()*/);
  
              onRefresh(false);
-             
              // restore index and top position
              restoreIndexAndTopPosition();
-             
          }   // else - should never happen now
-    
          return moveCount;
      }
-     
      @Override
      public void onItemClick(AdapterView<?> l, View v, int position, long id) {
          OCFile file = (OCFile) mAdapter.getItem(position);
          if (file != null) {
-             if (file.isFolder()) { 
+             if (file.isFolder()) {
                  // update state and view of this fragment
                  // TODO Enable when "On Device" is recovered ?
                  listDirectory(file/*, MainApp.getOnlyOnDevice()*/);
                  mContainerActivity.onBrowsedDownTo(file);
                  // save index and top position
                  saveIndexAndTopPosition(position);
-                 
              } else { /// Click on a file
                  if (PreviewImageFragment.canBePreviewed(file)) {
                      // preview image - it handles the download, if needed
                      ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
-                     
+                 } else if (PreviewTextFragment.canBePreviewed(file)){
+                     ((FileDisplayActivity)mContainerActivity).startTextPreview(file);
                  } else if (file.isDown()) {
                      if (PreviewMediaFragment.canBePreviewed(file)) {
                          // media preview
-                         ((FileDisplayActivity)mContainerActivity).startMediaPreview(file, 0, true);
+                         ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true);
                      } else {
                          mContainerActivity.getFileOperationsHelper().openFile(file);
                      }
 -
++                    
                  } else {
                      // automatic download, preview on finish
                      ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file);
                  }
 -
++                    
              }
 -
++            
          } else {
              Log_OC.d(TAG, "Null object in ListAdapter!!");
          }
-         
      }
-     
      /**
       * {@inheritDoc}
       */
      @Override
-     public void onCreateContextMenu (
+     public void onCreateContextMenu(
              ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
-         super.onCreateContextMenu(menu, v, menuInfo);
          Bundle args = getArguments();
-         boolean allowContextualActions = 
-                 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); 
+         boolean allowContextualActions =
+                 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
          if (allowContextualActions) {
              MenuInflater inflater = getActivity().getMenuInflater();
              inflater.inflate(R.menu.file_actions_menu, menu);
              AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
              OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-             
              if (mContainerActivity.getStorageManager() != null) {
                  FileMenuFilter mf = new FileMenuFilter(
                      targetFile,
              }
          }
      }
-     
-     
      /**
-      * {@inhericDoc}
+      * {@inheritDoc}
       */
      @Override
-     public boolean onContextItemSelected (MenuItem item) {
-         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();        
-         mTargetFile = (OCFile) mAdapter.getItem(info.position);
-         switch (item.getItemId()) {                
+     public boolean onFileActionChosen(int menuId, int filePosition) {
+         mTargetFile = (OCFile) mAdapter.getItem(filePosition);
+         switch (menuId) {
              case R.id.action_share_file: {
                  mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
                  return true;
              }
+             case R.id.action_share_with_users: {
+                 mContainerActivity.getFileOperationsHelper().showShareFile(mTargetFile);
+                 return true;
+             }
              case R.id.action_open_file_with: {
                  mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
                  return true;
                  dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                  return true;
              }
-             case R.id.action_download_file: 
+             case R.id.action_download_file:
              case R.id.action_sync_file: {
                  mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
                  return true;
              }
-             case R.id.action_cancel_download:
-             case R.id.action_cancel_upload: {
+             case R.id.action_cancel_sync: {
                  ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
                  return true;
              }
                  // Obtain the file
                  if (!mTargetFile.isDown()) {  // Download the file
                      Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
-                     ((FileDisplayActivity)mContainerActivity).startDownloadForSending(mTargetFile);
-                     
+                     ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile);
                  } else {
                      mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
                  }
                  getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
                  return true;
              }
+             case R.id.action_favorite_file: {
+                 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, true);
+                 return true;
+             }
+             case R.id.action_unfavorite_file: {
+                 mContainerActivity.getFileOperationsHelper().toggleFavorite(mTargetFile, false);
+                 return true;
+             }
+             case R.id.action_copy:
+                 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
+                 // Pass mTargetFile that contains info of selected file/folder
+                 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
+                 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_COPY_FILES);
+                 return true;
              default:
-                 return super.onContextItemSelected(item); 
+                 return false;
+         }
+     }
+     
+     /**
+      * {@inhericDoc}
+      */
+     @Override
+     public boolean onContextItemSelected (MenuItem item) {
+         AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+         boolean matched = onFileActionChosen(item.getItemId(),
+                 ((AdapterContextMenuInfo) item.getMenuInfo()).position);
+         if(!matched) {
+             return super.onContextItemSelected(item);
+         } else {
+             return matched;
          }
      }
  
      /**
       * Use this to query the {@link OCFile} that is currently
       * being displayed by this fragment
+      *
       * @return The currently viewed OCFile
       */
-     public OCFile getCurrentFile(){
+     public OCFile getCurrentFile() {
          return mFile;
      }
-     
      /**
       * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
       */
          // TODO Enable when "On Device" is recovered ?
          listDirectory(getCurrentFile()/*, MainApp.getOnlyOnDevice()*/);
      }
-     
      /**
       * Lists the given directory on the view. When the input parameter is null,
       * it will either refresh the last known directory. list the root
       * if there never was a directory.
-      * 
+      *
       * @param directory File to be listed
       */
      public void listDirectory(OCFile directory/*, boolean onlyOnDevice*/) {
          if (storageManager != null) {
  
              // Check input parameters for null
-             if(directory == null){
-                 if(mFile != null){
+             if (directory == null) {
+                 if (mFile != null) {
                      directory = mFile;
                  } else {
                      directory = storageManager.getFileByPath("/");
                      if (directory == null) return; // no files, wait for sync
                  }
              }
-         
-         
              // If that's not a directory -> List its parent
-             if(!directory.isFolder()){
+             if (!directory.isFolder()) {
                  Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
                  directory = storageManager.getFileById(directory.getParentId());
              }
                  if (file.isFolder()) {
                      foldersCount++;
                  } else {
-                     filesCount++;
-                     if (file.isImage()){
-                         imagesCount++;
+                     if (!file.isHidden()) {
+                         filesCount++;
+                         if (file.isImage()) {
+                             imagesCount++;
+                         }
                      }
                  }
              }
              if (version != null && version.supportsRemoteThumbnails() &&
                  imagesCount > 0 && imagesCount == filesCount) {
                  switchToGridView();
+                 registerLongClickListener();
              } else {
                  switchToListView();
              }
      }
  
      private String generateFooterText(int filesCount, int foldersCount) {
-         String output = "";
-         if (filesCount > 0){
-             if (filesCount == 1) {
-                 output = output + filesCount + " " + getResources().getString(R.string.file_list_file);
-             } else {
-                 output = output + filesCount + " " + getResources().getString(R.string.file_list_files);
+         String output;
+         if (filesCount <= 0) {
+             if (foldersCount <= 0) {
+                 output = "";
+             } else if (foldersCount == 1) {
+                 output = getResources().getString(R.string.file_list__footer__folder);
+             } else { // foldersCount > 1
+                 output = getResources().getString(R.string.file_list__footer__folders, foldersCount);
              }
-         }
-         if (foldersCount > 0 && filesCount > 0){
-             output = output + ", ";
-         }
-         if (foldersCount == 1) {
-             output = output + foldersCount + " " + getResources().getString(R.string.file_list_folder);
-         } else if (foldersCount > 1) {
-             output = output + foldersCount + " " + getResources().getString(R.string.file_list_folders);
-         }
  
+         } else if (filesCount == 1) {
+             if (foldersCount <= 0) {
+                 output = getResources().getString(R.string.file_list__footer__file);
+             } else if (foldersCount == 1) {
+                 output = getResources().getString(R.string.file_list__footer__file_and_folder);
+             } else { // foldersCount > 1
+                 output = getResources().getString(R.string.file_list__footer__file_and_folders, foldersCount);
+             }
+         } else {    // filesCount > 1
+             if (foldersCount <= 0) {
+                 output = getResources().getString(R.string.file_list__footer__files, filesCount);
+             } else if (foldersCount == 1) {
+                 output = getResources().getString(R.string.file_list__footer__files_and_folder, filesCount);
+             } else { // foldersCount > 1
+                 output = getResources().getString(
+                         R.string.file_list__footer__files_and_folders, filesCount, foldersCount
+                 );
+             }
+         }
          return output;
      }
  
      public void sortByName(boolean descending) {
          mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
      }
  
      public void sortBySize(boolean descending) {
          mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
-     }  
-     
-    
-     
+     }
  }
@@@ -53,13 -53,15 +53,15 @@@ import com.owncloud.android.lib.common.
  import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  import com.owncloud.android.lib.common.utils.Log_OC;
- import com.owncloud.android.operations.CreateShareOperation;
+ import com.owncloud.android.operations.CreateShareViaLinkOperation;
+ import com.owncloud.android.operations.CreateShareWithShareeOperation;
  import com.owncloud.android.operations.RemoveFileOperation;
- import com.owncloud.android.operations.UnshareLinkOperation;
+ import com.owncloud.android.operations.SynchronizeFileOperation;
+ import com.owncloud.android.operations.UnshareOperation;
  import com.owncloud.android.ui.activity.FileActivity;
  import com.owncloud.android.ui.activity.FileDisplayActivity;
+ import com.owncloud.android.ui.activity.ShareActivity;
  import com.owncloud.android.ui.fragment.FileFragment;
- import com.owncloud.android.utils.DisplayUtils;
  
  
  /**
@@@ -103,7 -105,6 +105,6 @@@ public class PreviewImageActivity exten
  
          // ActionBar
          ActionBar actionBar = getSupportActionBar();
-         actionBar.setIcon(DisplayUtils.getSeasonalIconId());
          updateActionBarTitleAndHomeButton(null);
          actionBar.hide();
  
                  }
              });
  
+             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                 getWindow().setStatusBarColor(getResources().getColor(R.color.owncloud_blue_dark_transparent));
+             }
          }
              
          if (savedInstanceState != null) {
      public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
          super.onRemoteOperationFinish(operation, result);
          
-         if (operation instanceof CreateShareOperation) {
-             onCreateShareOperationFinish((CreateShareOperation) operation, result);
-             
-         } else if (operation instanceof UnshareLinkOperation) {
-             onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
+         if (operation instanceof CreateShareViaLinkOperation ||
+                 operation instanceof CreateShareWithShareeOperation) {
+             onCreateShareOperationFinish(result);
+         } else if (operation instanceof UnshareOperation) {
+             onUnshareLinkOperationFinish((UnshareOperation) operation, result);
              
          } else if (operation instanceof RemoveFileOperation) {
              finish();
+         } else if (operation instanceof SynchronizeFileOperation) {
+             onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
          }
      }
      
      
-     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation,
+     private void onUnshareLinkOperationFinish(UnshareOperation operation,
                                                RemoteOperationResult result) {
          if (result.isSuccess()) {
              OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
              
      }
      
-     private void onCreateShareOperationFinish(CreateShareOperation operation,
-                                               RemoteOperationResult result) {
+     private void onCreateShareOperationFinish(RemoteOperationResult result) {
          if (result.isSuccess()) {
              OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
              if (file != null) {
          }
      }
  
+     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation,
+                                                   RemoteOperationResult result) {
+         if (result.isSuccess()) {
+             invalidateOptionsMenu();
+         }
+     }
      @Override
      protected ServiceConnection newTransferenceServiceConnection() {
          return new PreviewImageServiceConnection();
          
      }
  
-     
      private void requestForDownload(OCFile file) {
          if (mDownloaderBinder == null) {
              Log_OC.d(TAG, "requestForDownload called without binder to download service");
              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();
          }
  
      /**
       * Checks if OS version is Honeycomb one or higher
-      * 
+      *
       * @return boolean
       */
      private boolean isHoneycombOrHigher() {
@@@ -26,6 -26,7 +26,7 @@@ import android.annotation.SuppressLint
  import android.app.Activity;
  import android.graphics.Bitmap;
  import android.graphics.Point;
+ import android.graphics.drawable.Drawable;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.support.v4.app.FragmentStatePagerAdapter;
@@@ -40,10 -41,8 +41,10 @@@ import android.widget.ImageView
  import android.widget.ProgressBar;
  import android.widget.TextView;
  
 +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;
@@@ -70,20 -69,17 +71,20 @@@ public class PreviewImageFragment exten
  
      private static final String ARG_FILE = "FILE";
      private static final String ARG_IGNORE_FIRST = "IGNORE_FIRST";
 +    private static final String ARG_SHOW_RESIZED_IMAGE = "SHOW_RESIZED_IMAGE";
  
      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 boolean mIgnoreFirstSavedState;
-     
      private LoadBitmapTask mLoadBitmapTask = null;
  
  
       *                                  {@link FragmentStatePagerAdapter}
       *                                  ; TODO better solution
       */
 -    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);
 +        args.putBoolean(ARG_SHOW_RESIZED_IMAGE, showResizedImage);
          frag.setArguments(args);
          return frag;
      }
  
-     
      
      /**
       *  Creates an empty fragment for image previews.
      public PreviewImageFragment() {
          mIgnoreFirstSavedState = false;
      }
-     
-     
      /**
       * {@inheritDoc}
       */
              // not right now
  
          mIgnoreFirstSavedState = args.getBoolean(ARG_IGNORE_FIRST);
 +        mShowResizedImage = args.getBoolean(ARG_SHOW_RESIZED_IMAGE);
          setHasOptionsMenu(true);
      }
-     
  
      /**
       * {@inheritDoc}
       */
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
-             Bundle savedInstanceState) {
+                              Bundle savedInstanceState) {
          super.onCreateView(inflater, container, savedInstanceState);
          View view = inflater.inflate(R.layout.preview_image_fragment, container, false);
          mImageView = (TouchImageViewCustom) view.findViewById(R.id.image);
          if (getFile() == null) {
              throw new IllegalStateException("Instanced with a NULL OCFile");
          }
 -        if (!getFile().isDown()) {
 -            throw new IllegalStateException("There is no local file to preview");
 -        }
      }
-         
  
      /**
       * {@inheritDoc}
          super.onSaveInstanceState(outState);
          outState.putParcelable(PreviewImageFragment.EXTRA_FILE, getFile());
      }
-     
  
      @Override
      public void onStart() {
          super.onStart();
          if (getFile() != null) {
 -            mLoadBitmapTask = new LoadBitmapTask(mImageView, mMessageView, mProgressWheel);
 -            //mLoadBitmapTask.execute(new String[]{getFile().getStoragePath()});
 -//            mLoadBitmapTask.execute(getFile().getStoragePath());
 -            mLoadBitmapTask.execute(getFile());
 +            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.setVisibility(View.VISIBLE);
 +                    mBitmap  = thumbnail;
 +                } else {
 +                    // generate new Thumbnail
 +                    if (ThumbnailsCacheManager.cancelPotentialWork(getFile(), mImageView) &&
 +                        mContainerActivity.getStorageManager() != null) {
 +                        final ThumbnailsCacheManager.ThumbnailGenerationTask task =
 +                                new ThumbnailsCacheManager.ThumbnailGenerationTask(
 +                                        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(getFile().getStoragePath());
++                mLoadBitmapTask.execute(getFile());
 +            }
          }
      }
-     
-     
      @Override
      public void onStop() {
          Log_OC.d(TAG, "onStop starts");
          }
          super.onStop();
      }
-     
      /**
       * {@inheritDoc}
       */
      @Override
      public void onPrepareOptionsMenu(Menu menu) {
          super.onPrepareOptionsMenu(menu);
-         
          if (mContainerActivity.getStorageManager() != null) {
              // Update the file
              setFile(mContainerActivity.getStorageManager().getFileById(getFile().getFileId()));
-             
              FileMenuFilter mf = new FileMenuFilter(
                  getFile(),
                  mContainerActivity.getStorageManager().getAccount(),
              );
              mf.filter(menu);
          }
-         
          // additional restriction for this fragment 
          // TODO allow renaming in PreviewImageFragment
          MenuItem item = menu.findItem(R.id.action_rename_file);
              item.setVisible(false);
              item.setEnabled(false);
          }
-         
          // additional restriction for this fragment 
          // TODO allow refresh file in PreviewImageFragment
          item = menu.findItem(R.id.action_sync_file);
              item.setVisible(false);
              item.setEnabled(false);
          }
-         
+         // additional restriction for this fragment
+         item = menu.findItem(R.id.action_copy);
+         if (item != null) {
+             item.setVisible(false);
+             item.setEnabled(false);
+         }
      }
  
-     
-     
      /**
       * {@inheritDoc}
       */
                  mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                  return true;
              }
+             case R.id.action_share_with_users: {
+                 mContainerActivity.getFileOperationsHelper().showShareFile(getFile());
+                 return true;
+             }
              case R.id.action_unshare_file: {
                  mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                  return true;
                  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_download_file:
              case R.id.action_sync_file: {
                  mContainerActivity.getFileOperationsHelper().syncFile(getFile());
                  return true;
              }
-             
+             case R.id.action_favorite_file:{
+                 mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), true);
+                 return true;
+             }
+             case R.id.action_unfavorite_file:{
+                 mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), false);
+                 return true;
+             }
              default:
                  return false;
          }
      }
-     
  
      private void seeDetails() {
-         mContainerActivity.showDetails(getFile());        
+         mContainerActivity.showDetails(getFile());
      }
  
      @Override
      public void onResume() {
          super.onResume();
          super.onDestroy();
      }
  
-     
      /**
       * Opens the previewed image with an external application.
       */
          mContainerActivity.getFileOperationsHelper().openFile(getFile());
          finish();
      }
      
-     
-     private class LoadBitmapTask extends AsyncTask<String, Void, Bitmap> {
+     private class LoadBitmapTask extends AsyncTask<OCFile, Void, LoadImage> {
  
          /**
           * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
           */
          private final WeakReference<TextView> mMessageViewRef;
  
-         
          /**
           * Weak reference to the target {@link ProgressBar} shown while the load is in progress.
           * 
           */
          private final WeakReference<ProgressBar> mProgressWheelRef;
  
-         
          /**
-          * Error message to show when a load fails 
+          * Error message to show when a load fails
           */
          private int mErrorMessageId;
-         
-         
          /**
           * Constructor.
-          * 
-          * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
+          *
+          * @param imageView Target {@link ImageView} where the bitmap will be loaded into.
           */
          public LoadBitmapTask(ImageViewCustom imageView, TextView messageView,
                                ProgressBar progressWheel) {
              mMessageViewRef = new WeakReference<TextView>(messageView);
              mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
          }
-         
-         
          @Override
-         protected Bitmap doInBackground(String... params) {
+         protected LoadImage doInBackground(OCFile... params) {
              Bitmap result = null;
              if (params.length != 1) return null;
-             String storagePath = params[0];
+             OCFile ocFile = params[0];
+             String storagePath = ocFile.getStoragePath();
              try {
  
                  int maxDownScale = 3;   // could be a parameter passed to doInBackground(...)
                          result = BitmapUtils.decodeSampledBitmapFromFile(storagePath, minWidth,
                                  minHeight);
  
-                         if (isCancelled()) return result;
+                         if (isCancelled()) return new LoadImage(result, ocFile);
  
                          if (result == null) {
                              mErrorMessageId = R.string.preview_image_error_unknown_format;
  
              } 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);
-                 
              }
-             
-             return result;
+             return new LoadImage(result, ocFile);
          }
-         
          @Override
-         protected void onCancelled(Bitmap result) {
-             if (result != null) {
-                 result.recycle();
+         protected void onCancelled(LoadImage result) {
+             if (result != null && result.bitmap != null) {
+                 result.bitmap.recycle();
              }
          }
  
          @Override
-         protected void onPostExecute(Bitmap result) {
+         protected void onPostExecute(LoadImage result) {
              hideProgressWheel();
-             if (result != null) {
+             if (result.bitmap != null) {
                  showLoadedImage(result);
-             } else {
+             }
+             else {
                  showErrorMessage();
              }
-             if (result != null && mBitmap != result)  {
+             if (result.bitmap != null && mBitmap != result.bitmap)  {
                  // unused bitmap, release it! (just in case)
-                 result.recycle();
+                 result.bitmap.recycle();
              }
          }
-         
          @SuppressLint("InlinedApi")
-         private void showLoadedImage(Bitmap result) {
+         private void showLoadedImage(LoadImage result) {
              final ImageViewCustom imageView = mImageViewRef.get();
+             Bitmap bitmap = result.bitmap;
              if (imageView != null) {
-                 Log_OC.d(TAG, "Showing image with resolution " + result.getWidth() + "x" +
-                         result.getHeight());
-                 imageView.setImageBitmap(result);
+                 Log_OC.d(TAG, "Showing image with resolution " + bitmap.getWidth() + "x" +
+                         bitmap.getHeight());
+                 if (result.ocFile.getMimetype().equalsIgnoreCase("image/png")){
+                     Drawable backrepeat = getResources().getDrawable(R.drawable.backrepeat);
+                     imageView.setBackground(backrepeat);
+                 }
+                 imageView.setImageBitmap(bitmap);
                  imageView.setVisibility(View.VISIBLE);
-                 mBitmap  = result;  // needs to be kept for recycling when not useful
+                 mBitmap  = bitmap;  // needs to be kept for recycling when not useful
              }
  
              final TextView messageView = mMessageViewRef.get();
                  messageView.setVisibility(View.GONE);
              } // else , silently finish, the fragment was destroyed
          }
-         
          private void showErrorMessage() {
              final ImageView imageView = mImageViewRef.get();
              if (imageView != null) {
                  messageView.setVisibility(View.VISIBLE);
              } // else , silently finish, the fragment was destroyed
          }
-         
          private void hideProgressWheel() {
              final ProgressBar progressWheel = mProgressWheelRef.get();
              if (progressWheel != null) {
                  progressWheel.setVisibility(View.GONE);
              }
          }
-         
      }
  
      /**
          return (file != null && file.isImage());
      }
  
-     
      /**
       * Finishes the preview
       */
          Activity container = getActivity();
          container.finish();
      }
-     
      public TouchImageViewCustom getImageView() {
          return mImageView;
      }
  
+     private class LoadImage {
+         private Bitmap bitmap;
+         private OCFile ocFile;
+         public LoadImage(Bitmap bitmap, OCFile ocFile){
+             this.bitmap = bitmap;
+             this.ocFile = ocFile;
+         }
+     }
  }