浏览代码

Merge pull request #500 from owncloud/refactor_update_filelist_from_database

Refactored update of UI after finish of operations and file updates
David A. Velasco 11 年之前
父节点
当前提交
3969dbb768
共有 40 个文件被更改,包括 1609 次插入1952 次删除
  1. 1 1
      owncloud-android-library
  2. 1 1
      res/menu/file_actions_menu.xml
  3. 1 0
      res/values/strings.xml
  4. 1 1
      src/com/owncloud/android/authentication/AuthenticatorActivity.java
  5. 60 69
      src/com/owncloud/android/datamodel/FileDataStorageManager.java
  6. 239 0
      src/com/owncloud/android/files/FileMenuFilter.java
  7. 117 30
      src/com/owncloud/android/files/FileOperationsHelper.java
  8. 2 3
      src/com/owncloud/android/files/OwnCloudFileObserver.java
  9. 1 1
      src/com/owncloud/android/files/services/FileObserverService.java
  10. 3 4
      src/com/owncloud/android/files/services/FileUploader.java
  11. 2 0
      src/com/owncloud/android/media/MediaService.java
  12. 6 9
      src/com/owncloud/android/operations/CreateFolderOperation.java
  13. 13 1
      src/com/owncloud/android/operations/DownloadFileOperation.java
  14. 31 17
      src/com/owncloud/android/operations/RemoveFileOperation.java
  15. 15 15
      src/com/owncloud/android/operations/RenameFileOperation.java
  16. 21 8
      src/com/owncloud/android/operations/SynchronizeFileOperation.java
  17. 4 4
      src/com/owncloud/android/operations/SynchronizeFolderOperation.java
  18. 3 0
      src/com/owncloud/android/providers/FileContentProvider.java
  19. 50 12
      src/com/owncloud/android/services/OperationsService.java
  20. 1 1
      src/com/owncloud/android/ui/activity/AccountSelectActivity.java
  21. 8 1
      src/com/owncloud/android/ui/activity/ComponentsGetter.java
  22. 106 16
      src/com/owncloud/android/ui/activity/FileActivity.java
  23. 185 247
      src/com/owncloud/android/ui/activity/FileDisplayActivity.java
  24. 1 1
      src/com/owncloud/android/ui/activity/Preferences.java
  25. 2 2
      src/com/owncloud/android/ui/activity/UploadFilesActivity.java
  26. 8 7
      src/com/owncloud/android/ui/adapter/FileListListAdapter.java
  27. 1 1
      src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java
  28. 122 0
      src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java
  29. 0 178
      src/com/owncloud/android/ui/dialog/EditNameDialog.java
  30. 1 1
      src/com/owncloud/android/ui/dialog/LoadingDialog.java
  31. 114 0
      src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
  32. 136 0
      src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java
  33. 6 4
      src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java
  34. 43 454
      src/com/owncloud/android/ui/fragment/FileDetailFragment.java
  35. 63 17
      src/com/owncloud/android/ui/fragment/FileFragment.java
  36. 65 247
      src/com/owncloud/android/ui/fragment/OCFileListFragment.java
  37. 3 44
      src/com/owncloud/android/ui/preview/FileDownloadFragment.java
  38. 25 72
      src/com/owncloud/android/ui/preview/PreviewImageActivity.java
  39. 49 217
      src/com/owncloud/android/ui/preview/PreviewImageFragment.java
  40. 99 266
      src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

+ 1 - 1
owncloud-android-library

@@ -1 +1 @@
-Subproject commit 796189a04d5af05448993054a988658080128b20
+Subproject commit 7c481f7a70c9b7797cbd9eef31180c1ae77b4c18

+ 1 - 1
res/menu/file_actions_menu.xml

@@ -28,7 +28,7 @@
 	<item 	android:id="@+id/action_cancel_upload" 			android:title="@string/common_cancel_upload"		android:icon="@android:drawable/ic_menu_close_clear_cancel"		android:orderInCategory="1" />
 	<item 	android:id="@+id/action_rename_file"			android:title="@string/common_rename"				android:icon="@android:drawable/ic_menu_set_as"					android:orderInCategory="1" />
     <item 	android:id="@+id/action_remove_file"			android:title="@string/common_remove"				android:icon="@android:drawable/ic_menu_delete"					android:orderInCategory="1" />
-    <item 	android:id="@+id/action_see_details"			android:title="@string/actionbar_see_details"		android:icon="@android:drawable/ic_menu_info_details"			android:orderInCategory="1" />
     <item 	android:id="@+id/action_send_file"				android:title="@string/actionbar_send_file"			android:icon="@android:drawable/ic_menu_info_details"			android:orderInCategory="1" />
+    <item 	android:id="@+id/action_see_details"			android:title="@string/actionbar_see_details"		android:icon="@android:drawable/ic_menu_info_details"			android:orderInCategory="1" />
     
 </menu>

+ 1 - 0
res/values/strings.xml

@@ -193,6 +193,7 @@
     <string name="sync_file_nothing_to_do_msg">File contents already synchronized</string>
     <string name="create_dir_fail_msg">Folder could not be created</string>
     <string name="filename_forbidden_characters">Forbidden characters: / \\ &lt; &gt; : " | ? *</string>
+    <string name="filename_empty">File name cannot be empty</string>
     <string name="wait_a_moment">Wait a moment</string>
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <string name="filedisplay_no_file_selected">No file was selected</string>

+ 1 - 1
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -114,7 +114,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     private static final String KEY_AUTH_STATUS_TEXT = "AUTH_STATUS_TEXT";
     private static final String KEY_AUTH_STATUS_ICON = "AUTH_STATUS_ICON";
     private static final String KEY_SERVER_AUTH_METHOD = "SERVER_AUTH_METHOD";
-    private static final String KEY_WAITING_FOR_OP_ID = "DETECT_AUTH_OP_ID";
+    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
     private static final String KEY_AUTH_TOKEN = "AUTH_TOKEN";
 
     private static final String AUTH_ON = "on";

+ 60 - 69
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -422,10 +422,11 @@ public class FileDataStorageManager {
 //    }
     
 
-    public void removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
+    public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
+        boolean success = true;
         if (file != null) {
             if (file.isFolder()) {
-                removeFolder(file, removeDBData, removeLocalCopy);
+                success = removeFolder(file, removeDBData, removeLocalCopy);
                 
             } else {
                 if (removeDBData) {
@@ -433,19 +434,20 @@ public class FileDataStorageManager {
                     Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
                     String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
                     String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()};
+                    int deleted = 0;
                     if (getContentProviderClient() != null) {
                         try {
-                            getContentProviderClient().delete(file_uri, where, whereArgs);
+                            deleted = getContentProviderClient().delete(file_uri, where, whereArgs);
                         } catch (RemoteException e) {
                             e.printStackTrace();
                         }
                     } else {
-                        getContentResolver().delete(file_uri, where, whereArgs);
+                        deleted = getContentResolver().delete(file_uri, where, whereArgs);
                     }
-                    //updateFolderSize(file.getParentId());
+                    success &= (deleted > 0); 
                 }
-                if (removeLocalCopy && file.isDown() && file.getStoragePath() != null) {
-                    boolean success = new File(file.getStoragePath()).delete();
+                if (removeLocalCopy && file.isDown() && file.getStoragePath() != null && success) {
+                    success = new File(file.getStoragePath()).delete();
                     if (!removeDBData && success) {
                         // maybe unnecessary, but should be checked TODO remove if unnecessary
                         file.setStoragePath(null);
@@ -454,51 +456,84 @@ public class FileDataStorageManager {
                 }
             }
         }
+        return success;
     }
     
 
-    public void removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
+    public boolean removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
+        boolean success = true;
         if (folder != null && folder.isFolder()) {
             if (removeDBData &&  folder.getFileId() != -1) {
-                removeFolderInDb(folder);
+                success = removeFolderInDb(folder);
             }
-            if (removeLocalContent) {
-                File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
-                removeLocalFolder(localFolder);
+            if (removeLocalContent && success) {
+                success = removeLocalFolder(folder);
             }
         }
+        return success;
     }
 
-    private void removeFolderInDb(OCFile folder) {
+    private boolean removeFolderInDb(OCFile folder) {
         Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, ""+ folder.getFileId());   // URI for recursive deletion
         String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?";
         String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()};
+        int deleted = 0;
         if (getContentProviderClient() != null) {
             try {
-                getContentProviderClient().delete(folder_uri, where, whereArgs);
+                deleted = getContentProviderClient().delete(folder_uri, where, whereArgs);
             } catch (RemoteException e) {
                 e.printStackTrace();
             }
         } else {
-            getContentResolver().delete(folder_uri, where, whereArgs); 
+            deleted = getContentResolver().delete(folder_uri, where, whereArgs); 
         }
-        //updateFolderSize(folder.getParentId());
+        return deleted > 0;
     }
 
-    private void removeLocalFolder(File folder) {
-        if (folder.exists()) {
-            File[] files = folder.listFiles();
+    private boolean removeLocalFolder(OCFile folder) {
+        boolean success = true;
+        File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
+        if (localFolder.exists()) {
+            // stage 1: remove the local files already registered in the files database
+            Vector<OCFile> files = getFolderContent(folder.getFileId());
             if (files != null) {
-                for (File file : files) {
-                    if (file.isDirectory()) {
-                        removeLocalFolder(file);
+                for (OCFile file : files) {
+                    if (file.isFolder()) {
+                        success &= removeLocalFolder(file);
                     } else {
-                        file.delete();
+                        if (file.isDown()) {
+                            File localFile = new File(file.getStoragePath());
+                            success &= localFile.delete();
+                            if (success) {
+                                file.setStoragePath(null);
+                                saveFile(file);
+                            }
+                        }
                     }
                 }
             }
-            folder.delete();
+
+            // stage 2: remove the folder itself and any local file inside out of sync; 
+            //          for instance, after clearing the app cache or reinstalling
+            success &= removeLocalFolder(localFolder);
+        }
+        return success;
+    }
+
+    private boolean removeLocalFolder(File localFolder) {
+        boolean success = true;
+        File[] localFiles = localFolder.listFiles();
+        if (localFiles != null) {
+            for (File localFile : localFiles) {
+                if (localFile.isDirectory()) {
+                    success &= removeLocalFolder(localFile);
+                } else {
+                    success &= localFile.delete();
+                }
+            }
         }
+        success &= localFolder.delete();
+        return success;
     }
 
     /**
@@ -674,31 +709,6 @@ public class FileDataStorageManager {
         return c;
     }
     
-    private Cursor getShareCursorForValue(String key, String value) {
-        Cursor c = null;
-        if (getContentResolver() != null) {
-            c = getContentResolver()
-                    .query(ProviderTableMeta.CONTENT_URI_SHARE,
-                            null,
-                            key + "=? AND "
-                                    + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
-                                    + "=?",
-                                    new String[] { value, mAccount.name }, null);
-        } else {
-            try {
-                c = getContentProviderClient().query(
-                        ProviderTableMeta.CONTENT_URI_SHARE,
-                        null,
-                        key + "=? AND " + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER
-                        + "=?", new String[] { value, mAccount.name },
-                        null);
-            } catch (RemoteException e) {
-                Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
-                c = null;
-            }
-        }
-        return c;
-    }
 
     private OCFile createFileInstance(Cursor c) {
         OCFile file = null;
@@ -838,25 +848,6 @@ public class FileDataStorageManager {
         return overriden;
     }
 
-    private OCShare getShareById(long id) {
-        Cursor c = getShareCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
-        OCShare share = null;
-        if (c.moveToFirst()) {
-            share = createShareInstance(c);
-        }
-        c.close();
-        return share;
-    }
-
-    private OCShare getShareByRemoteId(long remoteId) {
-        Cursor c = getShareCursorForValue(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
-        OCShare share = null;
-        if (c.moveToFirst()) {
-            share = createShareInstance(c);
-        }
-        c.close();
-        return share;
-    }
 
     public OCShare getFirstShareByPathAndType(String path, ShareType type) {
         Cursor c = null;

+ 239 - 0
src/com/owncloud/android/files/FileMenuFilter.java

@@ -0,0 +1,239 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.files;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
+/**
+ * Filters out the file actions available in a given {@link Menu} for a given {@link OCFile} 
+ * according to the current state of the latest. 
+ * 
+ * @author David A. Velasco
+ */
+public class FileMenuFilter {
+
+    private OCFile mFile;
+    private ComponentsGetter mComponentsGetter;
+    private Account mAccount;
+    private Context mContext;
+    
+    /**
+     * Constructor
+     * 
+     * @param targetFile        {@link OCFile} target of the action to filter in the {@link Menu}.
+     * @param account           ownCloud {@link Account} holding targetFile.
+     * @param cg                Accessor to app components, needed to get access the 
+     *                          {@link FileUploader} and {@link FileDownloader} services.
+     * @param context           Android {@link Context}, needed to access build setup resources.
+     */
+    public FileMenuFilter(OCFile targetFile, Account account, ComponentsGetter cg, Context context) {
+        mFile = targetFile;
+        mAccount = account;
+        mComponentsGetter = cg;
+        mContext = context;
+    }
+    
+    
+    /**
+     * Filters out the file actions available in the passed {@link Menu} taken into account
+     * the state of the {@link OCFile} held by the filter.
+     *  
+     * @param menu              Options or context menu to filter.
+     */
+    public void filter(Menu menu) {
+        List<Integer> toShow = new ArrayList<Integer>();  
+        List<Integer> toHide = new ArrayList<Integer>();    
+        
+        filter(toShow, toHide);
+        
+        MenuItem item = null;
+        for (int i : toShow) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(true);
+                item.setEnabled(true);
+            }
+        }
+        
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * Filters out the file actions available in the passed {@link Menu} taken into account
+     * the state of the {@link OCFile} held by the filter.
+     * 
+     * Second method needed thanks to ActionBarSherlock.
+     * 
+     * TODO Get rid of it when ActionBarSherlock is replaced for newer Android Support Library.
+     *  
+     * @param menu              Options or context menu to filter.
+     */
+    public void filter(com.actionbarsherlock.view.Menu menu) {
+
+        List<Integer> toShow = new ArrayList<Integer>();
+        List<Integer> toHide = new ArrayList<Integer>();
+        
+        filter(toShow, toHide);
+
+        com.actionbarsherlock.view.MenuItem item = null;
+        for (int i : toShow) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(true);
+                item.setEnabled(true);
+            }
+        }
+        for (int i : toHide) {
+            item = menu.findItem(i);
+            if (item != null) {
+                item.setVisible(false);
+                item.setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * Performs the real filtering, to be applied in the {@link Menu} by the caller methods.
+     * 
+     * Decides what actions must be shown and hidden.
+     *  
+     * @param toShow            List to save the options that must be shown in the menu. 
+     * @param toHide            List to save the options that must be shown in the menu.
+     */
+    private void filter(List<Integer> toShow, List <Integer> toHide) {
+        boolean downloading = false;
+        boolean uploading = false;
+        if (mComponentsGetter != null && mFile != null && mAccount != null) {
+            FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
+            downloading = downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile);
+            FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
+            uploading = uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile);
+        }
+        
+        /// decision is taken for each possible action on a file in the menu
+        
+        // DOWNLOAD 
+        if (mFile == null || mFile.isFolder() || mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_download_file);
+            
+        } else {
+            toShow.add(R.id.action_download_file);
+        }
+        
+        // RENAME
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_rename_file);
+            
+        } else {
+            toShow.add(R.id.action_rename_file);
+        }
+        
+        // REMOVE
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_remove_file);
+            
+        } else {
+            toShow.add(R.id.action_remove_file);
+        }
+        
+        // OPEN WITH (different to preview!)
+        if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_open_file_with);
+            
+        } else {
+            toShow.add(R.id.action_open_file_with);
+        }
+        
+        
+        // CANCEL DOWNLOAD
+        if (mFile == null || !downloading || mFile.isFolder()) {
+            toHide.add(R.id.action_cancel_download);
+        } else {
+            toShow.add(R.id.action_cancel_download);
+        }
+        
+        // CANCEL UPLOAD
+        if (mFile == null || !uploading || mFile.isFolder()) {
+            toHide.add(R.id.action_cancel_upload);
+        } else {
+            toShow.add(R.id.action_cancel_upload);
+        }
+        
+        // SYNC FILE CONTENTS
+        if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+            toHide.add(R.id.action_sync_file);
+        } else {
+            toShow.add(R.id.action_sync_file);
+        }
+        
+        // SHARE FILE 
+        // TODO add check on SHARE available on server side?
+        if (mFile == null) {
+            toHide.add(R.id.action_share_file);
+        } else {
+            toShow.add(R.id.action_share_file);
+        }
+        
+        // UNSHARE FILE  
+        // TODO add check on SHARE available on server side?
+        if (mFile == null || !mFile.isShareByLink()) { 
+            toHide.add(R.id.action_unshare_file);
+        } else {
+            toShow.add(R.id.action_unshare_file);
+        }
+        
+        
+        // SEE DETAILS
+        if (mFile == null || mFile.isFolder()) {
+            toHide.add(R.id.action_see_details);
+        } else {
+            toShow.add(R.id.action_see_details);
+        }
+        
+        // SEND
+        boolean sendAllowed = (mContext != null &&
+                mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
+        if (mFile == null || !sendAllowed || mFile.isFolder() || uploading || downloading) {
+            toHide.add(R.id.action_send_file);
+        } else {
+            toShow.add(R.id.action_send_file);
+        }
+
+    }
+
+}

+ 117 - 30
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -19,6 +19,7 @@ package com.owncloud.android.files;
 
 import org.apache.http.protocol.HTTP;
 
+import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Intent;
 import android.net.Uri;
@@ -28,6 +29,8 @@ import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 
 import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
 import com.owncloud.android.lib.common.network.WebdavUtils;
