Merge of master after sync_review was merged into it
authorDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 09:25:06 +0000 (10:25 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 09:25:06 +0000 (10:25 +0100)
1  2 
res/values/strings.xml
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

diff --combined res/values/strings.xml
      <string name="filedetails_created">Created:</string>
      <string name="filedetails_modified">Modified:</string>
      <string name="filedetails_download">Download</string>
-       <string name="filedetails_redownload">Refresh</string>
+     <string name="filedetails_sync_file">Refresh</string>
+       <string name="filedetails_redownload">Redownload</string>
      <string name="filedetails_open">Open</string>
+     <string name="filedetails_renamed_in_upload_msg">File was renamed to %1$s during upload</string>
      <string name="common_yes">Yes</string>
      <string name="common_no">No</string>
      <string name="common_ok">OK</string>
 -    <string name="common_cancel">Cancel</string>
 +    <string name="common_cancel_download">Cancel download</string>
 +    <string name="common_cancel_upload">Cancel upload</string>
 +      <string name="common_cancel">Cancel</string>
      <string name="common_save_exit">Save &amp; Exit</string>
      <string name="common_exit">Leave ownCloud</string>
      <string name="common_error">Error</string>
      <string name="uploader_upload_failed_content_multiple">Upload failed: %1$d/%2$d files were upload</string>
      <string name="downloader_download_in_progress_ticker">Downloading &#8230;</string>
      <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
--    <string name="downloader_download_succeeded_ticker">Download suceeded</string>
++    <string name="downloader_download_succeeded_ticker">Download succeeded</string>
      <string name="downloader_download_succeeded_content">%1$s was successfully download</string>
      <string name="downloader_download_failed_ticker">Download failed</string>
      <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
      <string name="sync_string_contacts">Contacts</string>
        <string name="sync_fail_ticker">Synchronization failed</string>
      <string name="sync_fail_content">Synchronization of %1$s could not be completed</string>
+       <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
+       <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
+     <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
+       <string name="sync_fail_in_favourites_content">Contents of %1$d files could not be sync\'ed (%2$d conflicts)</string>
        <string name="use_ssl">Use Secure Connection</string>
      <string name="location_no_provider">ownCloud cannot track your device. Please check your location settings</string>
      
      <string name="common_rename">Rename</string>
      <string name="common_remove">Remove</string>
      
 -      <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
 -      <string name="confirmation_remove_local">Local only</string>
 -      <string name="confirmation_remove_remote">Remove from server</string>
 -      <string name="confirmation_remove_remote_and_local">Remote and local</string>
 +        <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
 +        <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents ?"</string>
 +        <string name="confirmation_remove_local">Local only</string>
 +        <string name="confirmation_remove_folder_local">Local contents only</string>
 +        <string name="confirmation_remove_remote">Remove from server</string>
 +        <string name="confirmation_remove_remote_and_local">Remote and local</string>
  
      <string name="remove_success_msg">"Successful removal"</string>
      <string name="remove_fail_msg">"Removal could not be completed"</string>
      
 +    <string name="rename_dialog_title">Enter a new name</string>
      <string name="rename_local_fail_msg">"Local copy could not be renamed; try a differente new name"</string>
      <string name="rename_server_fail_msg">"Rename could not be completed"</string>
          
+     <string name="sync_file_fail_msg">Remote file could not be checked</string> 
+     <string name="sync_file_nothing_to_do_msg">File contents already synchronized</string> 
+     
      <string name="create_dir_fail_msg">Directory could not be created</string>
      
      <string name="wait_a_moment">Wait a moment</string>
@@@ -27,7 -27,7 +27,7 @@@ import java.util.Vector
  
  import com.owncloud.android.db.ProviderMeta;
  import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
- import com.owncloud.android.files.services.FileDownloader;
+ import com.owncloud.android.utils.FileStorageUtils;
  
  import android.accounts.Account;
  import android.content.ContentProviderClient;
@@@ -118,16 -118,13 +118,18 @@@ public class FileDataStorageManager imp
          if (!file.isDirectory())
              cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
          cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
-         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate());
+         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
+         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
          cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
  
--        if (fileExists(file.getRemotePath())) {
--            OCFile oldFile = getFileByPath(file.getRemotePath());
-             if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
-                 file.setStoragePath(oldFile.getStoragePath());
-             if (!file.isDirectory());
-                 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
--            file.setFileId(oldFile.getFileId());
++        boolean sameRemotePath = fileExists(file.getRemotePath());
++        if (sameRemotePath ||
++            fileExists(file.getFileId())        ) {           // for renamed files; no more delete and create
++            
++            if (sameRemotePath) {
++                OCFile oldFile = getFileByPath(file.getRemotePath());
++                file.setFileId(oldFile.getFileId());
++            }
  
              overriden = true;
              if (getContentResolver() != null) {
                                      + e.getMessage());
                  }
              }
