Pārlūkot izejas kodu

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 gadi atpakaļ
vecāks
revīzija
3969dbb768
40 mainītis faili ar 1609 papildinājumiem un 1952 dzēšanām
  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();
     }