@@ -48,8 +51,17 @@ public class FileOperationsHelper {
     
     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 void openFile(OCFile file, FileActivity callerActivity) {
+    public FileOperationsHelper(FileActivity fileActivity) {
+        mFileActivity = fileActivity;
+    }
+
+
+    public void openFile(OCFile file) {
         if (file != null) {
             String storagePath = file.getStoragePath();
             String encodedStoragePath = WebdavUtils.encodePath(storagePath);
@@ -70,28 +82,28 @@ public class FileOperationsHelper {
             
             Intent chooserIntent = null;
             if (intentForGuessedMimeType != null) {
-                chooserIntent = Intent.createChooser(intentForGuessedMimeType, callerActivity.getString(R.string.actionbar_open_with));
+                chooserIntent = Intent.createChooser(intentForGuessedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
             } else {
-                chooserIntent = Intent.createChooser(intentForSavedMimeType, callerActivity.getString(R.string.actionbar_open_with));
+                chooserIntent = Intent.createChooser(intentForSavedMimeType, mFileActivity.getString(R.string.actionbar_open_with));
             }
             
-            callerActivity.startActivity(chooserIntent);
+            mFileActivity.startActivity(chooserIntent);
             
         } else {
             Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
         }
     }
     
-
-    public void shareFileWithLink(OCFile file, FileActivity callerActivity) {
+    
+    public void shareFileWithLink(OCFile file) {
         
-        if (isSharedSupported(callerActivity)) {
+        if (isSharedSupported()) {
             if (file != null) {
                 String link = "https://fake.url";
                 Intent intent = createShareWithLinkIntent(link);
-                String[] packagesToExclude = new String[] { callerActivity.getPackageName() };
+                String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
                 DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intent, packagesToExclude, file);
-                chooserDialog.show(callerActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
+                chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
                 
             } else {
                 Log_OC.wtf(TAG, "Trying to share a NULL OCFile");
@@ -99,23 +111,23 @@ public class FileOperationsHelper {
             
         } else {
             // Show a Message
-            Toast t = Toast.makeText(callerActivity, callerActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
             t.show();
         }
     }
     
     
-    public void shareFileWithLinkToApp(OCFile file, Intent sendIntent, FileActivity callerActivity) {
+    public void shareFileWithLinkToApp(OCFile file, Intent sendIntent) {
         
         if (file != null) {
-            callerActivity.showLoadingDialog();
+            mFileActivity.showLoadingDialog();
             
-            Intent service = new Intent(callerActivity, OperationsService.class);
+            Intent service = new Intent(mFileActivity, OperationsService.class);
             service.setAction(OperationsService.ACTION_CREATE_SHARE);
-            service.putExtra(OperationsService.EXTRA_ACCOUNT, callerActivity.getAccount());
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
             service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
-            callerActivity.getOperationsServiceBinder().newOperation(service);
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
             
         } else {
             Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
@@ -134,39 +146,38 @@ public class FileOperationsHelper {
     /**
      *  @return 'True' if the server supports the Share API
      */
-    public boolean isSharedSupported(FileActivity callerActivity) {
-        if (callerActivity.getAccount() != null) {
-            AccountManager accountManager = AccountManager.get(callerActivity);
+    public boolean isSharedSupported() {
+        if (mFileActivity.getAccount() != null) {
+            AccountManager accountManager = AccountManager.get(mFileActivity);
 
-            String version = accountManager.getUserData(callerActivity.getAccount(), Constants.KEY_OC_VERSION);
+            String version = accountManager.getUserData(mFileActivity.getAccount(), Constants.KEY_OC_VERSION);
             return (new OwnCloudVersion(version)).isSharedSupported();
-            //return Boolean.parseBoolean(accountManager.getUserData(callerActivity.getAccount(), OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API));
         }
         return false;
     }
     
     
-    public void unshareFileWithLink(OCFile file, FileActivity callerActivity) {
+    public void unshareFileWithLink(OCFile file) {
         
-        if (isSharedSupported(callerActivity)) {
+        if (isSharedSupported()) {
             // Unshare the file
-            Intent service = new Intent(callerActivity, OperationsService.class);
+            Intent service = new Intent(mFileActivity, OperationsService.class);
             service.setAction(OperationsService.ACTION_UNSHARE);
-            service.putExtra(OperationsService.EXTRA_ACCOUNT, callerActivity.getAccount());
+            service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
-            callerActivity.getOperationsServiceBinder().newOperation(service);
+            mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
             
-            callerActivity.showLoadingDialog();
+            mFileActivity.showLoadingDialog();
             
         } else {
             // Show a Message
-            Toast t = Toast.makeText(callerActivity, callerActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            Toast t = Toast.makeText(mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
             t.show();
             
         }
     }
     
-    public void sendDownloadedFile(OCFile file, FileActivity callerActivity) {
+    public void sendDownloadedFile(OCFile file) {
         if (file != null) {
             Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND);
             // set MimeType
@@ -175,13 +186,89 @@ public class FileOperationsHelper {
             sendIntent.putExtra(Intent.ACTION_SEND, true);      // Send Action
             
             // Show dialog, without the own app
-            String[] packagesToExclude = new String[] { callerActivity.getPackageName() };
+            String[] packagesToExclude = new String[] { mFileActivity.getPackageName() };
             DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude, file);
-            chooserDialog.show(callerActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
+            chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
 
         } else {
             Log_OC.wtf(TAG, "Trying to send a NULL OCFile");
         }
     }
+    
+    
+    public void syncFile(OCFile file) {
+        // Sync file
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_SYNC_FILE);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath()); 
+        service.putExtra(OperationsService.EXTRA_SYNC_FILE_CONTENTS, true);
+        mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+    
+    
+    public void renameFile(OCFile file, String newFilename) {
+        // RenameFile
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_RENAME);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_NEWNAME, newFilename);
+        mWaitingForOpId = mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+
 
+    public void removeFile(OCFile file, boolean onlyLocalCopy) {
+        // RemoveFile
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_REMOVE);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_REMOVE_ONLY_LOCAL, onlyLocalCopy);
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+    
+    
+    public void createFolder(String remotePath, boolean createFullPath) {
+        // Create Folder
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_CREATE_FOLDER);
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
+        service.putExtra(OperationsService.EXTRA_CREATE_FULL_PATH, createFullPath);
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+        
+        mFileActivity.showLoadingDialog();
+    }
+
+    
+    public void cancelTransference(OCFile file) {
+        Account account = mFileActivity.getAccount();
+        FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
+        FileUploaderBinder uploaderBinder =  mFileActivity.getFileUploaderBinder();
+        if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
+            downloaderBinder.cancel(account, file);
+
+        } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
+            uploaderBinder.cancel(account, file);
+        }
+    }    
+
+
+    public long getOpIdWaitingFor() {
+        return mWaitingForOpId;
+    }
+
+
+    public void setOpIdWaitingFor(long waitingForOpId) {
+        mWaitingForOpId = waitingForOpId;
+    }
+    
+    
 }

+ 2 - 3
src/com/owncloud/android/files/OwnCloudFileObserver.java

@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -91,11 +91,10 @@ public class OwnCloudFileObserver extends FileObserver {
                                                                     // again, assuming that local files are linked to a remote file AT MOST, SOMETHING TO BE DONE; 
         SynchronizeFileOperation sfo = new SynchronizeFileOperation(file, 
                                                                     null, 
-                                                                    storageManager, 
                                                                     mOCAccount, 
                                                                     true, 
                                                                     mContext);
-        RemoteOperationResult result = sfo.execute(mOCAccount, mContext);
+        RemoteOperationResult result = sfo.execute(storageManager, mContext);
         if (result.getCode() == ResultCode.SYNC_CONFLICT) {
             // ISSUE 5: if the user is not running the app (this is a service!), this can be very intrusive; a notification should be preferred
             Intent i = new Intent(mContext, ConflictsResolveActivity.class);

+ 1 - 1
src/com/owncloud/android/files/services/FileObserverService.java

@@ -82,10 +82,10 @@ public class FileObserverService extends Service {
     
     @Override
     public void onDestroy() {
-        super.onDestroy();
         unregisterReceiver(mDownloadReceiver);
         mObserversMap = null;   // TODO study carefully the life cycle of Services to grant the best possible observance
         Log_OC.d(TAG, "Bye, bye");
+        super.onDestroy();
     }
     
     

+ 3 - 4
src/com/owncloud/android/files/services/FileUploader.java

@@ -38,6 +38,7 @@ import com.owncloud.android.lib.resources.files.RemoteFile;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.operations.UploadFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
 import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
@@ -549,10 +550,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
         RemoteOperationResult result = operation.execute(mUploadClient);
         if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mCurrentUpload.isRemoteFolderToBeCreated()) {
-            operation = new CreateFolderOperation( pathToGrant,
-                    true,
-                    mStorageManager    );
-            result = operation.execute(mUploadClient);
+            SyncOperation syncOp = new CreateFolderOperation( pathToGrant, true);
+            result = syncOp.execute(mUploadClient, mStorageManager);
         }
         if (result.isSuccess()) {
             OCFile parentDir = mStorageManager.getFileByPath(pathToGrant);

+ 2 - 0
src/com/owncloud/android/media/MediaService.java

@@ -218,6 +218,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
      */
     @Override
     public void onCreate() {
+        super.onCreate();
         Log_OC.d(TAG, "Creating ownCloud media service");
 
         mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)).
@@ -637,6 +638,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         mState = State.STOPPED;
         releaseResources(true);
         giveUpAudioFocus();
+        super.onDestroy();
     }
     
 

+ 6 - 9
src/com/owncloud/android/operations/CreateFolderOperation.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012 ownCloud Inc.
+ *   Copyright (C) 2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -17,13 +17,13 @@
 
 package com.owncloud.android.operations;
 
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.resources.files.CreateRemoteFolderOperation;
 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.Log_OC;
 
@@ -35,24 +35,21 @@ import com.owncloud.android.utils.Log_OC;
  * @author David A. Velasco 
  * @author masensio
  */
-public class CreateFolderOperation extends RemoteOperation implements OnRemoteOperationListener{
+public class CreateFolderOperation extends SyncOperation implements OnRemoteOperationListener{
     
     private static final String TAG = CreateFolderOperation.class.getSimpleName();
     
     protected String mRemotePath;
     protected boolean mCreateFullPath;
-    protected FileDataStorageManager mStorageManager;
     
     /**
      * Constructor
      * 
      * @param createFullPath        'True' means that all the ancestor folders should be created if don't exist yet.
-     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
      */
-    public CreateFolderOperation(String remotePath, boolean createFullPath, FileDataStorageManager storageManager) {
+    public CreateFolderOperation(String remotePath, boolean createFullPath) {
         mRemotePath = remotePath;
         mCreateFullPath = createFullPath;
-        mStorageManager = storageManager;
         
     }
 
@@ -94,10 +91,10 @@ public class CreateFolderOperation extends RemoteOperation implements OnRemoteOp
     public void saveFolderInDB() {
         OCFile newDir = new OCFile(mRemotePath);
         newDir.setMimetype("DIR");
-        long parentId = mStorageManager.getFileByPath(FileStorageUtils.getParentPath(mRemotePath)).getFileId();
+        long parentId = getStorageManager().getFileByPath(FileStorageUtils.getParentPath(mRemotePath)).getFileId();
         newDir.setParentId(parentId);
         newDir.setModificationTimestamp(System.currentTimeMillis());
-        mStorageManager.saveFile(newDir);
+        getStorageManager().saveFile(newDir);
 
         Log_OC.d(TAG, "Create directory " + mRemotePath + " in Database");
 

+ 13 - 1
src/com/owncloud/android/operations/DownloadFileOperation.java

@@ -21,10 +21,12 @@ import java.io.File;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
 import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.OperationCancelledException;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
@@ -48,6 +50,7 @@ public class DownloadFileOperation extends RemoteOperation {
     private OCFile mFile;
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
     private long mModificationTimestamp = 0;
+    private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
     
     private DownloadRemoteFileOperation mDownloadOperation;
 
@@ -129,6 +132,12 @@ public class DownloadFileOperation extends RemoteOperation {
         String tmpFolder =  getTmpFolder();
         
         /// perform the download
+        synchronized(mCancellationRequested) {
+            if (mCancellationRequested.get()) {
+                return new RemoteOperationResult(new OperationCancelledException());
+            }
+        }
+        
         mDownloadOperation = new DownloadRemoteFileOperation(mFile.getRemotePath(), tmpFolder);
         Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
         while (listener.hasNext()) {
@@ -152,7 +161,10 @@ public class DownloadFileOperation extends RemoteOperation {
     }
 
     public void cancel() {
-        mDownloadOperation.cancel();
+        mCancellationRequested.set(true);   // atomic set; there is no need of synchronizing it
+        if (mDownloadOperation != null) {
+            mDownloadOperation.cancel();
+        }
     }
 
 

+ 31 - 17
src/com/owncloud/android/operations/RemoveFileOperation.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -17,40 +17,40 @@
 
 package com.owncloud.android.operations;
 
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 
 
 /**
  * Remote operation performing the removal of a remote file or folder in the ownCloud server.
  * 
  * @author David A. Velasco
+ * @author masensio
  */
-public class RemoveFileOperation extends RemoteOperation {
+public class RemoveFileOperation extends SyncOperation {
     
     // private static final String TAG = RemoveFileOperation.class.getSimpleName();
     
     OCFile mFileToRemove;
-    boolean mDeleteLocalCopy;
-    FileDataStorageManager mDataStorageManager;
+    String mRemotePath;
+    boolean mOnlyLocalCopy;
     
     
     /**
      * Constructor
      * 
-     * @param fileToRemove          OCFile instance describing the remote file or folder to remove from the server
-     * @param deleteLocalCopy       When 'true', and a local copy of the file exists, it is also removed.
-     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
+     * @param remotePath            RemotePath of the OCFile instance describing the remote file or 
+     *                              folder to remove from the server
+     * @param onlyLocalCopy         When 'true', and a local copy of the file exists, only this is 
+     *                              removed.
      */
-    public RemoveFileOperation(OCFile fileToRemove, boolean deleteLocalCopy, FileDataStorageManager storageManager) {
-        mFileToRemove = fileToRemove;
-        mDeleteLocalCopy = deleteLocalCopy;
-        mDataStorageManager = storageManager;
+    public RemoveFileOperation(String remotePath, boolean onlyLocalCopy) {
+        mRemotePath = remotePath;
+        mOnlyLocalCopy = onlyLocalCopy;
     }
     
     
@@ -72,11 +72,25 @@ public class RemoveFileOperation extends RemoteOperation {
     protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         
-        RemoveRemoteFileOperation operation = new RemoveRemoteFileOperation(mFileToRemove.getRemotePath());
-        result = operation.execute(client);
+        mFileToRemove = getStorageManager().getFileByPath(mRemotePath);
+
+        boolean localRemovalFailed = false;
+        if (!mOnlyLocalCopy) {
+            RemoveRemoteFileOperation operation = new RemoveRemoteFileOperation(mRemotePath);
+            result = operation.execute(client);
+            if (result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                localRemovalFailed = !(getStorageManager().removeFile(mFileToRemove, true, true));
+            }
+            
+        } else {
+            localRemovalFailed = !(getStorageManager().removeFile(mFileToRemove, false, true));
+            if (!localRemovalFailed) {
+                result = new RemoteOperationResult(ResultCode.OK);
+            }
+        }
         
-        if (result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND) {
-            mDataStorageManager.removeFile(mFileToRemove, true, mDeleteLocalCopy);
+        if (localRemovalFailed) {
+            result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_REMOVED);
         }
         
         return result;

+ 15 - 15
src/com/owncloud/android/operations/RenameFileOperation.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -20,13 +20,12 @@ package com.owncloud.android.operations;
 import java.io.File;
 import java.io.IOException;
 
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.OwnCloudClient;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.Log_OC;
 
@@ -37,33 +36,32 @@ import android.accounts.Account;
  * Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
  * 
  * @author David A. Velasco
+ * @author masensio
  */
-public class RenameFileOperation extends RemoteOperation {
+public class RenameFileOperation extends SyncOperation {
     
     private static final String TAG = RenameFileOperation.class.getSimpleName();
     
-
     private OCFile mFile;
+    private String mRemotePath;
     private Account mAccount;
     private String mNewName;
     private String mNewRemotePath;
-    private FileDataStorageManager mStorageManager;
+
     
     
     /**
      * Constructor
      * 
-     * @param file                  OCFile instance describing the remote file or folder to rename
+     * @param remotePath            RemotePath of the 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, Account account, String newName, FileDataStorageManager storageManager) {
-        mFile = file;
+    public RenameFileOperation(String remotePath, Account account, String newName) {
+        mRemotePath = remotePath;
         mAccount = account;
         mNewName = newName;
         mNewRemotePath = null;
-        mStorageManager = storageManager;
     }
   
     public OCFile getFile() {
@@ -80,6 +78,8 @@ public class RenameFileOperation extends RemoteOperation {
     protected RemoteOperationResult run(OwnCloudClient client) {
         RemoteOperationResult result = null;
         
+        mFile = getStorageManager().getFileByPath(mRemotePath);
+        
         // check if the new name is valid in the local file system
         try {
             if (!isValidNewName()) {
@@ -92,8 +92,8 @@ public class RenameFileOperation extends RemoteOperation {
                 mNewRemotePath += OCFile.PATH_SEPARATOR;
             }
 
-            // ckeck local overwrite
-            if (mStorageManager.getFileByPath(mNewRemotePath) != null) {
+            // check local overwrite
+            if (getStorageManager().getFileByPath(mNewRemotePath) != null) {
                 return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
             }
             
@@ -120,7 +120,7 @@ public class RenameFileOperation extends RemoteOperation {
 
     
     private void saveLocalDirectory() {
-        mStorageManager.moveFolder(mFile, mNewRemotePath);
+        getStorageManager().moveFolder(mFile, mNewRemotePath);
         String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
         File localDir = new File(localPath);
         if (localDir.exists()) {
@@ -145,7 +145,7 @@ public class RenameFileOperation extends RemoteOperation {
             // TODO - study conditions when this could be a problem
         }
         
-        mStorageManager.saveFile(mFile);
+        getStorageManager().saveFile(mFile);
     }
 
     /**

+ 21 - 8
src/com/owncloud/android/operations/SynchronizeFileOperation.java

@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -18,16 +18,15 @@
 
 package com.owncloud.android.operations;
 
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.resources.files.RemoteFile;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.Log_OC;
 
@@ -42,13 +41,13 @@ import android.content.Intent;
  * @author masensio
  */
 
-public class SynchronizeFileOperation extends RemoteOperation {
+public class SynchronizeFileOperation extends SyncOperation {
 
     private String TAG = SynchronizeFileOperation.class.getSimpleName();
     
     private OCFile mLocalFile;
+    private String mRemotePath;
     private OCFile mServerFile;
-    private FileDataStorageManager mStorageManager;
     private Account mAccount;
     private boolean mSyncFileContents;
     private Context mContext;
@@ -58,25 +57,39 @@ public class SynchronizeFileOperation extends RemoteOperation {
     public SynchronizeFileOperation(
             OCFile localFile,
             OCFile serverFile,          // make this null to let the operation checks the server; added to reuse info from SynchronizeFolderOperation 
-            FileDataStorageManager storageManager, 
             Account account, 
             boolean syncFileContents,
             Context context) {
         
         mLocalFile = localFile;
         mServerFile = serverFile;
-        mStorageManager = storageManager;
         mAccount = account;
         mSyncFileContents = syncFileContents;
         mContext = context;
     }
 
+    public SynchronizeFileOperation(
+            String remotePath,  
+            Account account, 
+            boolean syncFileContents,
+            Context context) {
+        
+        mRemotePath = remotePath;
+        mServerFile = null;
+        mAccount = account;
+        mSyncFileContents = syncFileContents;
+        mContext = context;
+    }
 
     @Override
     protected RemoteOperationResult run(OwnCloudClient client) {
 
         RemoteOperationResult result = null;
         mTransferWasRequested = false;
+        
+        // Get local file from the DB
+        mLocalFile = getStorageManager().getFileByPath(mRemotePath);
+        
         if (!mLocalFile.isDown()) {
             /// easy decision
             requestForDownload(mLocalFile);
@@ -135,7 +148,7 @@ public class SynchronizeFileOperation extends RemoteOperation {
                         mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
                         mServerFile.setStoragePath(mLocalFile.getStoragePath());
                         mServerFile.setParentId(mLocalFile.getParentId());
-                        mStorageManager.saveFile(mServerFile);
+                        getStorageManager().saveFile(mServerFile);
 
                     }
                     result = new RemoteOperationResult(ResultCode.OK);

+ 4 - 4
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -350,11 +350,11 @@ public class SynchronizeFolderOperation extends RemoteOperation {
             if (remoteFile.keepInSync()) {
                 SynchronizeFileOperation operation = new SynchronizeFileOperation(  localFile,        
                                                                                     remoteFile, 
-                                                                                    mStorageManager,
-                                                                                    mAccount,       
+                                                                                    mAccount, 
                                                                                     true, 
                                                                                     mContext
                                                                                     );
+                
                 filesToSyncContents.add(operation);
             }
             
@@ -382,7 +382,7 @@ public class SynchronizeFolderOperation extends RemoteOperation {
     private void startContentSynchronizations(List<SynchronizeFileOperation> filesToSyncContents, OwnCloudClient client) {
         RemoteOperationResult contentsResult = null;
         for (SynchronizeFileOperation op: filesToSyncContents) {
-            contentsResult = op.execute(client);   // returns without waiting for upload or download finishes
+            contentsResult = op.execute(mStorageManager, mContext);   // returns without waiting for upload or download finishes
             if (!contentsResult.isSuccess()) {
                 if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) {
                     mConflictsFound++;

+ 3 - 0
src/com/owncloud/android/providers/FileContentProvider.java

@@ -99,6 +99,8 @@ public class FileContentProvider extends ContentProvider {
     private static final int DIRECTORY = 2;
     private static final int ROOT_DIRECTORY = 3;
     private static final int SHARES = 4;
+
+    private static final String TAG = FileContentProvider.class.getSimpleName();
     
     // Projection for ocshares table
     private static HashMap<String, String> mOCSharesProjectionMap;
@@ -414,6 +416,7 @@ public class FileContentProvider extends ContentProvider {
         // DB case_sensitive
         db.execSQL("PRAGMA case_sensitive_like = true");
         Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
+        Log_OC.d(TAG, "setting notification URI: " + uri);
         c.setNotificationUri(getContext().getContentResolver(), uri);
         return c;
     }

+ 50 - 12
src/com/owncloud/android/services/OperationsService.java

@@ -34,9 +34,13 @@ import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
 import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
 import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.CreateShareOperation;
 import com.owncloud.android.operations.GetServerInfoOperation;
 import com.owncloud.android.operations.OAuth2GetAccessToken;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.RenameFileOperation;
+import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.utils.Log_OC;
 
@@ -64,6 +68,10 @@ public class OperationsService extends Service {
     public static final String EXTRA_OAUTH2_QUERY_PARAMETERS = "OAUTH2_QUERY_PARAMETERS";
     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
     public static final String EXTRA_SEND_INTENT = "SEND_INTENT";
+    public static final String EXTRA_NEWNAME = "NEWNAME";
+    public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY";
+    public static final String EXTRA_CREATE_FULL_PATH = "CREATE_FULL_PATH";
+    public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
     public static final String EXTRA_RESULT = "RESULT";
     
     // TODO review if ALL OF THEM are necessary
@@ -81,17 +89,16 @@ public class OperationsService extends Service {
     public static final String ACTION_OAUTH2_GET_ACCESS_TOKEN = "OAUTH2_GET_ACCESS_TOKEN";
     public static final String ACTION_EXISTENCE_CHECK = "EXISTENCE_CHECK";
     public static final String ACTION_GET_USER_NAME = "GET_USER_NAME";
+    public static final String ACTION_RENAME = "RENAME";
+    public static final String ACTION_REMOVE = "REMOVE";
+    public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER";
+    public static final String ACTION_SYNC_FILE = "SYNC_FILE";
     
     public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
     public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED";
 
     private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations = 
             new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
-    
-    /*
-    private ConcurrentMap<Integer, RemoteOperationResult> mOperationResults =
-            new ConcurrentHashMap<Integer, RemoteOperationResult>();
-     */
 
     private ConcurrentMap<Integer, Pair<RemoteOperation, RemoteOperationResult>> 
         mUndispatchedFinishedOperations =
@@ -165,10 +172,10 @@ public class OperationsService extends Service {
     @Override
     public void onDestroy() {
         //Log_OC.wtf(TAG, "onDestroy init" );
-        super.onDestroy();
         //Log_OC.wtf(TAG, "Clear mUndispatchedFinisiedOperations" );
         mUndispatchedFinishedOperations.clear();
         //Log_OC.wtf(TAG, "onDestroy end" );
+        super.onDestroy();
     }
 
 
@@ -335,7 +342,32 @@ public class OperationsService extends Service {
                     } else if (action.equals(ACTION_GET_USER_NAME)) {
                         // Get User Name
                         operation = new GetRemoteUserNameOperation();
+                        
+                    } else if (action.equals(ACTION_RENAME)) {
+                        // Rename file or folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        String newName = operationIntent.getStringExtra(EXTRA_NEWNAME);
+                        operation = new RenameFileOperation(remotePath, account, newName);
+                        
+                    } else if (action.equals(ACTION_REMOVE)) {
+                        // Remove file or folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean onlyLocalCopy = operationIntent.getBooleanExtra(EXTRA_REMOVE_ONLY_LOCAL, false);
+                        operation = new RemoveFileOperation(remotePath, onlyLocalCopy);
+                        
+                    } else if (action.equals(ACTION_CREATE_FOLDER)) {
+                        // Create Folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean createFullPath = operationIntent.getBooleanExtra(EXTRA_CREATE_FULL_PATH, true);
+                        operation = new CreateFolderOperation(remotePath, createFullPath);
+                        
+                    } else if (action.equals(ACTION_SYNC_FILE)) {
+                        // Sync file
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        boolean syncFileContents = operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true);
+                        operation = new SynchronizeFileOperation(remotePath, account, syncFileContents, getApplicationContext());
                     }
+                    
                 }
                     
             } catch (IllegalArgumentException e) {
@@ -356,13 +388,19 @@ public class OperationsService extends Service {
             }
         }
 
-        public void dispatchResultIfFinished(int operationId, OnRemoteOperationListener listener) {
+        public boolean dispatchResultIfFinished(int operationId, OnRemoteOperationListener listener) {
             Pair<RemoteOperation, RemoteOperationResult> undispatched = 
                     mUndispatchedFinishedOperations.remove(operationId);
             if (undispatched != null) {
                 listener.onRemoteOperationFinish(undispatched.first, undispatched.second);
+                return true;
                 //Log_OC.wtf(TAG, "Sending callback later");
             } else {
+                if (!mPendingOperations.isEmpty()) {
+                    return true;
+                } else {
+                    return false;
+                }
                 //Log_OC.wtf(TAG, "Not finished yet");
             }
         }
@@ -440,20 +478,20 @@ public class OperationsService extends Service {
                 } else {
                     result = mCurrentOperation.execute(mOwnCloudClient);
                 }
-            
+                
             } catch (AccountsException e) {
                 if (mLastTarget.mAccount == null) {
-                    Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e);
+                    Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
                 } else {
-                    Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e);
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
                 }
                 result = new RemoteOperationResult(e);
                 
             } catch (IOException e) {
                 if (mLastTarget.mAccount == null) {
-                    Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e);
+                    Log_OC.e(TAG, "Error while trying to get authorization for a NULL account", e);
                 } else {
-                    Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e);
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mLastTarget.mAccount.name, e);
                 }
                 result = new RemoteOperationResult(e);
             } catch (Exception e) {

+ 1 - 1
src/com/owncloud/android/ui/activity/AccountSelectActivity.java

@@ -89,7 +89,6 @@ public class AccountSelectActivity extends SherlockListActivity implements
     
     @Override
     protected void onPause() {
-        super.onPause();
         if (this.isFinishing()) {
             Account current = AccountUtils.getCurrentOwnCloudAccount(this);
             if ((mPreviousAccount == null && current != null) || 
@@ -102,6 +101,7 @@ public class AccountSelectActivity extends SherlockListActivity implements
                 startActivity(i);
             }
         }
+        super.onPause();
     }
 
     @Override

+ 8 - 1
src/com/owncloud/android/ui/activity/TransferServiceGetter.java → src/com/owncloud/android/ui/activity/ComponentsGetter.java

@@ -18,10 +18,12 @@
 
 package com.owncloud.android.ui.activity;
 
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.files.FileOperationsHelper;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 
-public interface TransferServiceGetter {
+public interface ComponentsGetter {
 
     /**
      * Callback method invoked when the parent activity is fully created to get a reference to the FileDownloader service API.
@@ -38,5 +40,10 @@ public interface TransferServiceGetter {
      */
     public FileUploaderBinder getFileUploaderBinder();
 
+    
+    
+    public FileDataStorageManager getStorageManager();
+    
+    public FileOperationsHelper getFileOperationsHelper();
 
 }

+ 106 - 16
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -22,6 +22,7 @@ import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -39,9 +40,14 @@ import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -60,7 +66,8 @@ import com.owncloud.android.utils.Log_OC;
  * 
  * @author David A. Velasco
  */
-public class FileActivity extends SherlockFragmentActivity implements OnRemoteOperationListener {
+public class FileActivity extends SherlockFragmentActivity 
+implements OnRemoteOperationListener, ComponentsGetter {
 
     public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
     public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
@@ -70,6 +77,7 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     public static final String TAG = FileActivity.class.getSimpleName();
     
     private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
+    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";;
     
     
     /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
@@ -101,7 +109,11 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     private ServiceConnection mOperationsServiceConnection = null;
     
     private OperationsServiceBinder mOperationsServiceBinder = null;
-
+    
+    protected FileDownloaderBinder mDownloaderBinder = null;
+    protected FileUploaderBinder mUploaderBinder = null;
+    private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
+    
     
     /**
      * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of 
@@ -114,12 +126,15 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mHandler = new Handler();
-        mFileOperationsHelper = new FileOperationsHelper();
+        mFileOperationsHelper = new FileOperationsHelper(this);
         Account account;
         if(savedInstanceState != null) {
             account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
             mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
             mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
+            mFileOperationsHelper.setOpIdWaitingFor(
+                    savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
+                    );
         } else {
             account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
             mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
@@ -130,6 +145,16 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
         
         mOperationsServiceConnection = new OperationsServiceConnection();
         bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);
+        
+        mDownloadServiceConnection = newTransferenceServiceConnection();
+        if (mDownloadServiceConnection != null) {
+            bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
+        }
+        mUploadServiceConnection = newTransferenceServiceConnection();
+        if (mUploadServiceConnection != null) {
+            bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, Context.BIND_AUTO_CREATE);
+        }
+        
     }
 
     
@@ -155,30 +180,43 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
         if (mAccountWasSet) {
             onAccountSet(mAccountWasRestored);
         }
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+        
         if (mOperationsServiceBinder != null) {
-            mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
+            doOnResumeAndBound();
         }
+
     }
     
-    
-    @Override 
-    protected void onStop() {
-
+    @Override
+    protected void onPause()  {
         if (mOperationsServiceBinder != null) {
             mOperationsServiceBinder.removeOperationListener(this);
         }
         
-        super.onStop();
+        super.onPause();
     }
     
     
     @Override
     protected void onDestroy() {
-        super.onDestroy();
         if (mOperationsServiceConnection != null) {
             unbindService(mOperationsServiceConnection);
             mOperationsServiceBinder = null;
         }
+        if (mDownloadServiceConnection != null) {
+            unbindService(mDownloadServiceConnection);
+            mDownloadServiceConnection = null;
+        }
+        if (mUploadServiceConnection != null) {
+            unbindService(mUploadServiceConnection);
+            mUploadServiceConnection = null;
+        }
+        super.onDestroy();
     }
     
     
@@ -258,6 +296,7 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
         outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
         outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
         outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
+        outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
     }
     
     
@@ -308,7 +347,11 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     public OperationsServiceBinder getOperationsServiceBinder() {
         return mOperationsServiceBinder;
     }
-
+    
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return null;
+    }
+    
 
     /**
      * Helper class handling a callback from the {@link AccountManager} after the creation of
@@ -393,7 +436,18 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     @Override
     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
         Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the FileActivities ");
-        if (operation instanceof CreateShareOperation) {
+        
+        mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
+        
+        if (!result.isSuccess() && (
+                result.getCode() == ResultCode.UNAUTHORIZED || 
+                result.isIdPRedirection() ||
+                (result.isException() && result.getException() instanceof AuthenticatorException)
+                )) {
+            
+            requestCredentialsUpdate();
+
+        } else if (operation instanceof CreateShareOperation) {
             onCreateShareOperationFinish((CreateShareOperation) operation, result);
             
         } else if (operation instanceof UnshareLinkOperation) {
@@ -402,6 +456,17 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
         } 
     }
 
+    private void requestCredentialsUpdate() {
+        Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+        updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
+        updateAccountCredentials.putExtra(
+                AuthenticatorActivity.EXTRA_ACTION, 
+                AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+        updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        startActivity(updateAccountCredentials);
+    }
+    
+
     private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
         dismissLoadingDialog();
         if (result.isSuccess()) {
@@ -471,6 +536,18 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
     }
 
     
+    private void doOnResumeAndBound() {
+        mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
+        long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
+        if (waitingForOpId <= Integer.MAX_VALUE) {
+            boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId, this);
+            if (!wait ) {
+                dismissLoadingDialog();
+            }
+        }
+    }
+
+
     /** 
      * Implements callback methods for service binding. Passed as a parameter to { 
      */
@@ -481,10 +558,10 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
             if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
                 Log_OC.d(TAG, "Operations service connected");
                 mOperationsServiceBinder = (OperationsServiceBinder) service;
-                mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
-                if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
+                /*if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
                     dismissLoadingDialog();
-                }
+                }*/
+                doOnResumeAndBound();
 
             } else {
                 return;
@@ -500,6 +577,19 @@ public class FileActivity extends SherlockFragmentActivity implements OnRemoteOp
                 // TODO whatever could be waiting for the service is unbound
             }
         }
+    }
+
+
+    @Override
+    public FileDownloaderBinder getFileDownloaderBinder() {
+        return mDownloaderBinder;
+    }
+
+
+    @Override
+    public FileUploaderBinder getFileUploaderBinder() {
+        return mUploaderBinder;
     };    
     
+    
 }

+ 185 - 247
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -1,6 +1,6 @@
 /* ownCloud Android client application
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -78,16 +78,15 @@ import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
-import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.syncadapter.FileSyncAdapter;
-import com.owncloud.android.ui.dialog.EditNameDialog;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
 import com.owncloud.android.ui.preview.PreviewVideoActivity;
 import com.owncloud.android.utils.DisplayUtils;
@@ -102,17 +101,13 @@ import com.owncloud.android.utils.Log_OC;
  */
 
 public class FileDisplayActivity extends HookActivity implements
-OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener, EditNameDialogListener {
+FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener {
 
     private ArrayAdapter<String> mDirectories;
 
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
-    //private OperationsServiceReceiver mOperationsServiceReceiver;
-    private FileDownloaderBinder mDownloaderBinder = null;
-    private FileUploaderBinder mUploaderBinder = null;
-    private ServiceConnection mDownloadConnection = null, mUploadConnection = null;
     private RemoteOperationResult mLastSslUntrustedServerResult = null;
 
     private boolean mDualPane;
@@ -121,12 +116,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
     private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
     private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
-    //private static final String KEY_REFRESH_SHARES_IN_PROGRESS = "SHARES_IN_PROGRESS";
     private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
 
     public static final int DIALOG_SHORT_WAIT = 0;
     private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1;
-    //private static final int DIALOG_SSL_VALIDATOR = 2;
     private static final int DIALOG_CERT_NOT_SAVED = 2;
     
     public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";
@@ -142,7 +135,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private OCFile mWaitingToPreview;
     
     private boolean mSyncInProgress = false;
-    //private boolean mRefreshSharesInProgress = false;
 
     private String DIALOG_UNTRUSTED_CERT;
     
@@ -155,12 +147,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
         super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid
 
-        /// bindings to transference services
-        mUploadConnection = new ListServiceConnection(); 
-        mDownloadConnection = new ListServiceConnection();
-        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
-        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
-
         // PIN CODE request ;  best location is to decide, let's try this first
         if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
             requestPinCode();
@@ -177,13 +163,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         if(savedInstanceState != null) {
             mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW);
             mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS);
-            //mRefreshSharesInProgress = savedInstanceState.getBoolean(KEY_REFRESH_SHARES_IN_PROGRESS);
             mWaitingToSend = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND);
            
         } else {
             mWaitingToPreview = null;
             mSyncInProgress = false;
-            //mRefreshSharesInProgress = false;
             mWaitingToSend = null;
         }        
 
@@ -215,16 +199,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     protected void onStart() {
         super.onStart();
         getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
-        refeshListOfFilesFragment();
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        if (mDownloadConnection != null)
-            unbindService(mDownloadConnection);
-        if (mUploadConnection != null)
-            unbindService(mUploadConnection);
     }
 
     /**
@@ -397,7 +376,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         return null;
     }
 
-    protected FileFragment getSecondFragment() {
+    public FileFragment getSecondFragment() {
         Fragment second = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_SECOND_FRAGMENT);
         if (second != null) {
             return (FileFragment)second;
@@ -405,7 +384,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         return null;
     }
 
-    public void cleanSecondFragment() {
+    protected void cleanSecondFragment() {
         Fragment second = getSecondFragment();
         if (second != null) {
             FragmentTransaction tr = getSupportFragmentManager().beginTransaction();
@@ -416,7 +395,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         updateNavigationElementsInActionBar(null);
     }
 
-    protected void refeshListOfFilesFragment() {
+    protected void refreshListOfFilesFragment() {
         OCFileListFragment fileListFragment = getListOfFilesFragment();
         if (fileListFragment != null) { 
             fileListFragment.listDirectory();
@@ -448,7 +427,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                             startMediaPreview(mWaitingToPreview, 0, true);
                             detailsFragmentChanged = true;
                         } else {
-                            getFileOperationsHelper().openFile(mWaitingToPreview, this);
+                            getFileOperationsHelper().openFile(mWaitingToPreview);
                         }
                     }
                     mWaitingToPreview = null;
@@ -472,7 +451,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         boolean retval = true;
         switch (item.getItemId()) {
         case R.id.action_create_dir: {
-            EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", -1, -1, this);
+            CreateFolderDialogFragment dialog = 
+                    CreateFolderDialogFragment.newInstance(getCurrentDir());
             dialog.show(getSupportFragmentManager(), "createdirdialog");
             break;
         }
@@ -685,11 +665,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     protected void onResume() {
         super.onResume();
         Log_OC.e(TAG, "onResume() start");
+        
+        // refresh list of files
+        refreshListOfFilesFragment();
 
         // Listen for sync messages
         IntentFilter syncIntentFilter = new IntentFilter(FileSyncAdapter.EVENT_FULL_SYNC_START);
         syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_END);
-        //syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED);
         syncIntentFilter.addAction(FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED);
         syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
         syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
@@ -708,21 +690,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
         
-        // Listen for messages from the OperationsService
-        /*
-        IntentFilter operationsIntentFilter = new IntentFilter(OperationsService.ACTION_OPERATION_ADDED);
-        operationsIntentFilter.addAction(OperationsService.ACTION_OPERATION_FINISHED);
-        mOperationsServiceReceiver = new OperationsServiceReceiver();
-        LocalBroadcastManager.getInstance(this).registerReceiver(mOperationsServiceReceiver, operationsIntentFilter);
-        */
-    
         Log_OC.d(TAG, "onResume() end");
     }
 
 
     @Override
     protected void onPause() {
-        super.onPause();
         Log_OC.e(TAG, "onPause() start");
         if (mSyncBroadcastReceiver != null) {
             unregisterReceiver(mSyncBroadcastReceiver);
@@ -737,13 +710,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             unregisterReceiver(mDownloadFinishReceiver);
             mDownloadFinishReceiver = null;
         }
-        /*
-        if (mOperationsServiceReceiver != null) {
-            LocalBroadcastManager.getInstance(this).unregisterReceiver(mOperationsServiceReceiver);
-            mOperationsServiceReceiver = null;
-        }
-        */
+        
+        
         Log_OC.d(TAG, "onPause() end");
+        super.onPause();
     }
 
 
@@ -940,7 +910,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                                 cleanSecondFragment();
                                 currentFile = currentDir;
                             }
-                        
+
                             if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
                                 OCFileListFragment fileListFragment = getListOfFilesFragment();
                                 if (fileListFragment != null) {
@@ -952,19 +922,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                         
                         mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
                                 
-                        /*
-                        if (synchResult != null && 
-                            synchResult.isSuccess() &&
-                                (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SYNCED.equals(event) || 
-                                    FileSyncAdapter.EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED.equals(event)
-                                ) &&
-                                !mRefreshSharesInProgress &&
-                                getFileOperationsHelper().isSharedSupported(FileDisplayActivity.this)
-                            ) {
-                            startGetShares();
-                        }
-                        */
-                            
                         }
                         removeStickyBroadcast(intent);
                         Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
@@ -985,6 +942,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
     
 
+    /**
+     * Once the file upload has finished -> update view
+     */
     private class UploadFinishReceiver extends BroadcastReceiver {
         /**
          * Once the file upload has finished -> update view
@@ -997,12 +957,52 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
             boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name);
             OCFile currentDir = getCurrentDir();
-            boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
+            boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && 
+                    (uploadedRemotePath.startsWith(currentDir.getRemotePath()));
+            
             if (sameAccount && isDescendant) {
-                refeshListOfFilesFragment();
+                refreshListOfFilesFragment();
             }
+            
+            boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
+            boolean renamedInUpload = getFile().getRemotePath().
+                    equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
+            boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) || 
+                    renamedInUpload;
+            FileFragment details = getSecondFragment();
+            boolean detailFragmentIsShown = (details != null && 
+                    details instanceof FileDetailFragment);
+            
+            if (sameAccount && sameFile && detailFragmentIsShown) {
+                if (uploadWasFine) {
+                    setFile(getStorageManager().getFileByPath(uploadedRemotePath));
+                }
+                if (renamedInUpload) {
+                    String newName = (new File(uploadedRemotePath)).getName();
+                    Toast msg = Toast.makeText(
+                            context, 
+                            String.format(
+                                    getString(R.string.filedetails_renamed_in_upload_msg), 
+                                    newName), 
+                            Toast.LENGTH_LONG);
+                    msg.show();
+                }
+                if (uploadWasFine || getFile().fileExists()) {
+                    ((FileDetailFragment)details).updateFileDetails(false, true);
+                } else {
+                    cleanSecondFragment();
+                }
+                
+                // Force the preview if the file is an image
+                if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
+                    startImagePreview(getFile());
+                } // TODO what about other kind of previews?
+            }
+        
+            removeStickyBroadcast(intent);
+            
         }
-
+        
     }
 
 
@@ -1020,7 +1020,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             boolean isDescendant = isDescendant(downloadedRemotePath);
 
             if (sameAccount && isDescendant) {
-                refeshListOfFilesFragment();
+                refreshListOfFilesFragment();
                 refreshSecondFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
             }
 
@@ -1046,44 +1046,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
     
     
-    /**
-     * Class waiting for broadcast events from the {@link OperationsService}.
-     * 
-     * Updates the list of files when a get for shares is finished; at this moment the refresh of shares is the only
-     * operation performed in {@link OperationsService}.
-     * 
-     * In the future will handle the progress or finalization of all the operations performed in {@link OperationsService}, 
-     * probably all the operations associated to the app model. 
-     */
-    private class OperationsServiceReceiver extends BroadcastReceiver {
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (OperationsService.ACTION_OPERATION_ADDED.equals(intent.getAction())) {
-                
-            } else if (OperationsService.ACTION_OPERATION_FINISHED.equals(intent.getAction())) {
-                //mRefreshSharesInProgress = false;
-                
-                Account account = intent.getParcelableExtra(OperationsService.EXTRA_ACCOUNT);
-                RemoteOperationResult getSharesResult = (RemoteOperationResult)intent.getSerializableExtra(OperationsService.EXTRA_RESULT);
-                if (getAccount() != null && account.name.equals(getAccount().name)
-                        && getStorageManager() != null
-                        ) {
-                    refeshListOfFilesFragment();
-                }
-                if ((getSharesResult != null) &&
-                        RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(getSharesResult.getCode())) {
-                    mLastSslUntrustedServerResult = getSharesResult;
-                    showUntrustedCertDialog(mLastSslUntrustedServerResult);
-                }
-
-                //setSupportProgressBarIndeterminateVisibility(mRefreshSharesInProgress || mSyncInProgress);
-            }
-            
-        }
-            
-    }
-
     public void browseToRoot() {
         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
         if (listOfFiles != null) {  // should never be null, indeed
@@ -1131,54 +1093,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         
     }
 
-    /**
-     * Opens the image gallery showing the image {@link OCFile} received as parameter.
-     * 
-     * @param file                      Image {@link OCFile} to show.
-     */
-    @Override
-    public void startImagePreview(OCFile file) {
-        Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-        showDetailsIntent.putExtra(EXTRA_FILE, file);
-        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
-        startActivity(showDetailsIntent);
-    }
-
-    /**
-     * Stars the preview of an already down media {@link OCFile}.
-     * 
-     * @param file                      Media {@link OCFile} to preview.
-     * @param startPlaybackPosition     Media position where the playback will be started, in milliseconds.
-     * @param autoplay                  When 'true', the playback will start without user interactions.
-     */
-    @Override
-    public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
-        Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
-        setSecondFragment(mediaFragment);
-        updateFragmentsVisibility(true);
-        updateNavigationElementsInActionBar(file);
-        setFile(file);
-    }
-
-    /**
-     * Requests the download of the received {@link OCFile} , updates the UI
-     * to monitor the download progress and prepares the activity to preview
-     * or open the file when the download finishes.
-     * 
-     * @param file          {@link OCFile} to download and preview.
-     */
-    @Override
-    public void startDownloadForPreview(OCFile file) {
-        Fragment detailFragment = new FileDetailFragment(file, getAccount());
-        setSecondFragment(detailFragment);
-        mWaitingToPreview = file;
-        requestForDownload();
-        updateFragmentsVisibility(true);
-        updateNavigationElementsInActionBar(file);
-        setFile(file);
-    }
-
-
     /**
      * Shows the information of the {@link OCFile} received as a 
      * parameter in the second fragment.
@@ -1221,34 +1135,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFileStateChanged() {
-        refeshListOfFilesFragment();
-        updateNavigationElementsInActionBar(getSecondFragment().getFile());
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDownloaderBinder getFileDownloaderBinder() {
-        return mDownloaderBinder;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public FileUploaderBinder getFileUploaderBinder() {
-        return mUploaderBinder;
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return new ListServiceConnection();
     }
 
-
     /** Defines callbacks for service binding, passed to bindService() */
     private class ListServiceConnection implements ServiceConnection {
 
@@ -1257,8 +1148,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
                 Log_OC.d(TAG, "Download service connected");
                 mDownloaderBinder = (FileDownloaderBinder) service;
-                if (mWaitingToPreview != null) {
-                    requestForDownload();
+                if (mWaitingToPreview != null)
+                    if (getStorageManager() != null) {
+                        mWaitingToPreview = getStorageManager().getFileById(mWaitingToPreview.getFileId()); // update the file
+                        if (!mWaitingToPreview.isDown()) {
+                            requestForDownload();
+                        }
                 }
 
             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
@@ -1362,7 +1257,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
             refreshShowDetails();
-            refeshListOfFilesFragment();
+            refreshListOfFilesFragment();
         }
     }
 
@@ -1370,10 +1265,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
             refreshShowDetails();
-            refeshListOfFilesFragment();
+            refreshListOfFilesFragment();
+            
         } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
             cleanSecondFragment();
-            refeshListOfFilesFragment();
+            refreshListOfFilesFragment();
         }
     }
     
@@ -1407,15 +1303,18 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);
             msg.show();
             OCFile removedFile = operation.getFile();
-            getSecondFragment();
             FileFragment second = getSecondFragment();
             if (second != null && removedFile.equals(second.getFile())) {
+                if (second instanceof PreviewMediaFragment) {
+                    ((PreviewMediaFragment)second).stopPreview(true);
+                }
+                setFile(getStorageManager().getFileById(removedFile.getParentId()));
                 cleanSecondFragment();
             }
             if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) {
-                refeshListOfFilesFragment();
+                refreshListOfFilesFragment();
             }
-
+            invalidateOptionsMenu();
         } else {
             Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); 
             msg.show();
@@ -1425,7 +1324,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             }
         }
     }
-
+    
+    
     /**
      * Updates the view associated to the activity after the finish of an operation trying create a new folder
      * 
@@ -1435,8 +1335,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
             dismissLoadingDialog();
-            refeshListOfFilesFragment();
-
+            refreshListOfFilesFragment();
         } else {
             dismissLoadingDialog();
             if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) {
@@ -1465,14 +1364,25 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         dismissLoadingDialog();
         OCFile renamedFile = operation.getFile();
         if (result.isSuccess()) {
-            if (mDualPane) {
-                FileFragment details = getSecondFragment();
-                if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+            FileFragment details = getSecondFragment();
+            if (details != null) {
+                if (details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
                     ((FileDetailFragment) details).updateFileDetails(renamedFile, getAccount());
+                    showDetails(renamedFile);
+
+                } else if (details instanceof PreviewMediaFragment && renamedFile.equals(details.getFile())) {
+                    ((PreviewMediaFragment) details).updateFile(renamedFile);
+                    if (PreviewMediaFragment.canBePreviewed(renamedFile)) {
+                        int position = ((PreviewMediaFragment)details).getPosition();
+                        startMediaPreview(renamedFile, position, true);
+                    } else {
+                        getFileOperationsHelper().openFile(renamedFile);
+                    }
                 }
             }
+            
             if (getStorageManager().getFileById(renamedFile.getParentId()).equals(getCurrentDir())) {
-                refeshListOfFilesFragment();
+                refreshListOfFilesFragment();
             }
 
         } else {
@@ -1494,7 +1404,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         }
     }
 
-
     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
         dismissLoadingDialog();
         OCFile syncedFile = operation.getLocalFile();
@@ -1506,12 +1415,11 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 startActivity(i);
 
             } 
-
+            
         } else {
             if (operation.transferWasRequested()) {
-                refeshListOfFilesFragment();
                 onTransferStateChanged(syncedFile, true, true);
-
+                
             } else {
                 Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
                 msg.show();
@@ -1519,44 +1427,26 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         }
     }
 
-
+    
     /**
      * {@inheritDoc}
      */
     @Override
     public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
-        if (mDualPane) {
-            FileFragment details = getSecondFragment();
-            if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
-                if (downloading || uploading) {
-                    ((FileDetailFragment)details).updateFileDetails(file, getAccount());
+        refreshListOfFilesFragment();
+        FileFragment details = getSecondFragment();
+        if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
+            if (downloading || uploading) {
+                ((FileDetailFragment)details).updateFileDetails(file, getAccount());
+            } else {
+                if (!file.fileExists()) {
+                    cleanSecondFragment();
                 } else {
                     ((FileDetailFragment)details).updateFileDetails(false, true);
                 }
             }
         }
-    }
-
-
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newDirectoryName = dialog.getNewFilename().trim();
-            Log_OC.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
-            if (newDirectoryName.length() > 0) {
-                String path = getCurrentDir().getRemotePath();
-
-                // Create directory
-                path += newDirectoryName + OCFile.PATH_SEPARATOR;
-                RemoteOperation operation = new CreateFolderOperation(path, false, getStorageManager());
-                operation.execute(  getAccount(), 
-                        FileDisplayActivity.this, 
-                        FileDisplayActivity.this, 
-                        getHandler(),
-                        FileDisplayActivity.this);
-
-                showLoadingDialog();
-            }
-        }
+            
     }
 
 
@@ -1593,7 +1483,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,  
                                                                         currentSyncTime, 
                                                                         false,
-                                                                        getFileOperationsHelper().isSharedSupported(this),
+                                                                        getFileOperationsHelper().isSharedSupported(),
                                                                         getStorageManager(), 
                                                                         getAccount(), 
                                                                         getApplicationContext()
@@ -1603,17 +1493,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         setSupportProgressBarIndeterminateVisibility(true);
     }
 
-    /*
-    private void startGetShares() {
-        // Get shared files/folders
-        Intent intent = new Intent(this, OperationsService.class);
-        intent.putExtra(OperationsService.EXTRA_ACCOUNT, getAccount());
-        startService(intent);
-        
-        mRefreshSharesInProgress = true;
-    }
-    */
-    
     /**
      * Show untrusted cert dialog 
      */
@@ -1625,6 +1504,22 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         dialog.show(ft, DIALOG_UNTRUSTED_CERT);
     }
     
+    private void requestForDownload(OCFile file) {
+        Account account = getAccount();
+        if (!mDownloaderBinder.isDownloading(account, file)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
+            i.putExtra(FileDownloader.EXTRA_FILE, file);
+            startService(i);
+        }
+    }
+    
+    private void sendDownloadedFile(){
+        getFileOperationsHelper().sendDownloadedFile(mWaitingToSend);
+        mWaitingToSend = null;
+    }
+
+    
     /**
      * Requests the download of the received {@link OCFile} , updates the UI
      * to monitor the download progress and prepares the activity to send the file
@@ -1632,7 +1527,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
      * 
      * @param file          {@link OCFile} to download and preview.
      */
-    @Override
     public void startDownloadForSending(OCFile file) {
         mWaitingToSend = file;
         requestForDownload(mWaitingToSend);
@@ -1640,19 +1534,63 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         updateFragmentsVisibility(hasSecondFragment);
     }
     
-    private void requestForDownload(OCFile file) {
-        Account account = getAccount();
-        if (!mDownloaderBinder.isDownloading(account, file)) {
-            Intent i = new Intent(this, FileDownloader.class);
-            i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
-            i.putExtra(FileDownloader.EXTRA_FILE, file);
-            startService(i);
-        }
+    /**
+     * Opens the image gallery showing the image {@link OCFile} received as parameter.
+     * 
+     * @param file                      Image {@link OCFile} to show.
+     */
+    public void startImagePreview(OCFile file) {
+        Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+        showDetailsIntent.putExtra(EXTRA_FILE, file);
+        showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount());
+        startActivity(showDetailsIntent);
+        
     }
-    
-    private void sendDownloadedFile(){
-        getFileOperationsHelper().sendDownloadedFile(mWaitingToSend, this);
-        mWaitingToSend = null;
+
+    /**
+     * Stars the preview of an already down media {@link OCFile}.
+     * 
+     * @param file                      Media {@link OCFile} to preview.
+     * @param startPlaybackPosition     Media position where the playback will be started, in milliseconds.
+     * @param autoplay                  When 'true', the playback will start without user interactions.
+     */
+    public void startMediaPreview(OCFile file, int startPlaybackPosition, boolean autoplay) {
+        Fragment mediaFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay);
+        setSecondFragment(mediaFragment);
+        updateFragmentsVisibility(true);
+        updateNavigationElementsInActionBar(file);
+        setFile(file);
+    }
+
+    /**
+     * Requests the download of the received {@link OCFile} , updates the UI
+     * to monitor the download progress and prepares the activity to preview
+     * or open the file when the download finishes.
+     * 
+     * @param file          {@link OCFile} to download and preview.
+     */
+    public void startDownloadForPreview(OCFile file) {
+        Fragment detailFragment = new FileDetailFragment(file, getAccount());
+        setSecondFragment(detailFragment);
+        mWaitingToPreview = file;
+        requestForDownload();
+        updateFragmentsVisibility(true);
+        updateNavigationElementsInActionBar(file);
+        setFile(file);
+    }
+
+
+    public void cancelTransference(OCFile file) {
+        getFileOperationsHelper().cancelTransference(file);
+        if (mWaitingToPreview != null && 
+                mWaitingToPreview.getRemotePath().equals(file.getRemotePath())) {
+            mWaitingToPreview = null;
+        }
+        if (mWaitingToSend != null &&
+                mWaitingToSend.getRemotePath().equals(file.getRemotePath())) {
+            mWaitingToSend = null;
+        }
+        onTransferStateChanged(file, false, false);
     }
     
 }

+ 1 - 1
src/com/owncloud/android/ui/activity/Preferences.java

@@ -261,10 +261,10 @@ public class Preferences extends SherlockPreferenceActivity {
 
     @Override
     protected void onResume() {
+        super.onResume();
         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
         boolean state = appPrefs.getBoolean("set_pincode", false);
         pCode.setChecked(state);
-        super.onResume();
     }
 
     @Override

+ 2 - 2
src/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -36,10 +36,10 @@ import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.R;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 import com.owncloud.android.ui.fragment.LocalFileListFragment;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.Log_OC;

+ 8 - 7
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -18,7 +18,7 @@
 package com.owncloud.android.ui.adapter;
 
 import android.accounts.Account;
-import android.content.Context;
+import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -37,7 +37,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.ui.activity.TransferServiceGetter;
+import com.owncloud.android.ui.activity.ComponentsGetter;
 import com.owncloud.android.utils.DisplayUtils;
 
 
@@ -52,15 +52,16 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
     private Context mContext;
     private OCFile mFile = null;
     private Vector<OCFile> mFiles = null;
-    private FileDataStorageManager mStorageManager;
-    private Account mAccount;
-    private TransferServiceGetter mTransferServiceGetter;
+
+    private FileDataStorageManager mStorageManager;
+    private Account mAccount;
+    private ComponentsGetter mTransferServiceGetter;
     
-    public FileListListAdapter(Context context, TransferServiceGetter transferServiceGetter) {
+    public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) {
         mContext = context;
         mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
         mTransferServiceGetter = transferServiceGetter;
-    }
+    }
 
     @Override
     public boolean areAllItemsEnabled() {

+ 1 - 1
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java → src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java

@@ -16,7 +16,7 @@
  *
  */
 
-package com.owncloud.android.ui.fragment;
+package com.owncloud.android.ui.dialog;
 
 import android.app.AlertDialog;
 import android.app.Dialog;

+ 122 - 0
src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java

@@ -0,0 +1,122 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ *  Dialog to input the name for a new folder to create.  
+ * 
+ *  Triggers the folder creation when name is confirmed. 
+ *  
+ *  @author David A. Velasco
+ */
+public class CreateFolderDialogFragment 
+extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+
+    private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
+
+    /**
+     * Public factory method to create new CreateFolderDialogFragment instances.
+     * 
+     * @param file            File to remove.
+     * @return                Dialog ready to show.
+     */
+    public static CreateFolderDialogFragment newInstance(OCFile parentFolder) {
+        CreateFolderDialogFragment frag = new CreateFolderDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_PARENT_FOLDER, parentFolder);
+        frag.setArguments(args);
+        return frag;
+        
+    }
+
+    private OCFile mParentFolder;
+    
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mParentFolder = getArguments().getParcelable(ARG_PARENT_FOLDER);
+        
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.edit_box_dialog, null);
+        
+        // Setup layout 
+        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
+        inputText.setText("");
+        inputText.requestFocus();
+        
+        // Build the dialog  
+        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this)
+               .setTitle(R.string.uploader_info_dirname);
+        Dialog d = builder.create();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }    
+    
+    
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            String newFolderName = 
+                    ((TextView)(getDialog().findViewById(R.id.user_input)))
+                        .getText().toString().trim();
+            
+            if (newFolderName.length() <= 0) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_empty, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            if (!FileUtils.isValidName(newFolderName)) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_forbidden_characters, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            String path = mParentFolder.getRemotePath();
+            path += newFolderName + OCFile.PATH_SEPARATOR;
+            ((ComponentsGetter)getSherlockActivity()).
+                getFileOperationsHelper().createFolder(path, false);
+        }
+    }
+        
+}

+ 0 - 178
src/com/owncloud/android/ui/dialog/EditNameDialog.java

@@ -1,178 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.dialog;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager.LayoutParams;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.actionbarsherlock.app.SherlockDialogFragment;
-import com.owncloud.android.R;
-import com.owncloud.android.lib.resources.files.FileUtils;
-
-
-/**
- * Dialog to request the user to input a name, optionally initialized with a former name.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
- */
-public class EditNameDialog extends SherlockDialogFragment implements DialogInterface.OnClickListener {
-
-    public static final String TAG = EditNameDialog.class.getSimpleName();
-    
-    protected static final String ARG_TITLE = "TITLE";
-    protected static final String ARG_NAME = "NAME";
-    protected static final String ARG_SELECTION_START = "SELECTION_START";
-    protected static final String ARG_SELECTION_END = "SELECTION_END";
-    
-    private String mNewFilename;
-    private boolean mResult;
-    private EditNameDialogListener mListener;
-    
-    /**
-     * Public factory method to get dialog instances.
-     * 
-     * @param title             Text to show as title in the dialog.
-     * @param name              Optional text to include in the text input field when the dialog is shown.
-     * @param listener          Instance to notify when the dialog is dismissed.
-     * @param selectionStart    Index to the first character to be selected in the input field; negative value for none
-     * @param selectionEnd      Index to the last character to be selected in the input field; negative value for none
-     * @return              New dialog instance, ready to show.
-     */
-    static public EditNameDialog newInstance(String title, String name, int selectionStart, int selectionEnd, EditNameDialogListener listener) {
-        EditNameDialog f = new EditNameDialog();
-        Bundle args = new Bundle();
-        args.putString(ARG_TITLE, title);
-        args.putString(ARG_NAME, name);
-        args.putInt(ARG_SELECTION_START, selectionStart);
-        args.putInt(ARG_SELECTION_END, selectionEnd);
-        f.setArguments(args);
-        f.setOnDismissListener(listener);
-        return f;
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        String currentName = getArguments().getString(ARG_NAME);
-        if (currentName == null)
-            currentName = "";
-        String title = getArguments().getString(ARG_TITLE);
-        
-        // Inflate the layout for the dialog
-        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
-        View v = inflater.inflate(R.layout.edit_box_dialog, null);  // null parent view because it will go in the dialog layout
-        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
-        inputText.setText(currentName);
-        
-        // Set it to the dialog 
-        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
-        builder.setView(v)
-               .setPositiveButton(R.string.common_ok, this)
-               .setNegativeButton(R.string.common_cancel, this);
-
-        if (title != null) {
-            builder.setTitle(title);
-        }
-        
-        mResult = false;
-        
-        Dialog d = builder.create();
-
-        inputText.requestFocus();
-        int selectionStart = getArguments().getInt(ARG_SELECTION_START, -1);
-        int selectionEnd = getArguments().getInt(ARG_SELECTION_END, -1);
-        if (selectionStart >= 0 && selectionEnd >= 0) {
-            inputText.setSelection(Math.min(selectionStart, selectionEnd), Math.max(selectionStart, selectionEnd));
-        }
-        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-        return d;
-    }    
-
-    
-    /**
-     * Performs the corresponding action when a dialog button is clicked.
-     * 
-     * Saves the text in the input field to be accessed through {@link #getNewFilename()} when the positive
-     * button is clicked.
-     * 
-     * Notify the current listener in any case.
-     */
-    @Override
-    public void onClick(DialogInterface dialog, int which) {
-        switch (which) {
-            case AlertDialog.BUTTON_POSITIVE: {
-                mNewFilename = ((TextView)(getDialog().findViewById(R.id.user_input))).getText().toString();
-                if (!FileUtils.isValidName(mNewFilename)) {
-                    Toast.makeText(getSherlockActivity(), R.string.filename_forbidden_characters, Toast.LENGTH_LONG).show();
-                    return;
-                }
-                mResult = true;
-            }
-            case AlertDialog.BUTTON_NEGATIVE: { // fall through
-                dismiss();
-                if (mListener != null)
-                    mListener.onDismiss(this);
-            }
-        }
-    }
-    
-    protected void setOnDismissListener(EditNameDialogListener listener) {
-        mListener = listener;
-    }
-    
-    /**
-     * Returns the text in the input field after the user clicked the positive button.
-     * 
-     * @return      Text in the input field.
-     */
-    public String getNewFilename() {
-        return mNewFilename;
-    }
-    
-    /**
-     * 
-     * @return      True when the user clicked the positive button.
-     */
-    public boolean getResult() {
-        return mResult;
-    }
-
-    
-    /**
-     * Interface to receive a notification when any button in the dialog is clicked.
-     */
-    public interface EditNameDialogListener {
-        public void onDismiss(EditNameDialog dialog);
-    }
-
-
-}
-

+ 1 - 1
src/com/owncloud/android/ui/dialog/LoadingDialog.java

@@ -69,6 +69,6 @@ public class LoadingDialog extends DialogFragment {
     public void onDestroyView() {
         if (getDialog() != null && getRetainInstance())
             getDialog().setDismissMessage(null);
-            super.onDestroyView();
+        super.onDestroyView();
     }
 }

+ 114 - 0
src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java

@@ -0,0 +1,114 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+/**
+ *  Dialog requiring confirmation before removing a given OCFile.  
+ * 
+ *  Triggers the removal according to the user response. 
+ *  
+ *  @author David A. Velasco
+ */
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+
+import android.app.Dialog;
+import android.os.Bundle;
+
+public class RemoveFileDialogFragment extends ConfirmationDialogFragment 
+implements ConfirmationDialogFragmentListener {
+
+    private static final String ARG_TARGET_FILE = "TARGET_FILE";
+
+    /**
+     * Public factory method to create new RemoveFileDialogFragment instances.
+     * 
+     * @param file            File to remove.
+     * @return                Dialog ready to show.
+     */
+    public static RemoveFileDialogFragment newInstance(OCFile file) {
+        RemoveFileDialogFragment frag = new RemoveFileDialogFragment();
+        Bundle args = new Bundle();
+        
+        int messageStringId = R.string.confirmation_remove_alert;
+        
+        int posBtn = R.string.confirmation_remove_remote;
+        int neuBtn = -1;
+        if (file.isFolder()) {
+            messageStringId = R.string.confirmation_remove_folder_alert;
+            posBtn = R.string.confirmation_remove_remote_and_local;
+            neuBtn = R.string.confirmation_remove_folder_local;
+        } else if (file.isDown()) {
+            posBtn = R.string.confirmation_remove_remote_and_local;
+            neuBtn = R.string.confirmation_remove_local;
+        }
+        
+        
+        args.putInt(ARG_CONF_RESOURCE_ID, messageStringId);
+        args.putStringArray(ARG_CONF_ARGUMENTS, new String[]{file.getFileName()});
+        args.putInt(ARG_POSITIVE_BTN_RES, posBtn);
+        args.putInt(ARG_NEUTRAL_BTN_RES, neuBtn);
+        args.putInt(ARG_NEGATIVE_BTN_RES, R.string.common_cancel);
+        args.putParcelable(ARG_TARGET_FILE, file);
+        frag.setArguments(args);
+        
+        return frag;
+    }
+
+    private OCFile mTargetFile;
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        mTargetFile = getArguments().getParcelable(ARG_TARGET_FILE);
+        
+        setOnConfirmationListener(this);
+        
+        return dialog;
+    }    
+
+    /**
+     * Performs the removal of the target file, both locally and in the server.
+     */
+    @Override
+    public void onConfirmation(String callerTag) {
+        ComponentsGetter cg = (ComponentsGetter)getSherlockActivity();
+        FileDataStorageManager storageManager = cg.getStorageManager();
+        if (storageManager.getFileById(mTargetFile.getFileId()) != null) {
+            cg.getFileOperationsHelper().removeFile(mTargetFile, false);
+        }
+    }
+    
+    /**
+     * Performs the removal of the local copy of the taget file
+     */
+    @Override
+    public void onNeutral(String callerTag) {
+        ((ComponentsGetter)getSherlockActivity()).getFileOperationsHelper()
+            .removeFile(mTargetFile, true);
+    }
+
+    @Override
+    public void onCancel(String callerTag) {
+        // nothing to do here
+    }
+    
+}

+ 136 - 0
src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java

@@ -0,0 +1,136 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.dialog;
+
+/**
+ *  Dialog to input a new name for an {@link OCFile} being renamed.  
+ * 
+ *  Triggers the rename operation. 
+ */
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.resources.files.FileUtils;
+import com.owncloud.android.ui.activity.ComponentsGetter;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+/**
+ *  Dialog to input a new name for a file or folder to rename.  
+ * 
+ *  Triggers the rename operation when name is confirmed. 
+ *  
+ *  @author David A. Velasco
+ */
+public class RenameFileDialogFragment
+extends SherlockDialogFragment implements DialogInterface.OnClickListener {
+
+    private static final String ARG_TARGET_FILE = "TARGET_FILE";
+
+    /**
+     * Public factory method to create new RenameFileDialogFragment instances.
+     * 
+     * @param file            File to rename.
+     * @return                Dialog ready to show.
+     */
+    public static RenameFileDialogFragment newInstance(OCFile file) {
+        RenameFileDialogFragment frag = new RenameFileDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_TARGET_FILE, file);
+        frag.setArguments(args);
+        return frag;
+        
+    }
+
+    private OCFile mTargetFile;
+    
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mTargetFile = getArguments().getParcelable(ARG_TARGET_FILE);
+
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getSherlockActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.edit_box_dialog, null);
+        
+        // Setup layout 
+        String currentName = mTargetFile.getFileName();
+        EditText inputText = ((EditText)v.findViewById(R.id.user_input));
+        inputText.setText(currentName);
+        int selectionStart = 0;
+        int extensionStart = mTargetFile.isFolder() ? -1 : currentName.lastIndexOf(".");
+        int selectionEnd = (extensionStart >= 0) ? extensionStart : currentName.length();
+        if (selectionStart >= 0 && selectionEnd >= 0) {
+            inputText.setSelection(
+                    Math.min(selectionStart, selectionEnd), 
+                    Math.max(selectionStart, selectionEnd));
+        }
+        inputText.requestFocus();
+        
+        // Build the dialog  
+        AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this)
+               .setTitle(R.string.rename_dialog_title);
+        Dialog d = builder.create();
+        d.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }    
+
+    
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            String newFileName = 
+                ((TextView)(getDialog().findViewById(R.id.user_input)))
+                    .getText().toString().trim();
+            
+            if (newFileName.length() <= 0) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_empty, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            if (!FileUtils.isValidName(newFileName)) {
+                Toast.makeText(
+                        getSherlockActivity(), 
+                        R.string.filename_forbidden_characters, 
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+            
+            ((ComponentsGetter)getSherlockActivity()).
+                getFileOperationsHelper().renameFile(mTargetFile, newFileName);
+            
+            
+        }
+    }
+    
+}

+ 6 - 4
src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java

@@ -42,7 +42,7 @@ import android.widget.TextView;
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.ui.activity.ComponentsGetter;
 import com.owncloud.android.ui.activity.CopyToClipboardActivity;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.utils.Log_OC;
@@ -132,7 +132,9 @@ public class ShareLinkToDialog  extends SherlockDialogFragment {
                             // Add the information of the chosen activity to the intent to send 
                             ResolveInfo chosen = mAdapter.getItem(which);
                             ActivityInfo actInfo = chosen.activityInfo;
-                            ComponentName name=new ComponentName(actInfo.applicationInfo.packageName, actInfo.name);
+                            ComponentName name=new ComponentName(
+                                    actInfo.applicationInfo.packageName, 
+                                    actInfo.name);
                             mIntent.setComponent(name);                               
 
                             if (sendAction) {
@@ -143,8 +145,8 @@ public class ShareLinkToDialog  extends SherlockDialogFragment {
 
                             } else {
                                 // Create a new share resource
-                                FileOperationsHelper foh = new FileOperationsHelper();
-                                foh.shareFileWithLinkToApp(mFile, mIntent, (FileActivity)getSherlockActivity());
+                                ((ComponentsGetter)getSherlockActivity()).getFileOperationsHelper()
+                                    .shareFileWithLinkToApp(mFile, mIntent);
                             }
                         }
         })

+ 43 - 454
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -17,19 +17,11 @@
  */
 package com.owncloud.android.ui.fragment;
 
-import java.io.File;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
 
 import android.accounts.Account;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -38,7 +30,6 @@ import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
@@ -46,24 +37,15 @@ import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.files.services.FileObserverService;
-import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
-import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.operations.RenameFileOperation;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.ui.activity.ConflictsResolveActivity;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.dialog.EditNameDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.preview.PreviewImageFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
+import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.Log_OC;
 
@@ -74,25 +56,17 @@ import com.owncloud.android.utils.Log_OC;
  * @author Bartek Przybylski
  * @author David A. Velasco
  */
-public class FileDetailFragment extends FileFragment implements
-        OnClickListener, 
-        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener {
+public class FileDetailFragment extends FileFragment implements OnClickListener {
 
-    private FileFragment.ContainerActivity mContainerActivity;
-    
     private int mLayout;
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
     
-    private UploadFinishReceiver mUploadFinishReceiver;
     public ProgressListener mProgressListener;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private static final String TAG = FileDetailFragment.class.getSimpleName();
     public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";
+    public static final String FTAG_RENAME_FILE = "RENAME_FILE_FRAGMENT";
     
 
     /**
@@ -103,7 +77,6 @@ public class FileDetailFragment extends FileFragment implements
     public FileDetailFragment() {
         super();
         mAccount = null;
-        mStorageManager = null;
         mLayout = R.layout.file_details_empty;
         mProgressListener = null;
     }
@@ -119,16 +92,14 @@ public class FileDetailFragment extends FileFragment implements
     public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {
         super(fileToDetail);
         mAccount = ocAccount;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
         mLayout = R.layout.file_details_empty;
         mProgressListener = null;
     }
     
     
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onActivityCreated(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -136,7 +107,6 @@ public class FileDetailFragment extends FileFragment implements
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        //super.onCreateView(inflater, container, savedInstanceState);
         
         if (savedInstanceState != null) {
             setFile((OCFile)savedInstanceState.getParcelable(FileActivity.EXTRA_FILE));
@@ -148,7 +118,6 @@ public class FileDetailFragment extends FileFragment implements
         }
         
         View view = null;
-        //view = inflater.inflate(mLayout, container, false);
         view = inflater.inflate(mLayout, null);
         mView = view;
         
@@ -162,37 +131,6 @@ public class FileDetailFragment extends FileFragment implements
         updateFileDetails(false, false);
         return view;
     }
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mContainerActivity = (ContainerActivity) activity;
-            
-        } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        if (mAccount != null) {
-            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-            OCFile file = mStorageManager.getFileByPath(getFile().getRemotePath());
-            if (file != null) {
-                setFile(file);
-            }
-        }
-    }
-        
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
@@ -207,30 +145,10 @@ public class FileDetailFragment extends FileFragment implements
         listenForTransferProgress();
     }
     
-    @Override
-    public void onResume() {
-        super.onResume();
-        mUploadFinishReceiver = new UploadFinishReceiver();
-        IntentFilter filter = new IntentFilter(FileUploader.getUploadFinishMessage());
-        getActivity().registerReceiver(mUploadFinishReceiver, filter);
-
-    }
-
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        if (mUploadFinishReceiver != null) {
-            getActivity().unregisterReceiver(mUploadFinishReceiver);
-            mUploadFinishReceiver = null;
-        }
-    }
-
-    
     @Override
     public void onStop() {
-        super.onStop();
         leaveTransferProgress();
+        super.onStop();
     }
 
     
@@ -247,26 +165,7 @@ public class FileDetailFragment extends FileFragment implements
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
         inflater.inflate(R.menu.file_actions_menu, menu);
-        MenuItem item = menu.findItem(R.id.action_see_details);
-        if (item != null) {
-            item.setVisible(false);
-            item.setEnabled(false);
-        }
-        
-        // Send file
-        item = menu.findItem(R.id.action_send_file);
-        boolean sendEnabled = getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on");
-        if (item != null) {
-            if (sendEnabled) {
-                item.setVisible(true);
-                item.setEnabled(true);
-            } else {
-                item.setVisible(false);
-                item.setEnabled(false);
-                
-            }
-        }
-    }
+   }
 
     
     /**
@@ -276,80 +175,21 @@ public class FileDetailFragment extends FileFragment implements
     public void onPrepareOptionsMenu (Menu menu) {
         super.onPrepareOptionsMenu(menu);
         
-        List<Integer> toHide = new ArrayList<Integer>();
-        List<Integer> toShow = new ArrayList<Integer>();
-        OCFile file = getFile();
-        
-        FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-        boolean downloading = downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file);
-        FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-        boolean uploading = uploaderBinder != null && uploaderBinder.isUploading(mAccount, getFile());
-        
-        if (downloading || uploading) {
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_rename_file);
-            toHide.add(R.id.action_remove_file);
-            toHide.add(R.id.action_open_file_with);
-            if (!downloading) {
-                toHide.add(R.id.action_cancel_download);
-                toShow.add(R.id.action_cancel_upload);
-            } else {
-                toHide.add(R.id.action_cancel_upload);
-                toShow.add(R.id.action_cancel_download);
-            }
-
-        } else if (file != null && file.isDown()) {
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            
-            toShow.add(R.id.action_rename_file);
-            toShow.add(R.id.action_remove_file);
-            toShow.add(R.id.action_open_file_with);
-            toShow.add(R.id.action_sync_file);
-            
-        } else if (file != null) {
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            
-            toShow.add(R.id.action_rename_file);
-            toShow.add(R.id.action_remove_file);
-            toShow.add(R.id.action_download_file);
-            
-        } else {
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_rename_file);
-            toHide.add(R.id.action_remove_file);
-            
-        }
-        
-        // Options shareLink
-        if (!file.isShareByLink()) {
-            toHide.add(R.id.action_unshare_file);
-        } else {
-            toShow.add(R.id.action_unshare_file);
+        if (mContainerActivity.getStorageManager() != null) {
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
         }
         
-        MenuItem item = null;
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
-        }
-        for (int i : toShow) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(true);
-                item.setEnabled(true);
-            }
+        // additional restriction for this fragment 
+        MenuItem item = menu.findItem(R.id.action_see_details);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
     }
 
@@ -361,44 +201,45 @@ public class FileDetailFragment extends FileFragment implements
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_share_file: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                activity.getFileOperationsHelper().shareFileWithLink(getFile(), activity);
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_unshare_file: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                activity.getFileOperationsHelper().unshareFileWithLink(getFile(), activity);
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_open_file_with: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                activity.getFileOperationsHelper().openFile(getFile(), activity);
+                mContainerActivity.getFileOperationsHelper().openFile(getFile());
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_rename_file: {
-                renameFile();
+                RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), FTAG_RENAME_FILE);
                 return true;
             }
-            case R.id.action_download_file: 
             case R.id.action_cancel_download:
-            case R.id.action_cancel_upload:
+            case R.id.action_cancel_upload: {
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(getFile());
+                return true;
+            }
+            case R.id.action_download_file: 
             case R.id.action_sync_file: {
-                synchronizeFile();
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
                 return true;
             }
             case R.id.action_send_file: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
                 // Obtain the file
                 if (!getFile().isDown()) {  // Download the file                    
                     Log_OC.d(TAG, getFile().getRemotePath() + " : File must be downloaded");
-                    activity.startDownloadForSending(getFile());
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForSending(getFile());
                     
                 } else {
-                    activity.getFileOperationsHelper().sendDownloadedFile(getFile(), activity);
+                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
                 }
                 return true;
             }
@@ -415,7 +256,7 @@ public class FileDetailFragment extends FileFragment implements
                 break;
             }
             case R.id.fdCancelBtn: {
-                synchronizeFile();
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(getFile());
                 break;
             }
             default:
@@ -428,7 +269,7 @@ public class FileDetailFragment extends FileFragment implements
         CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
         OCFile file = getFile();
         file.setKeepInSync(cb.isChecked());
-        mStorageManager.saveFile(file);
+        mContainerActivity.getStorageManager().saveFile(file);
         
         /// register the OCFile instance in the observer service to monitor local updates;
         /// if necessary, the file is download 
@@ -443,97 +284,10 @@ public class FileDetailFragment extends FileFragment implements
         getActivity().startService(intent);
         
         if (file.keepInSync()) {
-            synchronizeFile();   // force an immediate synchronization
+            mContainerActivity.getFileOperationsHelper().syncFile(getFile());
         }
     }
 
-    private void removeFile() {
-        OCFile file = getFile();
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{file.getFileName()},
-                file.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,
-                file.isDown() ? R.string.confirmation_remove_local : -1,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
-    }
-
-
-    private void renameFile() {
-        OCFile file = getFile();
-        String fileName = file.getFileName();
-        int extensionStart = file.isFolder() ? -1 : fileName.lastIndexOf(".");
-        int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length();
-        EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this);
-        dialog.show(getFragmentManager(), "nameeditdialog");
-    }
-
-    private void synchronizeFile() {
-        OCFile file = getFile();
-        FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-        FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-        if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {
-            downloaderBinder.cancel(mAccount, file);
-            if (file.isDown()) {
-                setButtonsForDown();
-            } else {
-                setButtonsForRemote();
-            }
-
-        } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {
-            uploaderBinder.cancel(mAccount, file);
-            if (!file.fileExists()) {
-                // TODO make something better
-                ((FileDisplayActivity)getActivity()).cleanSecondFragment();
-                
-            } else if (file.isDown()) {
-                setButtonsForDown();
-            } else {
-                setButtonsForRemote();
-            }
-            
-        } else {
-            mLastRemoteOperation = new SynchronizeFileOperation(file, null, mStorageManager, mAccount, true, getActivity());
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            // update ui 
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            
-        }
-    }
-
-    @Override
-    public void onConfirmation(String callerTag) {
-        OCFile file = getFile();
-        if (callerTag.equals(FTAG_CONFIRMATION)) {
-            if (mStorageManager.getFileById(file.getFileId()) != null) {
-                mLastRemoteOperation = new RemoveFileOperation( file, 
-                                                                true, 
-                                                                mStorageManager);
-                mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-                                
-                ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            }
-        }
-    }
-    
-    @Override
-    public void onNeutral(String callerTag) {
-        OCFile file = getFile();
-        mStorageManager.removeFile(file, false, true);    // TODO perform in background task / new thread
-        if (file.getStoragePath() != null) {
-            file.setStoragePath(null);
-            updateFileDetails(file, mAccount);
-        }
-    }
-    
-    @Override
-    public void onCancel(String callerTag) {
-        Log_OC.d(TAG, "REMOVAL CANCELED");
-    }
-    
-    
     /**
      * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.
      * 
@@ -551,12 +305,6 @@ public class FileDetailFragment extends FileFragment implements
      */
     public void updateFileDetails(OCFile file, Account ocAccount) {
         setFile(file);
-        if (ocAccount != null && ( 
-                mStorageManager == null || 
-                (mAccount != null && !mAccount.equals(ocAccount))
-           )) {
-            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
-        }
         mAccount = ocAccount;
         updateFileDetails(false, false);
     }
@@ -566,20 +314,17 @@ public class FileDetailFragment extends FileFragment implements
      *
      * TODO Remove parameter when the transferring state of files is kept in database. 
      * 
-     * TODO REFACTORING! this method called 5 times before every time the fragment is shown! 
-     * 
      * @param transferring      Flag signaling if the file should be considered as downloading or uploading, 
      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and 
      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.
      *                          
-     * @param refresh           If 'true', try to refresh the hold file from the database
+     * @param refresh           If 'true', try to refresh the whole file from the database
      */
     public void updateFileDetails(boolean transferring, boolean refresh) {
-
         if (readyToShow()) {
-            
-            if (refresh && mStorageManager != null) {
-                setFile(mStorageManager.getFileByPath(getFile().getRemotePath()));
+            FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
+            if (refresh && storageManager != null) {
+                setFile(storageManager.getFileByPath(getFile().getRemotePath()));
             }
             OCFile file = getFile();
             
@@ -597,7 +342,6 @@ public class FileDetailFragment extends FileFragment implements
             cb.setChecked(file.keepInSync());
 
             // configure UI for depending upon local state of the file
-            //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {
             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
             if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file))) {
@@ -757,161 +501,6 @@ public class FileDetailFragment extends FileFragment implements
     }
     
 
-    /**
-     * Once the file upload has finished -> update view
-     * 
-     * Being notified about the finish of an upload is necessary for the next sequence:
-     *   1. Upload a big file.
-     *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list
-     *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. 
-     *   3. Click the file in the list to see its details.
-     *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.
-     */
-    private class UploadFinishReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
-
-            if (!isEmpty() && accountName.equals(mAccount.name)) {
-                boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
-                String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);
-                boolean renamedInUpload = getFile().getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
-                if (getFile().getRemotePath().equals(uploadRemotePath) ||
-                    renamedInUpload) {
-                    if (uploadWasFine) {
-                        setFile(mStorageManager.getFileByPath(uploadRemotePath));
-                    }
-                    if (renamedInUpload) {
-                        String newName = (new File(uploadRemotePath)).getName();
-                        Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);
-                        msg.show();
-                    }
-                    getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done
-                    
-                    updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
-                   
-                    // Force the preview if the file is an image
-                    if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
-                        ((FileDisplayActivity) mContainerActivity).startImagePreview(getFile());
-                    } 
-                }
-            }
-        }
-    }
-    
-
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newFilename = dialog.getNewFilename();
-            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
-            mLastRemoteOperation = new RenameFileOperation( getFile(), 
-                                                            mAccount, 
-                                                            newFilename, 
-                                                            new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation)) {
-            if (operation instanceof RemoveFileOperation) {
-                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-                
-            } else if (operation instanceof RenameFileOperation) {
-                onRenameFileOperationFinish((RenameFileOperation)operation, result);
-                
-            } else if (operation instanceof SynchronizeFileOperation) {
-                onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
-            }
-        }
-    }
-    
-    
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            ((FileDisplayActivity)getActivity()).cleanSecondFragment();
-
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
-    
-    private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        
-        if (result.isSuccess()) {
-            updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);
-            mContainerActivity.onFileStateChanged();
-            
-        } else {
-            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                // TODO throw again the new rename dialog
-            } if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) {
-                Toast msg = Toast.makeText(getActivity(), R.string.filename_forbidden_characters, Toast.LENGTH_LONG);
-                msg.show();
-            } else {
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                if (result.isSslRecoverableException()) {
-                    // TODO show the SSL warning dialog
-                }
-            }
-        }
-    }
-    
-    private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        OCFile file = getFile();
-        if (!result.isSuccess()) {
-            if (result.getCode() == ResultCode.SYNC_CONFLICT) {
-                Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);
-                i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
-                i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);
-                startActivity(i);
-                
-            } 
-            
-            if (file.isDown()) {
-                setButtonsForDown();
-                
-            } else {
-                setButtonsForRemote();
-            }
-            
-        } else {
-            if (operation.transferWasRequested()) {
-                setButtonsForTransferring();
-                mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so 
-                                                            // checking the service to see if the file is downloading results in FALSE
-            } else {
-                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
-                msg.show();
-                if (file.isDown()) {
-                    setButtonsForDown();
-                    
-                } else {
-                    setButtonsForRemote();
-                }
-            }
-        }
-    }
-    
-
     public void listenForTransferProgress() {
         if (mProgressListener != null) {
             if (mContainerActivity.getFileDownloaderBinder() != null) {

+ 63 - 17
src/com/owncloud/android/ui/fragment/FileFragment.java

@@ -17,11 +17,15 @@
 
 package com.owncloud.android.ui.fragment;
 
+import android.accounts.Account;
+import android.app.Activity;
 import android.support.v4.app.Fragment;
 
 import com.actionbarsherlock.app.SherlockFragment;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.activity.TransferServiceGetter;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.activity.ComponentsGetter;
 
 
 /**
@@ -33,6 +37,8 @@ import com.owncloud.android.ui.activity.TransferServiceGetter;
 public class FileFragment extends SherlockFragment {
     
     private OCFile mFile;
+    
+    protected ContainerActivity mContainerActivity;
 
 
     /**
@@ -66,35 +72,75 @@ public class FileFragment extends SherlockFragment {
     protected void setFile(OCFile file) {
         mFile = file;
     }
-
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mContainerActivity = (ContainerActivity) activity;
+            
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + ContainerActivity.class.getSimpleName());
+        }
+    }
+    
+    
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDetach() {
+        mContainerActivity = null;
+        super.onDetach();
+    }    
+    
+    
+    /**
+     * Interface to implement by any Activity that includes some instance of FileListFragment
      * Interface to implement by any Activity that includes some instance of FileFragment
      * 
      * @author David A. Velasco
      */
-    public interface ContainerActivity extends TransferServiceGetter {
+    public interface ContainerActivity extends ComponentsGetter {
 
         /**
-         * Callback method invoked when the detail fragment wants to notice its container 
-         * activity about a relevant state the file shown by the fragment.
-         * 
-         * Added to notify to FileDisplayActivity about the need of refresh the files list. 
+         * Request the parent activity to show the details of an {@link OCFile}.
          * 
-         * Currently called when:
-         *  - a download is started;
-         *  - a rename is completed;
-         *  - a deletion is completed;
-         *  - the 'inSync' flag is changed;
+         * @param file      File to show details
          */
-        public void onFileStateChanged();
+        public void showDetails(OCFile file);
 
+        
+        ///// TO UNIFY IN A SINGLE CALLBACK METHOD - EVENT NOTIFICATIONs  -> something happened inside the fragment, MAYBE activity is interested --> unify in notification method
         /**
-         * Request the parent activity to show the details of an {@link OCFile}.
+         * Callback method invoked when a the user browsed into a different folder through the list of files
+         *  
+         * @param file
+         */
+        public void onBrowsedDownTo(OCFile folder);                 
+
+        /**
+         * Callback method invoked when a the 'transfer state' of a file changes.
          * 
-         * @param file      File to show details
+         * This happens when a download or upload is started or ended for a file.
+         * 
+         * This method is necessary by now to update the user interface of the double-pane layout in tablets
+         * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
+         * won't provide the needed response before the method where this is called finishes. 
+         * 
+         * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
+         * 
+         * @param file          OCFile which state changed.
+         * @param downloading   Flag signaling if the file is now downloading.
+         * @param uploading     Flag signaling if the file is now uploading.
          */
-        public void showDetails(OCFile file);
+        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading); 
 
+        
     }
-    
+
 }

+ 65 - 247
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -19,33 +19,22 @@ package com.owncloud.android.ui.fragment;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.List;
 
 import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.operations.RenameFileOperation;
-import com.owncloud.android.operations.SynchronizeFileOperation;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.activity.TransferServiceGetter;
+import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.ui.adapter.FileListListAdapter;
-import com.owncloud.android.ui.dialog.EditNameDialog;
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+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.utils.Log_OC;
 
-import android.accounts.Account;
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -56,10 +45,13 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
 /**
  * A Fragment that lists all files and folders in a given path.
  * 
- * @author Bartek Przybylski
+ * TODO refactorize to get rid of direct dependency on FileDisplayActivity
  * 
+ * @author Bartek Przybylski
+ * @author masensio
+ * @author David A. Velasco
  */
-public class OCFileListFragment extends ExtendedListFragment implements EditNameDialogListener, ConfirmationDialogFragmentListener {
+public class OCFileListFragment extends ExtendedListFragment {
     
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
@@ -71,12 +63,11 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     private static final String KEY_TOPS = "TOPS";
     private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
     
-    private OCFileListFragment.ContainerActivity mContainerActivity;
-    
+    private FileFragment.ContainerActivity mContainerActivity;
+   
     private OCFile mFile = null;
     private FileListListAdapter mAdapter;
     
-    private Handler mHandler;
     private OCFile mTargetFile;
 
     // Save the state of the scroll in browsing
@@ -94,12 +85,19 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         super.onAttach(activity);
         Log_OC.e(TAG, "onAttach");
         try {
-            mContainerActivity = (ContainerActivity) activity;
+            mContainerActivity = (FileFragment.ContainerActivity) activity;
         } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + OCFileListFragment.ContainerActivity.class.getSimpleName());
+            throw new ClassCastException(activity.toString() + " must implement " + 
+                    FileFragment.ContainerActivity.class.getSimpleName());
         }
     }
 
+    
+    @Override
+    public void onDetach() {
+        mContainerActivity = null;
+        super.onDetach();
+    }
 
     /**
      * {@inheritDoc}
@@ -108,7 +106,8 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         Log_OC.e(TAG, "onActivityCreated() start");
-        mAdapter = new FileListListAdapter(getActivity(), mContainerActivity);
+        mAdapter = new FileListListAdapter(getSherlockActivity(), mContainerActivity); 
+                
         if (savedInstanceState != null) {
             mFile = savedInstanceState.getParcelable(EXTRA_FILE);
             mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES);
@@ -124,14 +123,14 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
             
         }
         
+        mAdapter = new FileListListAdapter(getSherlockActivity(), mContainerActivity);
+        
         setListAdapter(mAdapter);
         
         registerForContextMenu(getListView());
         getListView().setOnCreateContextMenuListener(this);        
         
-        mHandler = new Handler();
-
-    }
+  }
     
     /**
      * Saves the current listed folder.
@@ -182,7 +181,7 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         if (mFile != null) {
             listDirectory(mFile);
 
-            mContainerActivity.startSyncFolderOperation(mFile);
+            ((FileDisplayActivity)mContainerActivity).startSyncFolderOperation(mFile);
             
             // restore index and top position
             restoreIndexAndTopPosition();
@@ -259,20 +258,19 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
             } else { /// Click on a file
                 if (PreviewImageFragment.canBePreviewed(file)) {
                     // preview image - it handles the download, if needed
-                    mContainerActivity.startImagePreview(file);
+                    ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
                     
                 } else if (file.isDown()) {
                     if (PreviewMediaFragment.canBePreviewed(file)) {
                         // media preview
-                        mContainerActivity.startMediaPreview(file, 0, true);
+                        ((FileDisplayActivity)mContainerActivity).startMediaPreview(file, 0, true);
                     } else {
-                        FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                        activity.getFileOperationsHelper().openFile(file, activity);
+                        mContainerActivity.getFileOperationsHelper().openFile(file);
                     }
                     
                 } else {
                     // automatic download, preview on finish
-                    mContainerActivity.startDownloadForPreview(file);
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file);
                 }
                     
             }
@@ -289,85 +287,40 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
     @Override
     public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
-        MenuInflater inflater = getActivity().getMenuInflater();
+        MenuInflater inflater = getSherlockActivity().getMenuInflater();
         inflater.inflate(R.menu.file_actions_menu, menu);
         AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
         OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-        List<Integer> toHide = new ArrayList<Integer>();    
-        List<Integer> toDisable = new ArrayList<Integer>();  
         
-        MenuItem item = null;
-        if (targetFile.isFolder()) {
-            // contextual menu for folders
-            toHide.add(R.id.action_open_file_with);
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_cancel_download);
-            toHide.add(R.id.action_cancel_upload);
-            toHide.add(R.id.action_sync_file);
-            toHide.add(R.id.action_see_details);
-            toHide.add(R.id.action_send_file);
-            if (    mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ||
-                    mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)           ) {
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                
-            }
-            
-        } else {
-            // contextual menu for regular files
-            
-            // new design: 'download' and 'open with' won't be available anymore in context menu
-            toHide.add(R.id.action_download_file);
-            toHide.add(R.id.action_open_file_with);
-            
-            if (targetFile.isDown()) {
-                toHide.add(R.id.action_cancel_download);
-                toHide.add(R.id.action_cancel_upload);
-                
-            } else {
-                toHide.add(R.id.action_sync_file);
-            }
-            if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
-                toHide.add(R.id.action_cancel_upload);
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                    
-            } else if ( mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
-                toHide.add(R.id.action_cancel_download);
-                toDisable.add(R.id.action_rename_file);
-                toDisable.add(R.id.action_remove_file);
-                    
-            } else {
-                toHide.add(R.id.action_cancel_download);
-                toHide.add(R.id.action_cancel_upload);
-            }
+        if (mContainerActivity.getStorageManager() != null) {
+            FileMenuFilter mf = new FileMenuFilter(
+                targetFile,
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
         }
         
-        // Options shareLink
-        if (!targetFile.isShareByLink()) {
-            toHide.add(R.id.action_unshare_file);
+        /// additional restrictions for this fragment 
+        // TODO allow in the future 'open with' for previewable files
+        MenuItem item = menu.findItem(R.id.action_open_file_with);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
         }
-
-        // Send file
-        boolean sendEnabled = getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on");
-        if (!sendEnabled) {
-            toHide.add(R.id.action_send_file);
-        }
-        
-        for (int i : toHide) {
-            item = menu.findItem(i);
+        /// TODO break this direct dependency on FileDisplayActivity... if possible
+        FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).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);
             }
         }
         
-        for (int i : toDisable) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setEnabled(false);
-            }
-        }
+
     }
     
     
@@ -380,86 +333,45 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         mTargetFile = (OCFile) mAdapter.getItem(info.position);
         switch (item.getItemId()) {                
             case R.id.action_share_file: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                activity.getFileOperationsHelper().shareFileWithLink(mTargetFile, activity);
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
                 return true;
             }
             case R.id.action_unshare_file: {
-                FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                activity.getFileOperationsHelper().unshareFileWithLink(mTargetFile, activity);
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
                 return true;
             }
             case R.id.action_rename_file: {
-                String fileName = mTargetFile.getFileName();
-                int extensionStart = mTargetFile.isFolder() ? -1 : fileName.lastIndexOf(".");
-                int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length();
-                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this);
-                dialog.show(getFragmentManager(), EditNameDialog.TAG);
+                RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
+                dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
                 return true;
             }
             case R.id.action_remove_file: {
-                int messageStringId = R.string.confirmation_remove_alert;
-                int posBtnStringId = R.string.confirmation_remove_remote;
-                int neuBtnStringId = -1;
-                if (mTargetFile.isFolder()) {
-                    messageStringId = R.string.confirmation_remove_folder_alert;
-                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
-                    neuBtnStringId = R.string.confirmation_remove_folder_local;
-                } else if (mTargetFile.isDown()) {
-                    posBtnStringId = R.string.confirmation_remove_remote_and_local;
-                    neuBtnStringId = R.string.confirmation_remove_local;
-                }
-                ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                        messageStringId,
-                        new String[]{mTargetFile.getFileName()},
-                        posBtnStringId,
-                        neuBtnStringId,
-                        R.string.common_cancel);
-                confDialog.setOnConfirmationListener(this);
-                confDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
+            case R.id.action_download_file: 
             case R.id.action_sync_file: {
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
-                RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, getSherlockActivity());
-                operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-                ((FileDisplayActivity) getSherlockActivity()).showLoadingDialog();
-                return true;
-            }
-            case R.id.action_cancel_download: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-                if (downloaderBinder != null && downloaderBinder.isDownloading(account, mTargetFile)) {
-                    downloaderBinder.cancel(account, mTargetFile);
-                    listDirectory();
-                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
-                }
+                mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
                 return true;
             }
+            case R.id.action_cancel_download:
             case R.id.action_cancel_upload: {
-                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-                Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-                if (uploaderBinder != null && uploaderBinder.isUploading(account, mTargetFile)) {
-                    uploaderBinder.cancel(account, mTargetFile);
-                    listDirectory();
-                    mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
-                }
+                ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
                 return true;
             }
             case R.id.action_see_details: {
-                ((FileFragment.ContainerActivity)getActivity()).showDetails(mTargetFile);
+                mContainerActivity.showDetails(mTargetFile);
                 return true;
             }
             case R.id.action_send_file: {
                 // Obtain the file
                 if (!mTargetFile.isDown()) {  // Download the file
                     Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
-                    mContainerActivity.startDownloadForSending(mTargetFile);
+                    ((FileDisplayActivity)mContainerActivity).startDownloadForSending(mTargetFile);
                     
                 } else {
-                
-                    FileDisplayActivity activity = (FileDisplayActivity) getSherlockActivity();
-                    activity.getFileOperationsHelper().sendDownloadedFile(mTargetFile, activity);
+                    mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
                 }
                 return true;
             }
@@ -521,98 +433,4 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName
         }
     }
     
-    
-    
-    /**
-     * Interface to implement by any Activity that includes some instance of FileListFragment
-     * 
-     * @author David A. Velasco
-     */
-    public interface ContainerActivity extends TransferServiceGetter, OnRemoteOperationListener {
-
-        /**
-         * Callback method invoked when a the user browsed into a different folder through the list of files
-         *  
-         * @param file
-         */
-        public void onBrowsedDownTo(OCFile folder);
-
-        public void startDownloadForPreview(OCFile file);
-
-        public void startMediaPreview(OCFile file, int i, boolean b);
-
-        public void startImagePreview(OCFile file);
-        
-        public void startSyncFolderOperation(OCFile folder);
-
-        /**
-         * Getter for the current DataStorageManager in the container activity
-         */
-        public FileDataStorageManager getStorageManager();
-        
-        
-        /**
-         * Callback method invoked when a the 'transfer state' of a file changes.
-         * 
-         * This happens when a download or upload is started or ended for a file.
-         * 
-         * This method is necessary by now to update the user interface of the double-pane layout in tablets
-         * because methods {@link FileDownloaderBinder#isDownloading(Account, OCFile)} and {@link FileUploaderBinder#isUploading(Account, OCFile)}
-         * won't provide the needed response before the method where this is called finishes. 
-         * 
-         * TODO Remove this when the transfer state of a file is kept in the database (other thing TODO)
-         * 
-         * @param file          OCFile which state changed.
-         * @param downloading   Flag signaling if the file is now downloading.
-         * @param uploading     Flag signaling if the file is now uploading.
-         */
-        public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading);
-
-        void startDownloadForSending(OCFile file);
-        
-    }
-    
-    
-    @Override
-    public void onDismiss(EditNameDialog dialog) {
-        if (dialog.getResult()) {
-            String newFilename = dialog.getNewFilename();
-            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
-            RemoteOperation operation = new RenameFileOperation(mTargetFile, 
-                                                                AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
-                                                                newFilename, 
-                                                                mContainerActivity.getStorageManager());
-            operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
-    }
-
-    
-    @Override
-    public void onConfirmation(String callerTag) {
-        if (callerTag.equals(FileDetailFragment.FTAG_CONFIRMATION)) {
-            if (mContainerActivity.getStorageManager().getFileById(mTargetFile.getFileId()) != null) {
-                RemoteOperation operation = new RemoveFileOperation( mTargetFile, 
-                                                                    true, 
-                                                                    mContainerActivity.getStorageManager());
-                operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
-                
-                ((FileDisplayActivity) getActivity()).showLoadingDialog();
-            }
-        }
-    }
-    
-    @Override
-    public void onNeutral(String callerTag) {
-        mContainerActivity.getStorageManager().removeFile(mTargetFile, false, true);    // TODO perform in background task / new thread
-        listDirectory();
-        mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
-    }
-    
-    @Override
-    public void onCancel(String callerTag) {
-        Log_OC.d(TAG, "REMOVAL CANCELED");
-    }
-
-
 }