-         } else if (fileExists(file.getFileId())) {      // for renamed files; no more delete and create
-                 OCFile oldFile = getFileById(file.getFileId());
-                 if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
-                     file.setStoragePath(oldFile.getStoragePath());
-                 if (!file.isDirectory());
-                     cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
-                 overriden = true;
-                 if (getContentResolver() != null) {
-                     getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
-                             ProviderTableMeta._ID + "=?",
-                             new String[] { String.valueOf(file.getFileId()) });
-                 } else {
-                     try {
-                         getContentProvider().update(ProviderTableMeta.CONTENT_URI,
-                                 cv, ProviderTableMeta._ID + "=?",
-                                 new String[] { String.valueOf(file.getFileId()) });
-                     } catch (RemoteException e) {
-                         Log.e(TAG,
-                                 "Fail to insert insert file to database "
-                                         + e.getMessage());
-                     }
-                 }
          } else {
              Uri result_uri = null;
              if (getContentResolver() != null) {
              if (!file.isDirectory())
                  cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
              cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
-             cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate());
+             cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
+             cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
              cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
  
              if (fileExists(file.getRemotePath())) {
                  OCFile oldFile = getFileByPath(file.getRemotePath());
-                 if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
-                     file.setStoragePath(oldFile.getStoragePath());
-                 if (!file.isDirectory());
-                     cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
                  file.setFileId(oldFile.getFileId());
                  operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
                          withValues(cv).
                          withSelection(  ProviderTableMeta._ID + "=?", 
                                          new String[] { String.valueOf(file.getFileId()) })
                          .build());
                  
 +            } else if (fileExists(file.getFileId())) {
 +                    OCFile oldFile = getFileById(file.getFileId());
 +                    if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
 +                        file.setStoragePath(oldFile.getStoragePath());
 +                    if (!file.isDirectory());
 +                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
 +
 +                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
 +                            withValues(cv).
 +                            withSelection(  ProviderTableMeta._ID + "=?", 
 +                                            new String[] { String.valueOf(file.getFileId()) })
 +                            .build());
 +                    
              } else {
                  operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
              }
                  file.setStoragePath(c.getString(c
                          .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
                  if (file.getStoragePath() == null) {
-                     // try to find existing file and bind it with current account
-                     File f = new File(FileDownloader.getSavePath(mAccount.name) + file.getRemotePath());
-                     if (f.exists())
+                     // try to find existing file and bind it with current account; - with the current update of SynchronizeFolderOperation, this won't be necessary anymore after a full synchronization of the account
+                     File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
+                     if (f.exists()) {
                          file.setStoragePath(f.getAbsolutePath());
+                         file.setLastSyncDateForData(f.lastModified());
+                     }
                  }
              }
              file.setFileLength(c.getLong(c
                      .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
              file.setModificationTimestamp(c.getLong(c
                      .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
-             file.setLastSyncDate(c.getLong(c
+             file.setLastSyncDateForProperties(c.getLong(c
                      .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
+             file.setLastSyncDateForData(c.getLong(c.
+                     getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
              file.setKeepInSync(c.getInt(
                                  c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
          }
          if (file.isDown() && removeLocalCopy) {
              new File(file.getStoragePath()).delete();
          }
-             File f = new File(FileDownloader.getSavePath(mAccount.name) + file.getRemotePath());
 +        if (file.isDirectory() && removeLocalCopy) {
-             String defaultSavePath = FileDownloader.getSavePath(mAccount.name);
++            File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
 +            if (f.exists() && f.isDirectory() && (f.list() == null || f.list().length == 0)) {
 +                f.delete();
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent) {
 +        // TODO consider possible failures
 +        if (dir != null && dir.isDirectory() && dir.getFileId() != -1) {
 +            Vector<OCFile> children = getDirectoryContent(dir);
 +            if (children != null) {
 +                OCFile child = null;
 +                for (int i=0; i<children.size(); i++) {
 +                    child = children.get(i);
 +                    if (child.isDirectory()) {
 +                        removeDirectory(child, removeDBData, removeLocalContent);
 +                    } else {
 +                        if (removeDBData) {
 +                            removeFile(child, removeLocalContent);
 +                        } else if (removeLocalContent) {
 +                            if (child.isDown()) {
 +                                new File(child.getStoragePath()).delete();
 +                            }
 +                        }
 +                    }
 +                }
 +                if (removeDBData) {
 +                    removeFile(dir, true);
 +                }
 +            }
 +        }
 +    }
 +    
 +    
 +    /**
 +     * Updates database for a folder that was moved to a different location.
 +     * 
 +     * TODO explore better (faster) implementations
 +     * TODO throw exceptions up !
 +     */
 +    @Override
 +    public void moveDirectory(OCFile dir, String newPath) {
 +        // TODO check newPath
 +        
 +        if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) {
 +            /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
 +            Cursor c = null;
 +            if (getContentProvider() != null) {
 +                try {
 +                    c = getContentProvider().query(ProviderTableMeta.CONTENT_URI, 
 +                                                    null,
 +                                                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
 +                                                    new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
 +                } catch (RemoteException e) {
 +                    Log.e(TAG, e.getMessage());
 +                }
 +            } else {
 +                c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, 
 +                                                null,
 +                                                ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
 +                                                new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
 +            }
 +
 +            /// 2. prepare a batch of update operations to change all the descendants
 +            ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
 +            int lengthOfOldPath = dir.getRemotePath().length();
++            String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
 +            int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
 +            if (c.moveToFirst()) {
 +                do {
 +                    ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
 +                    OCFile child = createFileInstance(c);
 +                    cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
 +                    if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
 +                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
 +                    }
 +                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
 +                                                                        withValues(cv).
 +                                                                        withSelection(  ProviderTableMeta._ID + "=?", 
 +                                                                                new String[] { String.valueOf(child.getFileId()) })
 +                                                                                .build());
 +                } while (c.moveToNext());
 +            }
 +            c.close();
 +            
 +            /// 3. apply updates in batch
 +            try {
 +                if (getContentResolver() != null) {
 +                    getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
 +                
 +                } else {
 +                    getContentProvider().applyBatch(operations);
 +                }
 +                
 +            } catch (OperationApplicationException e) {
 +                Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
 +                
 +            } catch (RemoteException e) {
 +                Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
 +            }
 +            
 +        }
      }
  
  }
@@@ -22,7 -22,6 +22,7 @@@ import java.io.File
  
  import android.os.Parcel;
  import android.os.Parcelable;
 +import android.util.Log;
  
  public class OCFile implements Parcelable, Comparable<OCFile> {
  
@@@ -39,8 -38,6 +39,8 @@@
      };
  
      public static final String PATH_SEPARATOR = "/";
 +
 +    private static final String TAG = OCFile.class.getSimpleName();
      
      private long mId;
      private long mParentId;
      private String mLocalPath;
      private String mMimeType;
      private boolean mNeedsUpdating;
-     private long mLastSyncDate;
+     private long mLastSyncDateForProperties;
+     private long mLastSyncDateForData;
      private boolean mKeepInSync;
  
+     private String mEtag;
      /**
       * Create new {@link OCFile} with given path.
       * 
@@@ -86,7 -86,8 +89,8 @@@
          mMimeType = source.readString();
          mNeedsUpdating = source.readInt() == 0;
          mKeepInSync = source.readInt() == 1;
-         mLastSyncDate = source.readLong();
+         mLastSyncDateForProperties = source.readLong();
+         mLastSyncDateForData = source.readLong();
      }
  
      @Override
          dest.writeString(mMimeType);
          dest.writeInt(mNeedsUpdating ? 1 : 0);
          dest.writeInt(mKeepInSync ? 1 : 0);
-         dest.writeLong(mLastSyncDate);
+         dest.writeLong(mLastSyncDateForProperties);
+         dest.writeLong(mLastSyncDateForData);
      }
      
      /**
       */
      public String getFileName() {
          File f = new File(getRemotePath());
 -        return f.getName().length() == 0 ? "/" : f.getName();
 +        return f.getName().length() == 0 ? PATH_SEPARATOR : f.getName();
 +    }
 +    
 +    /**
 +     * Sets the name of the file
 +     * 
 +     * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory 
 +     */
 +    public void setFileName(String name) {
 +        Log.d(TAG, "OCFile name changin from " + mRemotePath);
 +        if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(PATH_SEPARATOR)) {
 +            String parent = (new File(getRemotePath())).getParent();
 +            parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
 +            mRemotePath =  parent + name;
 +            if (isDirectory()) {
 +                mRemotePath += PATH_SEPARATOR;
 +            }
 +            Log.d(TAG, "OCFile name changed to " + mRemotePath);
 +        }
      }
  
      /**
          mLength = 0;
          mCreationTimestamp = 0;
          mModifiedTimestamp = 0;
-         mLastSyncDate = 0;
+         mLastSyncDateForProperties = 0;
+         mLastSyncDateForData = 0;
          mKeepInSync = false;
          mNeedsUpdating = false;
      }
          return mNeedsUpdating;
      }
      
-     public long getLastSyncDate() {
-         return mLastSyncDate;
+     public long getLastSyncDateForProperties() {
+         return mLastSyncDateForProperties;
+     }
+     
+     public void setLastSyncDateForProperties(long lastSyncDate) {
+         mLastSyncDateForProperties = lastSyncDate;
      }
      
-     public void setLastSyncDate(long lastSyncDate) {
-         mLastSyncDate = lastSyncDate;
+     public long getLastSyncDateForData() {
+         return mLastSyncDateForData;
+     }
+     public void setLastSyncDateForData(long lastSyncDate) {
+         mLastSyncDateForData = lastSyncDate;
      }
  
      public void setKeepInSync(boolean keepInSync) {
      @Override
      public String toString() {
          String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s]";
 -        asString = String.format(asString, new Long(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, new Long(mParentId), new Boolean(mKeepInSync));
 +        asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync));
          return asString;
      }
  
+     public String getEtag() {
+         return mEtag;
+     }
+     public long getLocalModificationTimestamp() {
+         if (mLocalPath != null && mLocalPath.length() > 0) {
+             File f = new File(mLocalPath);
+             return f.lastModified();
+         }
+         return 0;
+     }
  }
@@@ -25,8 -25,8 +25,8 @@@ import java.util.Vector
  import java.util.concurrent.ConcurrentHashMap;\r
  import java.util.concurrent.ConcurrentMap;\r
  \r
+ import com.owncloud.android.datamodel.FileDataStorageManager;\r
  import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
  import eu.alefzero.webdav.OnDatatransferProgressListener;\r
  \r
  import com.owncloud.android.network.OwnCloudClientUtils;\r
@@@ -40,11 -40,8 +40,8 @@@ import android.app.Notification
  import android.app.NotificationManager;\r
  import android.app.PendingIntent;\r
  import android.app.Service;\r
- import android.content.ContentValues;\r
  import android.content.Intent;\r
- import android.net.Uri;\r
  import android.os.Binder;\r
- import android.os.Environment;\r
  import android.os.Handler;\r
  import android.os.HandlerThread;\r
  import android.os.IBinder;\r
@@@ -62,6 -59,7 +59,7 @@@ public class FileDownloader extends Ser
      public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
      public static final String EXTRA_FILE = "FILE";\r
      \r
+     public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";\r
      public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
      public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    \r
      public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
@@@ -75,6 -73,7 +73,7 @@@
      private IBinder mBinder;\r
      private WebdavClient mDownloadClient = null;\r
      private Account mLastAccount = null;\r
+     private FileDataStorageManager mStorageManager;\r
      \r
      private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();\r
      private DownloadFileOperation mCurrentDownload = null;\r
      private String buildRemoteName(Account account, OCFile file) {\r
          return account.name + file.getRemotePath();\r
      }\r
-     \r
-     public static final String getSavePath(String accountName) {\r
-         File sdCard = Environment.getExternalStorageDirectory();\r
-         return sdCard.getAbsolutePath() + "/owncloud/" + Uri.encode(accountName, "@");   \r
-             // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B\r
-     }\r
-     \r
-     public static final String getTemporalPath(String accountName) {\r
-         File sdCard = Environment.getExternalStorageDirectory();\r
-         return sdCard.getAbsolutePath() + "/owncloud/tmp/" + Uri.encode(accountName, "@");\r
-             // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, that can be in the accountName since 0.1.190B\r
-     }\r
  \r
      \r
      /**\r
              mPendingDownloads.putIfAbsent(downloadKey, newDownload);\r
              newDownload.addDatatransferProgressListener(this);\r
              requestedDownloads.add(downloadKey);\r
+             sendBroadcastNewDownload(newDownload);\r
              \r
          } catch (IllegalArgumentException e) {\r
              Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());\r
          \r
          \r
          /**\r
 -         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download\r
 +         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
 +         * \r
 +         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. \r
           * \r
           * @param account       Owncloud account where the remote file is stored.\r
           * @param file          A file that could be in the queue of downloads.\r
           */\r
          public boolean isDownloading(Account account, OCFile file) {\r
 +            String targetKey = buildRemoteName(account, file);\r
              synchronized (mPendingDownloads) {\r
 -                return (mPendingDownloads.containsKey(buildRemoteName(account, file)));\r
 +                if (file.isDirectory()) {\r
 +                    // this can be slow if there are many downloads :(\r
 +                    Iterator<String> it = mPendingDownloads.keySet().iterator();\r
 +                    boolean found = false;\r
 +                    while (it.hasNext() && !found) {\r
 +                        found = it.next().startsWith(targetKey);\r
 +                    }\r
 +                    return found;\r
 +                } else {\r
 +                    return (mPendingDownloads.containsKey(targetKey));\r
 +                }\r
              }\r
          }\r
      }\r
              /// prepare client object to send the request to the ownCloud server\r
              if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
                  mLastAccount = mCurrentDownload.getAccount();\r
+                 mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
                  mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
              }\r
  \r
              try {\r
                  downloadResult = mCurrentDownload.execute(mDownloadClient);\r
                  if (downloadResult.isSuccess()) {\r
-                     ContentValues cv = new ContentValues();\r
-                     cv.put(ProviderTableMeta.FILE_STORAGE_PATH, mCurrentDownload.getSavePath());\r
-                     getContentResolver().update(\r
-                             ProviderTableMeta.CONTENT_URI,\r
-                             cv,\r
-                             ProviderTableMeta.FILE_NAME + "=? AND "\r
-                                     + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",\r
-                                     new String[] {\r
-                                     mCurrentDownload.getSavePath().substring(mCurrentDownload.getSavePath().lastIndexOf('/') + 1),\r
-                                     mLastAccount.name });\r
+                     saveDownloadedFile();\r
                  }\r
              \r
              } finally {\r
              /// notify result\r
              notifyDownloadResult(mCurrentDownload, downloadResult);\r
              \r
-             sendFinalBroadcast(mCurrentDownload, downloadResult);\r
+             sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);\r
          }\r
      }\r
  \r
-     \r
\r
+     /**\r
+      * Updates the OC File after a successful download.\r
+      */\r
+     private void saveDownloadedFile() {\r
+         OCFile file = mCurrentDownload.getFile();\r
+         long syncDate = System.currentTimeMillis();\r
+         file.setLastSyncDateForProperties(syncDate);\r
+         file.setLastSyncDateForData(syncDate);\r
+         file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());\r
+         // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available\r
+         file.setMimetype(mCurrentDownload.getMimeType());\r
+         file.setStoragePath(mCurrentDownload.getSavePath());\r
+         file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));\r
+         mStorageManager.saveFile(file);\r
+     }\r
\r
\r
      /**\r
       * Creates a status notification to show the download progress\r
       * \r
      \r
      \r
      /**\r
-      * Sends a broadcast in order to the interested activities can update their view\r
+      * Sends a broadcast when a download finishes in order to the interested activities can update their view\r
       * \r
       * @param download          Finished download operation\r
       * @param downloadResult    Result of the download operation\r
       */\r
-     private void sendFinalBroadcast(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
+     private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
          Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
          end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());\r
          end.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
          end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
-         if (downloadResult.isSuccess()) {\r
-             end.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
-         }\r
-         sendBroadcast(end);\r
+         end.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
+         sendStickyBroadcast(end);\r
+     }\r
+     \r
+     \r
+     /**\r
+      * Sends a broadcast when a new download is added to the queue.\r
+      * \r
+      * @param download          Added download operation\r
+      */\r
+     private void sendBroadcastNewDownload(DownloadFileOperation download) {\r
+         Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);\r
+         /*added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
+         added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/\r
+         added.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
+         sendStickyBroadcast(added);\r
      }\r
  \r
  }\r
@@@ -25,6 -25,10 +25,10 @@@ import java.util.Vector
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
  
+ import org.apache.http.HttpStatus;
+ import org.apache.jackrabbit.webdav.MultiStatus;
+ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
  import com.owncloud.android.authenticator.AccountAuthenticator;
  import com.owncloud.android.datamodel.FileDataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
@@@ -34,9 -38,12 +38,12 @@@ import com.owncloud.android.operations.
  import com.owncloud.android.operations.UploadFileOperation;
  import com.owncloud.android.ui.activity.FileDetailActivity;
  import com.owncloud.android.ui.fragment.FileDetailFragment;
+ import com.owncloud.android.utils.FileStorageUtils;
  import com.owncloud.android.utils.OwnCloudVersion;
  
  import eu.alefzero.webdav.OnDatatransferProgressListener;
+ import eu.alefzero.webdav.WebdavEntry;
+ import eu.alefzero.webdav.WebdavUtils;
  
  import com.owncloud.android.network.OwnCloudClientUtils;
  
@@@ -64,17 -71,22 +71,21 @@@ import eu.alefzero.webdav.WebdavClient
  public class FileUploader extends Service implements OnDatatransferProgressListener {
  
      public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH";
 -    public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID";
      public static final String EXTRA_UPLOAD_RESULT = "RESULT";
      public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+     public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH";
      public static final String EXTRA_FILE_PATH = "FILE_PATH";
+     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
      
 -    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";       // TODO remove this as a possible input argument ; use KEY_FILE everywhere
 -    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";     // TODO remove this as a possible input argument ; use KEY_FILE everywhere
+     public static final String KEY_FILE = "FILE";
 +    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";
 +    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";
+     public static final String KEY_MIME_TYPE = "MIME_TYPE";
      public static final String KEY_ACCOUNT = "ACCOUNT";
+     
      public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE";
      public static final String KEY_FORCE_OVERWRITE = "KEY_FORCE_OVERWRITE";
-     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
-     public static final String KEY_MIME_TYPE = "MIME_TYPE";
      public static final String KEY_INSTANT_UPLOAD = "INSTANT_UPLOAD";
  
      public static final int UPLOAD_SINGLE_FILE = 0;
       */
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
-         if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE)) {
+         if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE) || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
              Log.e(TAG, "Not enough information provided in intent");
              return Service.START_NOT_STICKY;
          }
          }
          Account account = intent.getParcelableExtra(KEY_ACCOUNT);
          
-         String[] localPaths, remotePaths, mimeTypes; 
+         String[] localPaths = null, remotePaths = null, mimeTypes = null;
+         OCFile[] files = null;
          if (uploadType == UPLOAD_SINGLE_FILE) {
-             localPaths = new String[] { intent.getStringExtra(KEY_LOCAL_FILE) };
-             remotePaths = new String[] { intent
-                     .getStringExtra(KEY_REMOTE_FILE) };
-             mimeTypes = new String[] { intent.getStringExtra(KEY_MIME_TYPE) };
+             
+             if (intent.hasExtra(KEY_FILE)) {
+                 files = new OCFile[] {intent.getParcelableExtra(KEY_FILE) };
+                 
+             } else {
+                 localPaths = new String[] { intent.getStringExtra(KEY_LOCAL_FILE) };
+                 remotePaths = new String[] { intent.getStringExtra(KEY_REMOTE_FILE) };
+                 mimeTypes = new String[] { intent.getStringExtra(KEY_MIME_TYPE) };
+             }
              
          } else { // mUploadType == UPLOAD_MULTIPLE_FILES
-             localPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE);
-             remotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE);
-             mimeTypes = intent.getStringArrayExtra(KEY_MIME_TYPE);
+             
+             if (intent.hasExtra(KEY_FILE)) {
+                 files = (OCFile[]) intent.getParcelableArrayExtra(KEY_FILE);    // TODO will this casting work fine?
+                 
+             } else {
+                 localPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE);
+                 remotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE);
+                 mimeTypes = intent.getStringArrayExtra(KEY_MIME_TYPE);
+             }
          }
  