+ 3 - 44
src/com/owncloud/android/ui/preview/FileDownloadFragment.java

@@ -26,7 +26,6 @@ import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.Log_OC;
 
 import android.accounts.Account;
-import android.app.Activity;
 import android.os.Bundle;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.view.LayoutInflater;
@@ -51,8 +50,6 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
     private static final String EXTRA_ERROR = "ERROR";
 
-    private FileFragment.ContainerActivity mContainerActivity;
-    
     private View mView;
     private Account mAccount;
     
@@ -139,33 +136,6 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     }
     
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        try {
-            mContainerActivity = (ContainerActivity) activity;
-            
-        } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-        }
-    }
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        if (mAccount != null) {
-            //mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;
-        }
-    }
-        
-
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
@@ -194,8 +164,8 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     
     @Override
     public void onStop() {
-        super.onStop();
         leaveTransferProgress();
+        super.onStop();
     }
     
     @Override
@@ -217,19 +187,8 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
     public void onClick(View v) {
         switch (v.getId()) {
             case R.id.cancelBtn: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, getFile())) {
-                    downloaderBinder.cancel(mAccount, getFile());
-                    getActivity().finish(); // :)
-                    /*
-                    leaveTransferProgress();
-                    if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-                    */
-                }
+                mContainerActivity.getFileOperationsHelper().cancelTransference(getFile());
+                getActivity().finish();
                 break;
             }
             default:

+ 25 - 72
src/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -26,9 +26,6 @@ import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.preference.PreferenceManager;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
 import android.support.v4.view.ViewPager;
 import android.view.MotionEvent;
 import android.view.View;
@@ -50,11 +47,11 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.activity.PinCodeActivity;
-import com.owncloud.android.ui.dialog.LoadingDialog;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.Log_OC;
@@ -65,7 +62,9 @@ import com.owncloud.android.utils.Log_OC;
  *  
  *  @author David A. Velasco
  */
-public class PreviewImageActivity extends FileActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener, OnTouchListener , OnRemoteOperationListener{
+public class PreviewImageActivity extends FileActivity implements 
+FileFragment.ContainerActivity, OnTouchListener,  
+ViewPager.OnPageChangeListener, OnRemoteOperationListener {
     
     public static final int DIALOG_SHORT_WAIT = 0;
 
@@ -74,15 +73,9 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
     private static final String KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER";
     
-    private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
-    
     private ViewPager mViewPager; 
     private PreviewImagePagerAdapter mPreviewImagePagerAdapter;    
     
-    private FileDownloaderBinder mDownloaderBinder = null;
-    private ServiceConnection mDownloadConnection, mUploadConnection = null;
-    private FileUploaderBinder mUploaderBinder = null;
-
     private boolean mRequestWaitingForBinder;
     
     private DownloadFinishReceiver mDownloadFinishReceiver;
@@ -141,10 +134,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     @Override
     public void onStart() {
         super.onStart();
-        mDownloadConnection = new PreviewImageServiceConnection();
-        bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
-        mUploadConnection = new PreviewImageServiceConnection();
-        bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
     }
     
     @Override
@@ -163,6 +152,8 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         } else if (operation instanceof UnshareLinkOperation) {
             onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result);
             
+        } else if (operation instanceof RemoveFileOperation) {
+            finish();
         }
     }
     