-         if (localPaths == null) {
-             Log.e(TAG, "Incorrect array for local paths provided in upload intent");
-             return Service.START_NOT_STICKY;
+         FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
+         
+         boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
+         boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false); 
+         boolean fixed = false;
+         if (isInstant) {
+             fixed = checkAndFixInstantUploadDirectory(storageManager);  // MUST be done BEFORE calling obtainNewOCFileToUpload
          }
-         if (remotePaths == null) {
-             Log.e(TAG, "Incorrect array for remote paths provided in upload intent");
+         
+         if (intent.hasExtra(KEY_FILE) && files == null) {
+             Log.e(TAG, "Incorrect array for OCFiles provided in upload intent");
              return Service.START_NOT_STICKY;
-         }
              
-         if (localPaths.length != remotePaths.length) {
-             Log.e(TAG, "Different number of remote paths and local paths!");
-             return Service.START_NOT_STICKY;
+         } else if (!intent.hasExtra(KEY_FILE)) {
+             if (localPaths == null) {
+                 Log.e(TAG, "Incorrect array for local paths provided in upload intent");
+                 return Service.START_NOT_STICKY;
+             }
+             if (remotePaths == null) {
+                 Log.e(TAG, "Incorrect array for remote paths provided in upload intent");
+                 return Service.START_NOT_STICKY;
+             }
+             if (localPaths.length != remotePaths.length) {
+                 Log.e(TAG, "Different number of remote paths and local paths!");
+                 return Service.START_NOT_STICKY;
+             }
+             
+             files = new OCFile[localPaths.length];
+             for (int i=0; i < localPaths.length; i++) {
+                 files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes!=null)?mimeTypes[i]:(String)null), storageManager);
+             }
          }
-         
-         boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false); 
-         boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
-         
+             
          OwnCloudVersion ocv = new OwnCloudVersion(AccountManager.get(this).getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
          boolean chunked = FileUploader.chunkedUploadIsSupported(ocv);
          AbstractList<String> requestedUploads = new Vector<String>();
          String uploadKey = null;
          UploadFileOperation newUpload = null;
-         OCFile file = null;
-         FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
-         boolean fixed = false;
-         if (isInstant) {
-             fixed = checkAndFixInstantUploadDirectory(storageManager);
-         }
          try {
-             for (int i=0; i < localPaths.length; i++) {
-                 uploadKey = buildRemoteName(account, remotePaths[i]);
-                 file = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes!=null)?mimeTypes[i]:(String)null), isInstant, forceOverwrite, storageManager);
+             for (int i=0; i < files.length; i++) {
+                 uploadKey = buildRemoteName(account, files[i].getRemotePath());
                  if (chunked) {
-                     newUpload = new ChunkedUploadFileOperation(account, file, isInstant, forceOverwrite);
+                     newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite);
                  } else {
-                     newUpload = new UploadFileOperation(account, file, isInstant, forceOverwrite);
+                     newUpload = new UploadFileOperation(account, files[i], isInstant, forceOverwrite);
                  }
                  if (fixed && i==0) {
                      newUpload.setRemoteFolderToBeCreated();
          /**
           * Returns True when the file described by 'file' is being uploaded to the ownCloud account 'account' or waiting for it
           * 
 +         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. 
 +         * 
           * @param account       Owncloud account where the remote file will be stored.
           * @param file          A file that could be in the queue of pending uploads
           */
          public boolean isUploading(Account account, OCFile file) {
 +            String targetKey = buildRemoteName(account, file);
              synchronized (mPendingUploads) {
 -                return (mPendingUploads.containsKey(buildRemoteName(account, file)));
 +                if (file.isDirectory()) {
 +                    // this can be slow if there are many downloads :(
 +                    Iterator<String> it = mPendingUploads.keySet().iterator();
 +                    boolean found = false;
 +                    while (it.hasNext() && !found) {
 +                        found = it.next().startsWith(targetKey);
 +                    }
 +                    return found;
 +                } else {
 +                    return (mPendingUploads.containsKey(targetKey));
 +                }
              }
          }
      }
              try {
                  uploadResult = mCurrentUpload.execute(mUploadClient);
                  if (uploadResult.isSuccess()) {
-                     saveUploadedFile(mCurrentUpload.getFile(), mStorageManager);
+                     saveUploadedFile();
                  }
                  
              } finally {
      }
  
      /**
-      * Saves a new OC File after a successful upload.
+      * Saves a OC File after a successful upload.
+      * 
+      * A PROPFIND is necessary to keep the props in the local database synchronized with the server, 
+      * specially the modification time and Etag (where available)
       * 
-      * @param file              OCFile describing the uploaded file
-      * @param storageManager    Interface to the database where the new OCFile has to be stored.
-      * @param parentDirId       Id of the parent OCFile.
+      * TODO refactor this ugly thing
       */
-     private void saveUploadedFile(OCFile file, FileDataStorageManager storageManager) {
-         file.setModificationTimestamp(System.currentTimeMillis());
-         storageManager.saveFile(file);
+     private void saveUploadedFile() {
+         OCFile file = mCurrentUpload.getFile();
+         long syncDate = System.currentTimeMillis();
+         file.setLastSyncDateForData(syncDate);
+         
+         /// new PROPFIND to keep data consistent with server in theory, should return the same we already have
+         PropFindMethod propfind = null;
+         RemoteOperationResult result = null;
+         try {
+           propfind = new PropFindMethod(mUploadClient.getBaseUri() + WebdavUtils.encodePath(mCurrentUpload.getRemotePath()));
+           int status = mUploadClient.executeMethod(propfind);
+           boolean isMultiStatus = (status == HttpStatus.SC_MULTI_STATUS);
+           if (isMultiStatus) {
+               MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
+               WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
+                                                mUploadClient.getBaseUri().getPath());
+               updateOCFile(file, we);
+               file.setLastSyncDateForProperties(syncDate);
+               
+           } else {
+               mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
+           }
+           
+           result = new RemoteOperationResult(isMultiStatus, status);
+           Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage());
+           
+         } catch (Exception e) {
+             result = new RemoteOperationResult(e);
+             Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage(), e);
+         } finally {
+             if (propfind != null)
+                 propfind.releaseConnection();
+         }
+         
+         if (mCurrentUpload.wasRenamed()) {
+             OCFile oldFile = mCurrentUpload.getOldFile();
+             if (!oldFile.fileExists()) {
+                 // just a name coincidence
+                 file.setStoragePath(oldFile.getStoragePath());
+                 
+             } else {
+                 // conflict resolved with 'Keep both' by the user
+                 File localFile = new File(oldFile.getStoragePath());
+                 File newLocalFile = new File(FileStorageUtils.getDefaultSavePathFor(mCurrentUpload.getAccount().name, file));
+                 boolean renameSuccessed = localFile.renameTo(newLocalFile);
+                 if (renameSuccessed) {
+                     file.setStoragePath(newLocalFile.getAbsolutePath());
+                     
+                 } else {
+                     // poor solution
+                     Log.d(TAG, "DAMN IT: local rename failed after uploading a file with a new name already existing both in the remote account and the local database (should be due to a conflict solved with 'keep both'");
+                     file.setStoragePath(null);
+                         // not so fine:
+                         //      - local file will be kept there as 'trash' until is download (and overwritten) again from the server;
+                         //      - user will see as 'not down' a file that was just upload
+                         // BUT:
+                         //      - no loss of data happened
+                         //      - when the user downloads again the renamed and original file from the server, local file names and contents will be correctly synchronized with names and contents in server
+                 }
+                 oldFile.setStoragePath(null);
+                 mStorageManager.saveFile(oldFile);
+             }
+         }
+         
+         mStorageManager.saveFile(file);
+     }
+     
+     private void updateOCFile(OCFile file, WebdavEntry we) {
+         file.setCreationTimestamp(we.createTimestamp());
+         file.setFileLength(we.contentLength());
+         file.setMimetype(we.contentType());
+         file.setModificationTimestamp(we.modifiedTimesamp());
+         // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available
      }
      
      
      }
  
      