@@ -189,7 +180,12 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
             invalidateOptionsMenu();
         }
     }
-    
+
+    @Override
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return new PreviewImageServiceConnection();
+    }
+
     /** Defines callbacks for service binding, passed to bindService() */
     private class PreviewImageServiceConnection implements ServiceConnection {
 
@@ -229,14 +225,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     @Override
     public void onStop() {
         super.onStop();
-        if (mDownloadConnection != null) {
-            unbindService(mDownloadConnection);
-            mDownloadConnection = null;
-        }
-        if (mUploadConnection != null) {
-            unbindService(mUploadConnection);
-            mUploadConnection = null;
-        }
     }
     
     
@@ -281,9 +269,9 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     
     @Override
     public void onPause() {
-        super.onPause();
         unregisterReceiver(mDownloadFinishReceiver);
         mDownloadFinishReceiver = null;
+        super.onPause();
     }
     
 
@@ -291,53 +279,6 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         finish();
     }
     
-    /**
-     * Show loading dialog 
-     */
-    public void showLoadingDialog() {
-        // Construct dialog
-        LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
-        FragmentManager fm = getSupportFragmentManager();
-        FragmentTransaction ft = fm.beginTransaction();
-        loading.show(ft, DIALOG_WAIT_TAG);
-        
-    }
-    
-    /**
-     * Dismiss loading dialog
-     */
-    public void dismissLoadingDialog(){
-        Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
-      if (frag != null) {
-          LoadingDialog loading = (LoadingDialog) frag;
-            loading.dismiss();
-        }
-    }
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onFileStateChanged() {
-        // nothing to do here!
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FileDownloaderBinder getFileDownloaderBinder() {
-        return mDownloaderBinder;
-    }
-
-
-    @Override
-    public FileUploaderBinder getFileUploaderBinder() {
-        return mUploaderBinder;
-    }
-
-
     @Override
     public void showDetails(OCFile file) {
         Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
@@ -516,4 +457,16 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
         }
     }
 