-     private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType, boolean isInstant, boolean forceOverwrite, FileDataStorageManager storageManager) {
+     private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType, FileDataStorageManager storageManager) {
          OCFile newFile = new OCFile(remotePath);
          newFile.setStoragePath(localPath);
-         newFile.setLastSyncDate(0);
-         newFile.setKeepInSync(forceOverwrite);
+         newFile.setLastSyncDateForProperties(0);
+         newFile.setLastSyncDateForData(0);
          
          // size
          if (localPath != null && localPath.length() > 0) {
              File localFile = new File(localPath);
              newFile.setFileLength(localFile.length());
+             newFile.setLastSyncDateForData(localFile.lastModified());
          }   // don't worry about not assigning size, the problems with localPath are checked when the UploadFileOperation instance is created
          
          // MIME type
          
          // parent dir
          String parentPath = new File(remotePath).getParent();
 -        parentPath = parentPath.endsWith("/")?parentPath:parentPath+"/" ;
 +        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR ;
          OCFile parentDir = storageManager.getFileByPath(parentPath);
          if (parentDir == null) {
              throw new IllegalStateException("Can not upload a file to a non existing remote location: " + parentPath);
      private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
          Intent end = new Intent(UPLOAD_FINISH_MESSAGE);
          end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath());    // real remote path, after possible automatic renaming
+         if (upload.wasRenamed()) {
+             end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath());
+         }
          end.putExtra(EXTRA_FILE_PATH, upload.getStoragePath());
          end.putExtra(ACCOUNT_NAME, upload.getAccount().name);
          end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess());
-         sendBroadcast(end);
 -        end.putExtra(EXTRA_PARENT_DIR_ID, upload.getFile().getParentId());
+         sendStickyBroadcast(end);
      }
  
  
@@@ -24,13 -24,12 +24,13 @@@ import java.io.IOException
  import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
  //import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
  
 +import android.accounts.Account;
  import android.util.Log;
  
  import com.owncloud.android.datamodel.DataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
- import com.owncloud.android.files.services.FileDownloader;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+ import com.owncloud.android.utils.FileStorageUtils;
  
  import eu.alefzero.webdav.WebdavClient;
  import eu.alefzero.webdav.WebdavUtils;
@@@ -49,9 -48,7 +49,9 @@@ public class RenameFileOperation extend
      
  
      private OCFile mFile;
 +    private Account mAccount;
      private String mNewName;
 +    private String mNewRemotePath;
      private DataStorageManager mStorageManager;
      
      
       * Constructor
       * 
       * @param file                  OCFile instance describing the remote file or folder to rename
 +     * @param account               OwnCloud account containing the remote file 
       * @param newName               New name to set as the name of file.
       * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
       */
 -    public RenameFileOperation(OCFile file, String newName, DataStorageManager storageManager) {
 +    public RenameFileOperation(OCFile file, Account account, String newName, DataStorageManager storageManager) {
          mFile = file;
 +        mAccount = account;
          mNewName = newName;
 +        mNewRemotePath = null;
          mStorageManager = storageManager;
      }
    
          RemoteOperationResult result = null;
          
          LocalMoveMethod move = null;
 -        //MoveMethod move = null;   // TODO find out why not use this
 -        String newRemotePath = null;
 +        mNewRemotePath = null;
          try {
              if (mNewName.equals(mFile.getFileName())) {
                  return new RemoteOperationResult(ResultCode.OK);
              }
          
 -            newRemotePath = (new File(mFile.getRemotePath())).getParent() + mNewName;
 +            String parent = (new File(mFile.getRemotePath())).getParent();
 +            parent = (parent.endsWith(OCFile.PATH_SEPARATOR)) ? parent : parent + OCFile.PATH_SEPARATOR; 
 +            mNewRemotePath =  parent + mNewName;
 +            if (mFile.isDirectory()) {
 +                mNewRemotePath += OCFile.PATH_SEPARATOR;
 +            }
              
              // check if the new name is valid in the local file system
              if (!isValidNewName()) {
                  return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
              }
          
 -            // check if a remote file with the new name already exists
 -            if (client.existsFile(newRemotePath)) {
 +            // check if a file with the new name already exists
 +            if (client.existsFile(mNewRemotePath) ||                             // remote check could fail by network failure, or by indeterminate behavior of HEAD for folders ... 
 +                    mStorageManager.getFileByPath(mNewRemotePath) != null) {     // ... so local check is convenient
                  return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
              }
 -            /*move = new MoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()), 
 -                                                client.getBaseUri() + WebdavUtils.encodePath(newRemotePath),
 -                                                false);*/
              move = new LocalMoveMethod( client.getBaseUri() + WebdavUtils.encodePath(mFile.getRemotePath()),
 -                                        client.getBaseUri() + WebdavUtils.encodePath(newRemotePath));
 +                                        client.getBaseUri() + WebdavUtils.encodePath(mNewRemotePath));
              int status = client.executeMethod(move, RENAME_READ_TIMEOUT, RENAME_CONNECTION_TIMEOUT);
              if (move.succeeded()) {
  
 -                // create new OCFile instance for the renamed file
 -                OCFile newFile = obtainUpdatedFile();
 -                OCFile oldFile = mFile;
 -                mFile = newFile; 
 -                
 -                // try to rename the local copy of the file
 -                if (oldFile.isDown()) {
 -                    File f = new File(oldFile.getStoragePath());
 -                    String newStoragePath = f.getParent() + mNewName;
 -                    if (f.renameTo(new File(newStoragePath))) {
 -                        mFile.setStoragePath(newStoragePath);
 -                    }
 -                    // else - NOTHING: the link to the local file is kept although the local name can't be updated
 -                    // TODO - study conditions when this could be a problem
 +                if (mFile.isDirectory()) {
 +                    saveLocalDirectory();
 +                    
 +                } else {
 +                    saveLocalFile();
 +                    
                  }
 -                
 -                mStorageManager.removeFile(oldFile, false);
 -                mStorageManager.saveFile(mFile);
 +             
 +            /* 
 +             *} else if (mFile.isDirectory() && (status == 207 || status >= 500)) {
 +             *   // TODO 
 +             *   // if server fails in the rename of a folder, some children files could have been moved to a folder with the new name while some others
 +             *   // stayed in the old folder;
 +             *   //
 +             *   // easiest and heaviest solution is synchronizing the parent folder (or the full account);
 +             *   //
 +             *   // a better solution is synchronizing the folders with the old and new names;
 +             *}
 +             */
                  
              }
              
              move.getResponseBodyAsString(); // exhaust response, although not interesting
              result = new RemoteOperationResult(move.succeeded(), status);
 -            Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + newRemotePath + ": " + result.getLogMessage());
 +            Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
              
          } catch (Exception e) {
              result = new RemoteOperationResult(e);
 -            Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((newRemotePath==null) ? mNewName : newRemotePath) + ": " + result.getLogMessage(), e);
 +            Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
              
          } finally {
              if (move != null)
      }
  
      