+    @Override
+    public void onBrowsedDownTo(OCFile folder) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    @Override
+    public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+        // TODO Auto-generated method stub
+        
+    }
+
 }

+ 49 - 217
src/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc. 
+ *   Copyright (C) 2012-2014 ownCloud Inc. 
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License version 2,
@@ -17,48 +17,35 @@
 package com.owncloud.android.ui.preview;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
 
 
 import android.accounts.Account;
 import android.annotation.SuppressLint;
 import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapFactory.Options;
 import android.graphics.Point;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Handler;
 import android.support.v4.app.FragmentStatePagerAdapter;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.lib.common.network.WebdavUtils;
-import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.ui.activity.FileActivity;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.files.FileMenuFilter;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.Log_OC;
 
@@ -72,23 +59,18 @@ import com.owncloud.android.utils.Log_OC;
  * 
  * @author David A. Velasco
  */
-public class PreviewImageFragment extends FileFragment implements   OnRemoteOperationListener, 
-                                                                        ConfirmationDialogFragment.ConfirmationDialogFragmentListener {
+public class PreviewImageFragment extends FileFragment {
     public static final String EXTRA_FILE = "FILE";
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
 
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
     private ImageView mImageView;
     private TextView mMessageView;
     private ProgressBar mProgressWheel;
 
     public Bitmap mBitmap = null;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private static final String TAG = PreviewImageFragment.class.getSimpleName();
 
     private boolean mIgnoreFirstSavedState;
@@ -106,7 +88,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
         super(fileToDetail);
         mAccount = ocAccount;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment
         mIgnoreFirstSavedState = ignoreFirstSavedState;
     }
     
@@ -121,7 +102,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public PreviewImageFragment() {
         super();
         mAccount = null;
-        mStorageManager = null;
         mIgnoreFirstSavedState = false;
     }
     
@@ -132,7 +112,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -147,7 +126,7 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
         mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
         mImageView = (ImageView)mView.findViewById(R.id.image);
         mImageView.setVisibility(View.GONE);
-        mView.setOnTouchListener((OnTouchListener)getActivity());   // WATCH OUT THAT CAST
+        mView.setOnTouchListener((OnTouchListener)getActivity());
         mMessageView = (TextView)mView.findViewById(R.id.message);
         mMessageView.setVisibility(View.GONE);
         mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel);