-         String localPath = FileDownloader.getSavePath(mAccount.name) + mFile.getRemotePath();
 +    private void saveLocalDirectory() {
 +        mStorageManager.moveDirectory(mFile, mNewRemotePath);
-             localDir.renameTo(new File(FileDownloader.getSavePath(mAccount.name) + mNewRemotePath));
++        String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
 +        File localDir = new File(localPath);
 +        if (localDir.exists()) {
++            localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewRemotePath));
 +            // TODO - if renameTo fails, children files that are already down will result unlinked
 +        }
 +    }
 +
 +    private void saveLocalFile() {
 +        mFile.setFileName(mNewName);
 +        
 +        // try to rename the local copy of the file
 +        if (mFile.isDown()) {
 +            File f = new File(mFile.getStoragePath());
 +            String parentStoragePath = f.getParent();
 +            if (!parentStoragePath.endsWith(File.separator))
 +                parentStoragePath += File.separator;
 +            if (f.renameTo(new File(parentStoragePath + mNewName))) {
 +                mFile.setStoragePath(parentStoragePath + mNewName);
 +            }
 +            // else - NOTHING: the link to the local file is kept although the local name can't be updated
 +            // TODO - study conditions when this could be a problem
 +        }
 +        
 +        mStorageManager.saveFile(mFile);
 +    }
 +
      /**
       * Checks if the new name to set is valid in the file system 
       * 
              return false;
          }
          // create a test file
-         String tmpFolder = FileDownloader.getTemporalPath("");
+         String tmpFolder = FileStorageUtils.getTemporalPath("");
          File testFile = new File(tmpFolder + mNewName);
          try {
              testFile.createNewFile();   // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name
      }
  
  
 -    /**
 -     * Creates a new OCFile for the new remote name of the renamed file.
 -     * 
 -     * @return      OCFile object with the same information than mFile, but the renamed remoteFile and the storagePath (empty)
 -     */
 -    private OCFile obtainUpdatedFile() {
 -        OCFile file = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName);
 -        file.setCreationTimestamp(mFile.getCreationTimestamp());
 -        file.setFileId(mFile.getFileId());
 -        file.setFileLength(mFile.getFileLength());
 -        file.setKeepInSync(mFile.keepInSync());
 -        file.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
 -        file.setLastSyncDateForData(mFile.getLastSyncDateForData());
 -        file.setMimetype(mFile.getMimetype());
 -        file.setModificationTimestamp(mFile.getModificationTimestamp());
 -        file.setParentId(mFile.getParentId());
 -        return file;
 -    }
 -
--
--    // move operation - TODO: find out why org.apache.jackrabbit.webdav.client.methods.MoveMethod is not used instead Â¿?
++    // move operation
      private class LocalMoveMethod extends DavMethodBase {
  
          public LocalMoveMethod(String uri, String dest) {
@@@ -82,6 -82,8 +82,8 @@@ import com.owncloud.android.operations.
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
  import com.owncloud.android.operations.RemoveFileOperation;\r
  import com.owncloud.android.operations.RenameFileOperation;\r
+ import com.owncloud.android.operations.SynchronizeFileOperation;\r
+ import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
  import com.owncloud.android.ui.activity.FileDetailActivity;\r
  import com.owncloud.android.ui.activity.FileDisplayActivity;\r
  import com.owncloud.android.ui.activity.TransferServiceGetter;\r
@@@ -111,6 -113,7 +113,7 @@@ public class FileDetailFragment extend
      private View mView;\r
      private OCFile mFile;\r
      private Account mAccount;\r
+     private FileDataStorageManager mStorageManager;\r
      private ImageView mPreview;\r
      \r
      private DownloadFinishReceiver mDownloadFinishReceiver;\r
      private Handler mHandler;\r
      private RemoteOperation mLastRemoteOperation;\r
  \r
-     private static final String TAG = "FileDetailFragment";\r
+     private static final String TAG = FileDetailFragment.class.getSimpleName();\r
      public static final String FTAG = "FileDetails"; \r
      public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
  \r
      public FileDetailFragment() {\r
          mFile = null;\r
          mAccount = null;\r
+         mStorageManager = null;\r
          mLayout = R.layout.file_details_empty;\r
      }\r
      \r
      public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {\r
          mFile = fileToDetail;\r
          mAccount = ocAccount;\r
+         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment \r
          mLayout = R.layout.file_details_empty;\r
          \r
          if(fileToDetail != null && ocAccount != null) {\r
              mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
          }\r
          \r
 -        updateFileDetails();\r
 +        updateFileDetails(false);\r
          return view;\r
      }\r
      \r
              throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
          }\r
      }\r
+     \r
+     \r
+     /**\r
+      * {@inheritDoc}\r
+      */\r
+     @Override\r
+     public void onActivityCreated(Bundle savedInstanceState) {\r
+         super.onActivityCreated(savedInstanceState);\r
+         if (mAccount != null) {\r
+             mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;\r
+         }\r
+     }\r
          \r
  \r
      @Override\r
      public void onClick(View v) {\r
          switch (v.getId()) {\r
              case R.id.fdDownloadBtn: {\r
--                //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath())) {\r
                  FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
                  FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
                  if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
                      }\r
                      \r
                  } else {\r
-                     Intent i = new Intent(getActivity(), FileDownloader.class);\r
-                     i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);\r
-                     i.putExtra(FileDownloader.EXTRA_FILE, mFile);\r
-                     /*i.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mFile.getRemotePath());\r
-                     i.putExtra(FileDownloader.EXTRA_FILE_PATH, mFile.getRemotePath());\r
-                     i.putExtra(FileDownloader.EXTRA_FILE_SIZE, mFile.getFileLength());*/\r
+                     mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
+                     WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
+                     mLastRemoteOperation.execute(wc, this, mHandler);\r
                  \r
                      // update ui \r
-                     setButtonsForTransferring();\r
-                 \r
-                     getActivity().startService(i);\r
-                     mContainerActivity.onFileStateChanged();    // this is not working; it is performed before the fileDownloadService registers it as 'in progress'\r
+                     boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+                     getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+                     setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference\r
+                     \r
                  }\r
                  break;\r
              }\r
              case R.id.fdKeepInSync: {\r
                  CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
                  mFile.setKeepInSync(cb.isChecked());\r
-                 FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
-                 fdsm.saveFile(mFile);\r
-                 if (mFile.keepInSync()) {\r
-                     onClick(getView().findViewById(R.id.fdDownloadBtn));\r
-                 } else {\r
-                     mContainerActivity.onFileStateChanged();    // put inside 'else' to not call it twice (here, and in the virtual click on fdDownloadBtn)\r
-                 }\r
+                 mStorageManager.saveFile(mFile);\r
                  \r
+                 /// register the OCFile instance in the observer service to monitor local updates;\r
+                 /// if necessary, the file is download \r
                  Intent intent = new Intent(getActivity().getApplicationContext(),\r
                                             FileObserverService.class);\r
                  intent.putExtra(FileObserverService.KEY_FILE_CMD,\r
                             (cb.isChecked()?\r
                                     FileObserverService.CMD_ADD_OBSERVED_FILE:\r
                                     FileObserverService.CMD_DEL_OBSERVED_FILE));\r
-                 intent.putExtra(FileObserverService.KEY_CMD_ARG, mFile.getStoragePath());\r
+                 intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);\r
+                 intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);\r
                  Log.e(TAG, "starting observer service");\r
                  getActivity().startService(intent);\r
                  \r
+                 if (mFile.keepInSync()) {\r
+                     onClick(getView().findViewById(R.id.fdDownloadBtn));    // force an immediate synchronization\r
+                 }\r
                  break;\r
              }\r
              case R.id.fdRenameBtn: {\r
 -                EditNameDialog dialog = EditNameDialog.newInstance(mFile.getFileName());\r
 -                dialog.setOnDismissListener(this);\r
 +                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);\r
                  dialog.show(getFragmentManager(), "nameeditdialog");\r
                  break;\r
              }   \r
                      try {\r
                          Intent i = new Intent(Intent.ACTION_VIEW);\r
                          mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
 -                        if (mimeType != null && !mimeType.equals(mFile.getMimetype())) {\r
 -                            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
 +                        if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
 +                            if (mimeType != null) {\r
 +                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
 +                            } else {\r
 +                                // desperate try\r
 +                                i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
 +                            }\r
                              i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
                              startActivity(i);\r
                              toastIt = false;\r
      @Override\r
      public void onConfirmation(String callerTag) {\r
          if (callerTag.equals(FTAG_CONFIRMATION)) {\r
-             FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
-             if (fdsm.getFileById(mFile.getFileId()) != null) {\r
+             if (mStorageManager.getFileById(mFile.getFileId()) != null) {\r
                  mLastRemoteOperation = new RemoveFileOperation( mFile, \r
                                                                  true, \r
-                                                                 new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
+                                                                 mStorageManager);\r
                  WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
                  mLastRemoteOperation.execute(wc, this, mHandler);\r
                  \r
      \r
      @Override\r
      public void onNeutral(String callerTag) {\r
-         FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getContentResolver());\r
          File f = null;\r
          if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
              f.delete();\r
              mFile.setStoragePath(null);\r
-             fdsm.saveFile(mFile);\r
+             mStorageManager.saveFile(mFile);\r
              updateFileDetails(mFile, mAccount);\r
          }\r
      }\r
       */\r
      public void updateFileDetails(OCFile file, Account ocAccount) {\r
          mFile = file;\r
+         if (ocAccount != null && ( \r
+                 mStorageManager == null || \r
+                 (mAccount != null && !mAccount.equals(ocAccount))\r
+            )) {\r
+             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
+         }\r
          mAccount = ocAccount;\r
 -        updateFileDetails();\r
 +        updateFileDetails(false);\r
      }\r
      \r
  \r
      /**\r
       * Updates the view with all relevant details about that file.\r
 +     *\r
 +     * TODO Remove parameter when the transferring state of files is kept in database. \r
 +     * \r
 +     * @param transferring      Flag signaling if the file should be considered as downloading or uploading, \r
 +     *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and \r
 +     *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
 +     * \r
       */\r
 -    public void updateFileDetails() {\r
 +    public void updateFileDetails(boolean transferring) {\r
  \r
          if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
              \r
              //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
              FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
              FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
 -            if ((downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
 +            if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
                  setButtonsForTransferring();\r
                  \r
              } else if (mFile.isDown()) {\r
                  setButtonsForDown();\r
                  \r
              } else {\r
 +                // TODO load default preview image; when the local file is removed, the preview remains there\r
                  setButtonsForRemote();\r
              }\r
          }\r
 +        getView().invalidate();\r
      }\r
      \r
      \r
      private void setButtonsForDown() {\r
          if (!isEmpty()) {\r
              Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-             downloadButton.setText(R.string.filedetails_redownload);\r
-             //downloadButton.setEnabled(true);\r
+             downloadButton.setText(R.string.filedetails_sync_file);\r
 -            //downloadButton.setEnabled(true);\r
          \r
              ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
              ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
                  String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
                  if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
                      if (downloadWasFine) {\r
-                         mFile.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH));    // updates the local object without accessing the database again\r
+                         mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
                      }\r
 -                    updateFileDetails();    // it updates the buttons; must be called although !downloadWasFine\r
 +                    updateFileDetails(false);    // it updates the buttons; must be called although !downloadWasFine\r
                  }\r
              }\r
          }\r
      private class UploadFinishReceiver extends BroadcastReceiver {\r
          @Override\r
          public void onReceive(Context context, Intent intent) {\r
 -            Log.d(TAG, "Received broacast! : " + intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH));\r
              String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
  \r
              if (!isEmpty() && accountName.equals(mAccount.name)) {\r
                  boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
                  String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
-                 if (mFile.getRemotePath().equals(uploadRemotePath)) {\r
+                 boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));\r
+                 if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
+                     renamedInUpload) {\r
                      if (uploadWasFine) {\r
-                         FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
-                         mFile = fdsm.getFileByPath(mFile.getRemotePath());\r
+                         mFile = mStorageManager.getFileByPath(mFile.getRemotePath());\r
+                     }\r
+                     if (renamedInUpload) {\r
+                         String newName = (new File(uploadRemotePath)).getName();\r
+                         Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
+                         msg.show();\r
                      }\r
 -                    updateFileDetails();    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
 +                    updateFileDetails(false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
                  }\r
              }\r
          }\r
              String newFilename = dialog.getNewFilename();\r
              Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
              mLastRemoteOperation = new RenameFileOperation( mFile, \r
 +                                                            mAccount, \r
                                                              newFilename, \r
                                                              new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
              WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
                  \r
              } else if (operation instanceof RenameFileOperation) {\r
                  onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
+                 \r
+             } else if (operation instanceof SynchronizeFileOperation) {\r
+                 onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
              }\r
          }\r
      }\r
              }\r
          }\r
      }\r
+     \r
+     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
+         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
  \r
+         if (!result.isSuccess()) {\r
+             if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
+                 Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);\r
+                 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);\r
+                 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);\r
+                 startActivity(i);\r
+                 \r
+             } else {\r
+                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
+                 msg.show();\r
+             }\r
+             \r
+             if (mFile.isDown()) {\r
+                 setButtonsForDown();\r
+                 \r
+             } else {\r
+                 setButtonsForRemote();\r
+             }\r
+             \r
+         } else {\r
+             if (operation.transferWasRequested()) {\r
+                 mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so \r
+                                                             // checking the service to see if the file is downloading results in FALSE\r
+             } else {\r
+                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
+                 msg.show();\r
+                 if (mFile.isDown()) {\r
+                     setButtonsForDown();\r
+                     \r
+                 } else {\r
+                     setButtonsForRemote();\r
+                 }\r
+             }\r
+         }\r
+     }\r
  \r
  }\r