@@ -162,8 +141,10 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        if (!(activity instanceof FileFragment.ContainerActivity))
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
+        if (!(activity instanceof OnTouchListener)) {
+            throw new ClassCastException(activity.toString() + 
+                    " must implement " + OnTouchListener.class.getSimpleName());
+        }
     }
     
     
@@ -173,25 +154,11 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
         if (savedInstanceState != null) {
             if (!mIgnoreFirstSavedState) {
                 OCFile file = (OCFile)savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+                setFile(file);
                 mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
-                
-                // Update the file
-                if (mAccount!= null) {
-                    mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-                    OCFile updatedFile = mStorageManager.getFileByPath(file.getRemotePath());
-                    if (updatedFile != null) {
-                        setFile(updatedFile);
-                    } else {
-                        setFile(file);
-                    }
-                } else {
-                    setFile(file);
-                }
-
             } else {
                 mIgnoreFirstSavedState = false;
             }
@@ -235,35 +202,7 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-
         inflater.inflate(R.menu.file_actions_menu, menu);
-        List<Integer> toHide = new ArrayList<Integer>();    
-        
-        MenuItem item = null;
-        toHide.add(R.id.action_cancel_download);
-        toHide.add(R.id.action_cancel_upload);
-        toHide.add(R.id.action_download_file);
-        toHide.add(R.id.action_rename_file);    // by now
-        
-        // Options shareLink
-        if (!getFile().isShareByLink()) {
-            toHide.add(R.id.action_unshare_file);
-        }
-
-        // Send file
-        boolean sendEnabled = getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on");
-        if (!sendEnabled) {
-            toHide.add(R.id.action_send_file);
-        }
-        
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
-        }
-        
     }
 
     /**
@@ -273,17 +212,35 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public void onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
         
-        MenuItem item = menu.findItem(R.id.action_unshare_file);
-        // Options shareLink
-        OCFile file = ((FileActivity) getSherlockActivity()).getFile();
-        if (!file.isShareByLink()) {
+        if (mContainerActivity.getStorageManager() != null) {
+            // Update the file
+            setFile(mContainerActivity.getStorageManager().getFileById(getFile().getFileId()));
+            
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
+        }
+        
+        // additional restriction for this fragment 
+        // TODO allow renaming in PreviewImageFragment
+        MenuItem item = menu.findItem(R.id.action_rename_file);
+        if (item != null) {
             item.setVisible(false);
             item.setEnabled(false);
-        } else {
-            item.setVisible(true);
-            item.setEnabled(true);
         }
-            
+        
+        // additional restriction for this fragment 
+        // TODO allow refresh file in PreviewImageFragment
+        item = menu.findItem(R.id.action_sync_file);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
+        
     }
 
     
@@ -295,13 +252,11 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_share_file: {
-                FileActivity act = (FileActivity)getSherlockActivity();
-                act.getFileOperationsHelper().shareFileWithLink(getFile(), act);
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_unshare_file: {
-                FileActivity act = (FileActivity)getSherlockActivity();
-                act.getFileOperationsHelper().unshareFileWithLink(getFile(), act);
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_open_file_with: {
@@ -309,7 +264,8 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_see_details: {
@@ -317,8 +273,11 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
                 return true;
             }
             case R.id.action_send_file: {
-                FileActivity act = (FileActivity)getSherlockActivity();
-                act.getFileOperationsHelper().sendDownloadedFile(getFile(), act);
+                mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
+                return true;
+            }
+            case R.id.action_sync_file: {
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
                 return true;
             }
             
@@ -329,7 +288,7 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     
 
     private void seeDetails() {
-        ((FileFragment.ContainerActivity)getActivity()).showDetails(getFile());        
+        mContainerActivity.showDetails(getFile());        
     }
 
 
@@ -347,122 +306,22 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
 
     @Override
     public void onDestroy() {
-        super.onDestroy();
         if (mBitmap != null) {
             mBitmap.recycle();
         }
+        super.onDestroy();
     }
 
     
     /**
      * Opens the previewed image with an external application.
-     * 
-     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
-     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
-     * available apps for the MIME type known from the file extension, to let the user choose
      */
     private void openFile() {
-        OCFile file = getFile();
-        String storagePath = file.getStoragePath();
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-        try {
-            Intent i = new Intent(Intent.ACTION_VIEW);
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            startActivity(i);
-            
-        } catch (Throwable t) {
-            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
-            boolean toastIt = true; 
-            String mimeType = "";
-            try {
-                Intent i = new Intent(Intent.ACTION_VIEW);
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (mimeType == null || !mimeType.equals(file.getMimetype())) {
-                    if (mimeType != null) {
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
-                    } else {
-                        // desperate try
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
-                    }
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                    startActivity(i);
-                    toastIt = false;
-                }
-                
-            } catch (IndexOutOfBoundsException e) {
-                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-                
-            } catch (ActivityNotFoundException e) {
-                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-                
-            } catch (Throwable th) {
-                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-                
-            } finally {
-                if (toastIt) {
-                    Toast.makeText(getActivity(), "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
-                }
-            }
-            
-        }
-        finish();
-    }
-    
-    
-    /**
-     * Starts a the removal of the previewed file.
-     * 
-     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
-     * depending upon the user selection in the dialog. 
-     */
-    private void removeFile() {
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{getFile().getFileName()},
-                R.string.confirmation_remove_remote_and_local,
-                R.string.confirmation_remove_local,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-    }
-
-    
-    /**
-     * Performs the removal of the previewed file, both locally and in the server.
-     */
-    @Override
-    public void onConfirmation(String callerTag) {
-        if (mStorageManager.getFileById(getFile().getFileId()) != null) {   // check that the file is still there;
-            mLastRemoteOperation = new RemoveFileOperation( getFile(),      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
-                                                            true, 
-                                                            mStorageManager);
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            ((PreviewImageActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * Removes the file from local storage
-     */
-    @Override
-    public void onNeutral(String callerTag) {
-        OCFile file = getFile();
-        mStorageManager.removeFile(file, false, true);    // TODO perform in background task / new thread
+        mContainerActivity.getFileOperationsHelper().openFile(getFile());
         finish();
     }
     
-    /**
-     * User cancelled the removal action.
-     */
-    @Override
-    public void onCancel(String callerTag) {
-        // nothing to do here
-    }
     
-
     private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
 
         /**
@@ -646,33 +505,6 @@ public class PreviewImageFragment extends FileFragment implements   OnRemoteOper
     }
 
     
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
-            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-        }
-    }
-    
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((PreviewImageActivity) getActivity()).dismissLoadingDialog();
-        
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            finish();
-                
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
-
     /**
      * Finishes the preview
      */

+ 99 - 266
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -16,13 +16,9 @@
  */
 package com.owncloud.android.ui.preview;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import android.accounts.Account;
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -33,17 +29,14 @@ import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
-import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
 import android.widget.ImageView;
 import android.widget.Toast;
 import android.widget.VideoView;
@@ -52,19 +45,14 @@ import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.media.MediaControlView;
 import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
-import com.owncloud.android.lib.common.network.WebdavUtils;
-import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
-import com.owncloud.android.lib.common.operations.RemoteOperation;
-import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.ui.activity.FileActivity;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
-import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
+import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.Log_OC;
 
@@ -79,8 +67,7 @@ import com.owncloud.android.utils.Log_OC;
  * @author David A. Velasco
  */
 public class PreviewMediaFragment extends FileFragment implements
-        OnTouchListener,  
-        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener  {
+        OnTouchListener {
 
     public static final String EXTRA_FILE = "FILE";
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
@@ -89,14 +76,10 @@ public class PreviewMediaFragment extends FileFragment implements
 
     private View mView;
     private Account mAccount;
-    private FileDataStorageManager mStorageManager;
     private ImageView mImagePreview;
     private VideoView mVideoPreview;
     private int mSavedPlaybackPosition;
     
-    private Handler mHandler;
-    private RemoteOperation mLastRemoteOperation;
-    
     private MediaServiceBinder mMediaServiceBinder = null;
     private MediaControlView mMediaController = null;
     private MediaServiceConnection mMediaServiceConnection = null;
@@ -115,11 +98,15 @@ public class PreviewMediaFragment extends FileFragment implements
      * @param fileToDetail      An {@link OCFile} to preview in the fragment
      * @param ocAccount         An ownCloud account; needed to start downloads
      */
-    public PreviewMediaFragment(OCFile fileToDetail, Account ocAccount, int startPlaybackPosition, boolean autoplay) {
+    public PreviewMediaFragment(
+            OCFile fileToDetail, 
+            Account ocAccount, 
+            int startPlaybackPosition, 
+            boolean autoplay) {
+        
         super(fileToDetail);
         mAccount = ocAccount;
         mSavedPlaybackPosition = startPlaybackPosition;
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
         mAutoplay = autoplay;
     }
     
@@ -127,15 +114,16 @@ public class PreviewMediaFragment extends FileFragment implements
     /**
      *  Creates an empty fragment for previews.
      * 
-     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+     *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically 
+     *  (for instance, when the device is turned a aside).
      * 
-     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+     *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful 
+     *  construction 
      */
     public PreviewMediaFragment() {
         super();
         mAccount = null;
         mSavedPlaybackPosition = 0;
-        mStorageManager = null;
         mAutoplay = true;
     }
     
@@ -146,7 +134,6 @@ public class PreviewMediaFragment extends FileFragment implements
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mHandler = new Handler();
         setHasOptionsMenu(true);
     }
     
@@ -173,19 +160,6 @@ public class PreviewMediaFragment extends FileFragment implements
     }
     
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        Log_OC.e(TAG, "onAttach");
-        
-        if (!(activity instanceof FileFragment.ContainerActivity))
-            throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
-    }
-    
-    
     /**
      * {@inheritDoc}
      */
@@ -194,32 +168,36 @@ public class PreviewMediaFragment extends FileFragment implements
         super.onActivityCreated(savedInstanceState);
         Log_OC.e(TAG, "onActivityCreated");
 
-        mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
-        if (savedInstanceState != null) {
+        OCFile file = getFile();
+        if (savedInstanceState == null) {
+            if (file == null) {
+                throw new IllegalStateException("Instanced with a NULL OCFile");
+            }
+            if (mAccount == null) {
+                throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+            }
+            if (!file.isDown()) {
+                throw new IllegalStateException("There is no local file to preview");
+            }
+            
+        } else {
             setFile((OCFile)savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE));
             mAccount = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_ACCOUNT);
-            mSavedPlaybackPosition = savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
+            mSavedPlaybackPosition = 
+                    savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
             mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING);
             
         }
-        OCFile file = getFile();
-        if (file == null) {
-            throw new IllegalStateException("Instanced with a NULL OCFile");
-        }
-        if (mAccount == null) {
-            throw new IllegalStateException("Instanced with a NULL ownCloud Account");
-        }
-        if (!file.isDown()) {
-            throw new IllegalStateException("There is no local file to preview");
-        }
-        if (file.isVideo()) {
-            mVideoPreview.setVisibility(View.VISIBLE);
-            mImagePreview.setVisibility(View.GONE);
-            prepareVideo();
+        if (file != null && file.isDown()) {
+            if (file.isVideo()) {
+                mVideoPreview.setVisibility(View.VISIBLE);
+                mImagePreview.setVisibility(View.GONE);
+                prepareVideo();
             
-        } else {
-            mVideoPreview.setVisibility(View.GONE);
-            mImagePreview.setVisibility(View.VISIBLE);
+            } else {
+                mVideoPreview.setVisibility(View.GONE);
+                mImagePreview.setVisibility(View.VISIBLE);
+            }
         }
         
     }
@@ -242,8 +220,11 @@ public class PreviewMediaFragment extends FileFragment implements
             outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mSavedPlaybackPosition);
             outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mAutoplay);
         } else {
-            outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mMediaServiceBinder.getCurrentPosition());
-            outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
+            outState.putInt(
+                    PreviewMediaFragment.EXTRA_PLAY_POSITION , 
+                    mMediaServiceBinder.getCurrentPosition());
+            outState.putBoolean(
+                    PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
         }
     }
     
@@ -254,7 +235,7 @@ public class PreviewMediaFragment extends FileFragment implements
         Log_OC.e(TAG, "onStart");
 
         OCFile file = getFile();
-        if (file != null) {
+        if (file != null && file.isDown()) {
            if (file.isAudio()) {
                bindMediaService();
                
@@ -279,36 +260,7 @@ public class PreviewMediaFragment extends FileFragment implements
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-
         inflater.inflate(R.menu.file_actions_menu, menu);
-        List<Integer> toHide = new ArrayList<Integer>();    
-        
-        MenuItem item = null;
-        toHide.add(R.id.action_cancel_download);
-        toHide.add(R.id.action_cancel_upload);
-        toHide.add(R.id.action_download_file);
-        toHide.add(R.id.action_sync_file);
-        toHide.add(R.id.action_rename_file);    // by now
-        
-        // Options shareLink
-        if (!getFile().isShareByLink()) {
-            toHide.add(R.id.action_unshare_file);
-        }
-        
-        // Send file
-        boolean sendEnabled = getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on");
-        if (!sendEnabled) {
-            toHide.add(R.id.action_send_file);
-        }
-        
-        for (int i : toHide) {
-            item = menu.findItem(i);
-            if (item != null) {
-                item.setVisible(false);
-                item.setEnabled(false);
-            }
-        }
-        
     }
 
 
@@ -319,14 +271,22 @@ public class PreviewMediaFragment extends FileFragment implements
     public void onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
         
-        MenuItem item = menu.findItem(R.id.action_unshare_file);
-        // Options shareLink
-        if (!getFile().isShareByLink()) {            
+        if (mContainerActivity.getStorageManager() != null) {
+            FileMenuFilter mf = new FileMenuFilter(
+                getFile(),
+                mContainerActivity.getStorageManager().getAccount(),
+                mContainerActivity,
+                getSherlockActivity()
+            );
+            mf.filter(menu);
+        }
+
+        // additional restriction for this fragment 
+        // TODO allow renaming in PreviewImageFragment
+        MenuItem item = menu.findItem(R.id.action_rename_file);
+        if (item != null) {
             item.setVisible(false);
             item.setEnabled(false);
-        } else {
-            item.setVisible(true);
-            item.setEnabled(true);
         }
     }
     
@@ -338,11 +298,13 @@ public class PreviewMediaFragment extends FileFragment implements
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_share_file: {
-                shareFileWithLink();
+                stopPreview(false);
+                mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_unshare_file: {
-                unshareFileWithLink();
+                stopPreview(false);
+                mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
                 return true;
             }
             case R.id.action_open_file_with: {
@@ -350,7 +312,8 @@ public class PreviewMediaFragment extends FileFragment implements
                 return true;
             }
             case R.id.action_remove_file: {
-                removeFile();
+                RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
+                dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
                 return true;
             }
             case R.id.action_see_details: {
@@ -359,8 +322,13 @@ public class PreviewMediaFragment extends FileFragment implements
             }
             case R.id.action_send_file: {
                 sendFile();
+                return true;
             }
-            
+            case R.id.action_sync_file: {
+                mContainerActivity.getFileOperationsHelper().syncFile(getFile());
+                return true;
+            }
+
             default:
                 return false;
         }
@@ -376,29 +344,15 @@ public class PreviewMediaFragment extends FileFragment implements
         setFile(file);
     }
     
-    private void unshareFileWithLink() {
-        stopPreview(false);
-        FileActivity activity = (FileActivity)((FileFragment.ContainerActivity)getActivity());
-        activity.getFileOperationsHelper().unshareFileWithLink(getFile(), activity);
-    }
-    
-    private void shareFileWithLink() {
-        stopPreview(false);
-        FileActivity activity = (FileActivity)((FileFragment.ContainerActivity)getActivity());
-        activity.getFileOperationsHelper().shareFileWithLink(getFile(), activity);
-        
-    }
-
     private void sendFile() {
         stopPreview(false);
-        FileActivity activity = (FileActivity)((FileFragment.ContainerActivity)getActivity());
-        activity.getFileOperationsHelper().sendDownloadedFile(getFile(), activity);
+        mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
         
     }
 
     private void seeDetails() {
         stopPreview(false);
-        ((FileFragment.ContainerActivity)getActivity()).showDetails(getFile());        
+        mContainerActivity.showDetails(getFile());        
     }
 
 
@@ -414,7 +368,8 @@ public class PreviewMediaFragment extends FileFragment implements
         // create and prepare control panel for the user
         mMediaController.setMediaPlayer(mVideoPreview);
         
-        // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
+        // load the video file in the video player ; 
+        // when done, VideoHelper#onPrepared() will be called
         mVideoPreview.setVideoPath(getFile().getStoragePath()); 
     }
     
@@ -481,8 +436,9 @@ public class PreviewMediaFragment extends FileFragment implements
         @Override
         public boolean onError(MediaPlayer mp, int what, int extra) {
             if (mVideoPreview.getWindowToken() != null) {
-                String message = MediaService.getMessageForMediaError(getActivity(), what, extra);
-                new AlertDialog.Builder(getActivity())
+                String message = MediaService.getMessageForMediaError(
+                        getSherlockActivity(), what, extra);
+                new AlertDialog.Builder(getSherlockActivity())
                         .setMessage(message)
                         .setPositiveButton(android.R.string.VideoView_error_button,
                                 new DialogInterface.OnClickListener() {
@@ -502,8 +458,8 @@ public class PreviewMediaFragment extends FileFragment implements
     
     @Override
     public void onPause() {
-        super.onPause();
         Log_OC.e(TAG, "onPause");
+        super.onPause();
     }
     
     @Override
@@ -514,14 +470,13 @@ public class PreviewMediaFragment extends FileFragment implements
     
     @Override
     public void onDestroy() {
-        super.onDestroy();
         Log_OC.e(TAG, "onDestroy");
+        super.onDestroy();
     }
     
     @Override
     public void onStop() {
         Log_OC.e(TAG, "onStop");
-        super.onStop();
 
         mPrepared = false;
         if (mMediaServiceConnection != null) {
@@ -529,10 +484,12 @@ public class PreviewMediaFragment extends FileFragment implements
             if (mMediaServiceBinder != null && mMediaController != null) {
                 mMediaServiceBinder.unregisterMediaController(mMediaController);
             }
-            getActivity().unbindService(mMediaServiceConnection);
+            getSherlockActivity().unbindService(mMediaServiceConnection);
             mMediaServiceConnection = null;
             mMediaServiceBinder = null;
         }
+        
+        super.onStop();
     }
     
     @Override
@@ -546,7 +503,7 @@ public class PreviewMediaFragment extends FileFragment implements
 
     
     private void startFullScreenVideo() {
-        Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
+        Intent i = new Intent(getSherlockActivity(), PreviewVideoActivity.class);
         i.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
         i.putExtra(FileActivity.EXTRA_FILE, getFile());
         i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
@@ -565,7 +522,8 @@ public class PreviewMediaFragment extends FileFragment implements
         Log_OC.e(TAG, "onActivityResult " + this);
         super.onActivityResult(requestCode, resultCode, data);
         if (resultCode == Activity.RESULT_OK) {
-            mSavedPlaybackPosition = data.getExtras().getInt(PreviewVideoActivity.EXTRA_START_POSITION);
+            mSavedPlaybackPosition = data.getExtras().getInt(
+                    PreviewVideoActivity.EXTRA_START_POSITION);
             mAutoplay = data.getExtras().getBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY); 
         }
     }
@@ -591,7 +549,7 @@ public class PreviewMediaFragment extends FileFragment implements
         if (mMediaServiceConnection == null) {
             mMediaServiceConnection = new MediaServiceConnection();
         }
-        getActivity().bindService(  new Intent(getActivity(), 
+        getSherlockActivity().bindService(  new Intent(getSherlockActivity(), 
                                     MediaService.class),
                                     mMediaServiceConnection, 
                                     Context.BIND_AUTO_CREATE);
@@ -603,8 +561,9 @@ public class PreviewMediaFragment extends FileFragment implements
 
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
-            if (getActivity() != null) {
-                if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
+            if (getSherlockActivity() != null) {
+                if (component.equals(
+                        new ComponentName(getSherlockActivity(), MediaService.class))) {
                     Log_OC.d(TAG, "Media service connected");
                     mMediaServiceBinder = (MediaServiceBinder) service;
                     if (mMediaServiceBinder != null) {
@@ -631,12 +590,15 @@ public class PreviewMediaFragment extends FileFragment implements
 
         @Override
         public void onServiceDisconnected(ComponentName component) {
-            if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
+            if (component.equals(new ComponentName(getSherlockActivity(), MediaService.class))) {
                 Log_OC.e(TAG, "Media service suddenly disconnected");
                 if (mMediaController != null) {
                     mMediaController.setMediaPlayer(null);
                 } else {
-                    Toast.makeText(getActivity(), "No media controller to release when disconnected from media service", Toast.LENGTH_SHORT).show();
+                    Toast.makeText(
+                            getSherlockActivity(), 
+                            "No media controller to release when disconnected from media service", 
+                            Toast.LENGTH_SHORT).show();
                 }
                 mMediaServiceBinder = null;
                 mMediaServiceConnection = null;
@@ -648,118 +610,16 @@ public class PreviewMediaFragment extends FileFragment implements
 
     /**
      * Opens the previewed file with an external application.
-     * 
-     * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
-     * we should get a list of available apps for MIME tpye in the server and join it with the list of 
-     * available apps for the MIME type known from the file extension, to let the user choose
      */
     private void openFile() {
-        OCFile file = getFile();
         stopPreview(true);
-        String storagePath = file.getStoragePath();
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
-        try {
-            Intent i = new Intent(Intent.ACTION_VIEW);
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            startActivity(i);
-            
-        } catch (Throwable t) {
-            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + file.getMimetype());
-            boolean toastIt = true; 
-            String mimeType = "";
-            try {
-                Intent i = new Intent(Intent.ACTION_VIEW);
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
-                if (mimeType == null || !mimeType.equals(file.getMimetype())) {
-                    if (mimeType != null) {
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
-                    } else {
-                        // desperate try
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
-                    }
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-                    startActivity(i);
-                    toastIt = false;
-                }
-                
-            } catch (IndexOutOfBoundsException e) {
-                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-                
-            } catch (ActivityNotFoundException e) {
-                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-                
-            } catch (Throwable th) {
-                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-                
-            } finally {
-                if (toastIt) {
-                    Toast.makeText(getActivity(), "There is no application to handle file " + file.getFileName(), Toast.LENGTH_SHORT).show();
-                }
-            }
-            
-        }
+        mContainerActivity.getFileOperationsHelper().openFile(getFile());
         finish();
     }
     
     /**
-     * Starts a the removal of the previewed file.
-     * 
-     * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
-     * depending upon the user selection in the dialog. 
-     */
-    private void removeFile() {
-        ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
-                R.string.confirmation_remove_alert,
-                new String[]{getFile().getFileName()},
-                R.string.confirmation_remove_remote_and_local,
-                R.string.confirmation_remove_local,
-                R.string.common_cancel);
-        confDialog.setOnConfirmationListener(this);
-        confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
-    }
-
-    
-    /**
-     * Performs the removal of the previewed file, both locally and in the server.
-     */
-    @Override
-    public void onConfirmation(String callerTag) {
-        OCFile file = getFile();
-        if (mStorageManager.getFileById(file.getFileId()) != null) {   // check that the file is still there;
-            stopPreview(true);
-            mLastRemoteOperation = new RemoveFileOperation( file,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
-                                                            true, 
-                                                            mStorageManager);
-            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
-            
-            ((FileDisplayActivity) getActivity()).showLoadingDialog();
-        }
-    }
-    
-    
-    /**
-     * Removes the file from local storage
-     */
-    @Override
-    public void onNeutral(String callerTag) {
-        OCFile file = getFile();
-        stopPreview(true);
-        mStorageManager.removeFile(file, false, true);    // TODO perform in background task / new thread
-        finish();
-    }
-    
-    /**
-     * User cancelled the removal action.
-     */
-    @Override
-    public void onCancel(String callerTag) {
-        // nothing to do here
-    }
-    
-
-    /**
-     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed.
+     * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment}
+     *  to be previewed.
      * 
      * @param file      File to test if can be previewed.
      * @return          'True' if the file can be handled by the fragment.
@@ -767,36 +627,9 @@ public class PreviewMediaFragment extends FileFragment implements
     public static boolean canBePreviewed(OCFile file) {
         return (file != null && (file.isAudio() || file.isVideo()));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-        if (operation.equals(mLastRemoteOperation)) {
-            if (operation instanceof RemoveFileOperation) {
-                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
-            }
-        }
-    }
     
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
-        ((FileDisplayActivity) getActivity()).dismissLoadingDialog();
-        if (result.isSuccess()) {
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
-            msg.show();
-            finish();
-                
-        } else {
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
-            msg.show();
-            if (result.isSslRecoverableException()) {
-                // TODO show the SSL warning dialog
-            }
-        }
-    }
 
-    private void stopPreview(boolean stopAudio) {
+    public void stopPreview(boolean stopAudio) {
         OCFile file = getFile();
         if (file.isAudio() && stopAudio) {
             mMediaServiceBinder.pause();
@@ -812,7 +645,7 @@ public class PreviewMediaFragment extends FileFragment implements
      * Finishes the preview
      */
     private void finish() {
-        getActivity().onBackPressed();
+        getSherlockActivity().onBackPressed();
     }