Эх сурвалжийг харах

Merge pull request #608 from owncloud/move_files_and_folders

Added capability to move files (and folders)
jabarros 10 жил өмнө
parent
commit
12d64c769f

+ 7 - 3
AndroidManifest.xml

@@ -185,10 +185,14 @@
         </receiver>
         <service android:name=".services.observer.FileObserverService"/>
         
+		<activity
+			android:name=".ui.activity.CopyToClipboardActivity"
+			android:label="@string/copy_link"
+			android:icon="@drawable/copy_link"/>
+
         <activity 
-            android:name=".ui.activity.CopyToClipboardActivity" 
-           	android:label="@string/copy_link"
-           	android:icon="@drawable/copy_link" />
+			android:name=".ui.activity.MoveActivity"
+			android:label="@string/app_name"/>
         
     </application>
 

+ 1 - 1
owncloud-android-library

@@ -1 +1 @@
-Subproject commit e43e43f51a895c591b72aaef8f36ef5595d18dba
+Subproject commit 5d146c923620523a871a0fe50bdcbc3b7559df8c

+ 36 - 0
res/layout/files_move.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/background_color"
+    android:orientation="vertical" >
+
+	<FrameLayout 
+		android:layout_width="match_parent"
+		android:layout_height="0dip"
+        android:layout_weight="1"
+		android:id="@+id/fragment_container" />
+	
+	<LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/move_files_btn_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/common_cancel" />
+
+		<Button
+		    android:id="@+id/move_files_btn_choose"
+		    android:layout_width="wrap_content"
+		    android:layout_height="wrap_content"
+		    android:layout_weight="1"
+		    android:text="@string/move_choose_button_text" />
+
+	</LinearLayout>
+
+ </LinearLayout>

+ 2 - 1
res/menu/file_actions_menu.xml

@@ -27,8 +27,9 @@
 	<item 	android:id="@+id/action_cancel_download"		android:title="@string/common_cancel_download"	 	android:icon="@android:drawable/ic_menu_close_clear_cancel"		android:orderInCategory="1" />
 	<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_edit"					android:orderInCategory="1" />
+    <item 	android:id="@+id/action_move"					android:title="@string/actionbar_move"				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_send_file"				android:title="@string/actionbar_send_file"			android:icon="@android:drawable/ic_menu_set_as"					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>

+ 12 - 2
res/values/strings.xml

@@ -255,9 +255,9 @@
 
 	<string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your
 		administrator.</string>
-	<string name="share_link_file_no_exist">Unable to share this file or folder. Please, make sure it exists</string>
+	<string name="share_link_file_no_exist">Unable to share. Please check whether the file exists</string>
 	<string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
-	<string name="unshare_link_file_no_exist">Unable to unshare this file or folder. It does not exist.</string>
+	<string name="unshare_link_file_no_exist">Unable to unshare. Please check whether the file exists</string>
 	<string name="unshare_link_file_error">An error occurred while trying to unshare this file or folder</string>
 
 	<string name="activity_chooser_send_file_title">Send</string>
@@ -286,4 +286,14 @@
 	<string name="prefs_add_account">Add account</string>
 	<string name="auth_redirect_non_secure_connection_title">Secure connection is redirected through an unsecured route.</string>
 
+	<string name="actionbar_move">Move</string>
+	<string name="file_list_empty_moving">Nothing in here. You can add a folder!</string>
+	<string name="move_choose_button_text">Choose</string>
+
+	<string name="move_file_not_found">Unable to move. Please check whether the file exists</string>
+	<string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant</string>
+	<string name="move_file_invalid_overwrite">The file exists already in the destination folder</string>
+	<string name="move_file_error">An error occurred while trying to move this file or folder</string>
+	<string name="forbidden_permissions_move">to move this file</string>
+
 </resources>

+ 121 - 0
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -612,6 +612,126 @@ public class FileDataStorageManager {
     }
 
     
+    public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
+
+        if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
+            
+            OCFile targetParent = getFileByPath(targetParentPath);
+            if (targetParent == null) {
+                // TODO panic
+            }
+            
+            /// 1. get all the descendants of the moved element in a single QUERY
+            Cursor c = null;
+            if (getContentProviderClient() != null) {
+                try {
+                    c = getContentProviderClient().query(
+                        ProviderTableMeta.CONTENT_URI, 
+                        null,
+                        ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                                ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                        new String[] { 
+                                mAccount.name, 
+                                file.getRemotePath() + "%"  
+                        }, 
+                        ProviderTableMeta.FILE_PATH + " ASC "
+                    );
+                } catch (RemoteException e) {
+                    Log_OC.e(TAG, e.getMessage());
+                }
+                
+            } else {
+                c = getContentResolver().query(
+                    ProviderTableMeta.CONTENT_URI, 
+                    null,
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + 
+                            ProviderTableMeta.FILE_PATH + " LIKE ? ",
+                    new String[] { 
+                            mAccount.name, 
+                            file.getRemotePath() + "%"  
+                    }, 
+                    ProviderTableMeta.FILE_PATH + " ASC "
+                );
+            }
+
+            /// 2. prepare a batch of update operations to change all the descendants
+            ArrayList<ContentProviderOperation> operations = 
+                    new ArrayList<ContentProviderOperation>(c.getCount());
+            String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
+            if (c.moveToFirst()) {
+                int lengthOfOldPath = file.getRemotePath().length();
+                int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
+                do {
+                    ContentValues cv = new ContentValues(); // keep construction in the loop
+                    OCFile child = createFileInstance(c);
+                    cv.put(
+                        ProviderTableMeta.FILE_PATH, 
+                        targetPath + child.getRemotePath().substring(lengthOfOldPath)
+                    );
+                    if (child.getStoragePath() != null && 
+                            child.getStoragePath().startsWith(defaultSavePath)) {
+                        // update link to downloaded content - but local move is not done here!
+                        cv.put(
+                            ProviderTableMeta.FILE_STORAGE_PATH, 
+                            defaultSavePath + targetPath + 
+                                child.getStoragePath().substring(lengthOfOldStoragePath)
+                        );
+                    }
+                    if (child.getRemotePath().equals(file.getRemotePath())) {
+                        cv.put(
+                                ProviderTableMeta.FILE_PARENT,
+                                targetParent.getFileId()
+                            );
+                    }
+                    operations.add(
+                        ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                            withValues(cv).
+                            withSelection(  
+                                    ProviderTableMeta._ID + "=?", 
+                                    new String[] { String.valueOf(child.getFileId()) }
+                                    )
+                            .build());
+                    
+                } while (c.moveToNext());
+            }
+            c.close();
+
+            /// 3. apply updates in batch
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (Exception e) {
+                Log_OC.e(
+                    TAG, 
+                    "Fail to update " + file.getFileId() + " and descendants in database", 
+                    e
+                );
+            }
+
+            /// 4. move in local file system 
+            String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
+            File localFile = new File(localPath);
+            boolean renamed = false;
+            if (localFile.exists()) {
+                File targetFile = new File(defaultSavePath + targetPath);
+                File targetFolder = targetFile.getParentFile();
+                if (!targetFolder.exists()) {
+                    targetFolder.mkdirs();
+                }
+                renamed = localFile.renameTo(targetFile);
+            }
+            Log_OC.d(TAG, "Local file RENAMED : " + renamed);
+            
+        }
+        
+    }
+    
+    
     private Vector<OCFile> getFolderContent(long parentId) {
 
         Vector<OCFile> ret = new Vector<OCFile>();
@@ -1302,4 +1422,5 @@ public class FileDataStorageManager {
             */
         //}
     }
+
 }

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

@@ -162,6 +162,14 @@ public class FileMenuFilter {
         } else {
             toShow.add(R.id.action_rename_file);
         }
+
+        // MOVE
+        if (mFile == null || downloading || uploading) {
+            toHide.add(R.id.action_move);
+
+        } else {
+            toShow.add(R.id.action_move);
+        }
         
         // REMOVE
         if (mFile == null || downloading || uploading) {

+ 18 - 1
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -265,7 +265,24 @@ public class FileOperationsHelper {
         } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
             uploaderBinder.cancel(account, file);
         }
-    }    
+    }
+
+    /**
+     * Start move file operation
+     * @param newfile           File where it is going to be moved
+     * @param currentFile       File with the previous info
+     */
+    public void moveFile(OCFile newfile, OCFile currentFile) {
+        // Move files
+        Intent service = new Intent(mFileActivity, OperationsService.class);
+        service.setAction(OperationsService.ACTION_MOVE_FILE);
+        service.putExtra(OperationsService.EXTRA_NEW_PARENT_PATH, newfile.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_REMOTE_PATH, currentFile.getRemotePath());
+        service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
+        mWaitingForOpId =  mFileActivity.getOperationsServiceBinder().newOperation(service);
+
+        mFileActivity.showLoadingDialog();
+    }
 
 
     public long getOpIdWaitingFor() {

+ 103 - 0
src/com/owncloud/android/operations/MoveFileOperation.java

@@ -0,0 +1,103 @@
+/* ownCloud Android client application
+ *   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,
+ *   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.operations;
+
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.lib.resources.files.MoveRemoteFileOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+
+import android.accounts.Account;
+
+
+/**
+ * Operation mmoving an {@link OCFile} to a different folder.
+ * 
+ * @author David A. Velasco
+ */
+public class MoveFileOperation extends SyncOperation {
+    
+    //private static final String TAG = MoveFileOperation.class.getSimpleName();
+    
+    private String mSrcPath;
+    private String mTargetParentPath;
+    
+    private OCFile mFile;
+
+    
+    
+    /**
+     * Constructor
+     * 
+     * @param path              Remote path of the {@link OCFile} to move.
+     * @param newParentPath     Path to the folder where the file will be moved into. 
+     * @param account           OwnCloud account containing both the file and the target folder 
+     */
+    public MoveFileOperation(String srcPath, String targetParentPath, Account account) {
+        mSrcPath = srcPath;
+        mTargetParentPath = targetParentPath;
+        if (!mTargetParentPath.endsWith(OCFile.PATH_SEPARATOR)) {
+            mTargetParentPath += OCFile.PATH_SEPARATOR;
+        }
+        
+        mFile = null;
+    }
+  
+    /**
+     * Performs the operation.
+     * 
+     * @param   client      Client object to communicate with the remote ownCloud server.
+     */
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        RemoteOperationResult result = null;
+        
+        /// 1. check move validity
+        if (mTargetParentPath.startsWith(mSrcPath)) {
+            return new RemoteOperationResult(ResultCode.INVALID_MOVE_INTO_DESCENDANT);
+        }
+        mFile = getStorageManager().getFileByPath(mSrcPath);
+        if (mFile == null) {
+            return new RemoteOperationResult(ResultCode.FILE_NOT_FOUND);
+        }
+        
+        /// 2. remote move
+        String targetPath = mTargetParentPath + mFile.getFileName();
+        if (mFile.isFolder()) {
+            targetPath += OCFile.PATH_SEPARATOR;
+        }
+        MoveRemoteFileOperation operation = new MoveRemoteFileOperation(
+                mSrcPath, 
+                targetPath, 
+                false
+        );
+        result = operation.execute(client);
+        
+        /// 3. local move
+        if (result.isSuccess()) {
+            getStorageManager().moveLocalFile(mFile, targetPath, mTargetParentPath);
+        } 
+        // TODO handle ResultCode.PARTIAL_MOVE_DONE in client Activity, for the moment
+        
+        return result;
+    }
+    
+
+}

+ 8 - 0
src/com/owncloud/android/services/OperationsService.java

@@ -42,6 +42,7 @@ 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.MoveFileOperation;
 import com.owncloud.android.operations.OAuth2GetAccessToken;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
@@ -79,6 +80,7 @@ public class OperationsService extends Service {
     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";
+    public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
     
     // TODO review if ALL OF THEM are necessary
     public static final String EXTRA_SUCCESS_IF_ABSENT = "SUCCESS_IF_ABSENT";
@@ -97,6 +99,7 @@ public class OperationsService extends Service {
     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_MOVE_FILE = "MOVE_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";
@@ -375,6 +378,11 @@ public class OperationsService extends Service {
                         String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
                         boolean syncFileContents = operationIntent.getBooleanExtra(EXTRA_SYNC_FILE_CONTENTS, true);
                         operation = new SynchronizeFileOperation(remotePath, account, syncFileContents, getApplicationContext());
+                    } else if (action.equals(ACTION_MOVE_FILE)) {
+                        // Move file/folder
+                        String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                        String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
+                        operation = new MoveFileOperation(remotePath,newParentPath,account);
                     }
                     
                 }

+ 8 - 5
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -80,6 +80,8 @@ implements OnRemoteOperationListener, ComponentsGetter {
     private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
     private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";;
     
+    protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
+    
     
     /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
     private Account mAccount;
@@ -506,11 +508,12 @@ implements OnRemoteOperationListener, ComponentsGetter {
     }
     
     
-    private void updateFileFromDB(){
-      OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
-      if (file != null) {
-          setFile(file);
-      }
+    protected void updateFileFromDB(){
+        OCFile file = getFile();
+        if (file != null) {
+            file = getStorageManager().getFileByPath(file.getRemotePath());
+            setFile(file);
+        }
     }
     
     /**

+ 79 - 7
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -21,6 +21,8 @@ package com.owncloud.android.ui.activity;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.commons.httpclient.methods.PostMethod;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorException;
@@ -48,6 +50,7 @@ import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
+import android.support.v4.widget.SwipeRefreshLayout;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -79,6 +82,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
@@ -109,8 +113,9 @@ import com.owncloud.android.utils.Log_OC;
  */
 
 public class FileDisplayActivity extends HookActivity implements
-FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener {
-
+FileFragment.ContainerActivity, OnNavigationListener, 
+OnSslUntrustedCertListener, SwipeRefreshLayout.OnRefreshListener {
+    
     private ArrayAdapter<String> mDirectories;
 
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
@@ -134,6 +139,7 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
 
     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
+    public static final int ACTION_MOVE_FILES = 3;
 
     private static final String TAG = FileDisplayActivity.class.getSimpleName();
 
@@ -550,6 +556,20 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
         } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
             requestMultipleUpload(data, resultCode);
 
+        } else if (requestCode == ACTION_MOVE_FILES && (resultCode == RESULT_OK || 
+                resultCode == MoveActivity.RESULT_OK_AND_MOVE)){
+
+            final Intent fData = data;
+            final int fResultCode = resultCode; 
+            getHandler().postDelayed(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        requestMoveOperation(fData, fResultCode);
+                    }
+                }, 
+                DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS
+            );
         }
     }
 
@@ -630,6 +650,18 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
         startService(i);
     }
 
+    /**
+     * Request the operation for moving the file/folder from one path to another
+     * 
+     * @param data              Intent received
+     * @param resultCode        Result code received
+     */
+    private void requestMoveOperation(Intent data, int resultCode) {
+        OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_CURRENT_FOLDER);
+        OCFile targetFile = (OCFile) data.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
+        getFileOperationsHelper().moveFile(folderToMoveAt, targetFile);
+    }
+
     @Override
     public void onBackPressed() {
         OCFileListFragment listOfFiles = getListOfFilesFragment(); 
@@ -1315,7 +1347,9 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
         } else if (operation instanceof UnshareLinkOperation) {
             onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
         
-        } 
+        } else if (operation instanceof MoveFileOperation) {
+            onMoveFileOperationFinish((MoveFileOperation)operation, result);
+        }
         
     }
 
@@ -1394,12 +1428,13 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
     
     
     /**
-     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * Updates the view associated to the activity after the finish of an operation trying to move a 
+     * file.
      * 
-     * @param operation     Creation operation performed.
-     * @param result        Result of the creation.
+     * @param operation     Move operation performed.
+     * @param result        Result of the move operation.
      */
-    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+    private void onMoveFileOperationFinish(MoveFileOperation operation, RemoteOperationResult result) {
         if (result.isSuccess()) {
             dismissLoadingDialog();
             refreshListOfFilesFragment();
@@ -1486,6 +1521,30 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
         }
     }
 
+    /**
+     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            dismissLoadingDialog();
+            refreshListOfFilesFragment();
+        } else {
+            dismissLoadingDialog();
+            try {
+                Toast msg = Toast.makeText(FileDisplayActivity.this, 
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
+                msg.show();
+
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
+
     
     /**
      * {@inheritDoc}
@@ -1654,4 +1713,17 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener
         onTransferStateChanged(file, false, false);
     }
 
+    @Override
+    public void onRefresh() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {
+            OCFile folder = listOfFiles.getCurrentFile();
+            if (folder != null) {
+                /*mFile = mContainerActivity.getStorageManager().getFileById(mFile.getFileId());
+                listDirectory(mFile);*/
+                startSyncFolderOperation(folder);
+            }
+        }
+    }
+
 }

+ 568 - 0
src/com/owncloud/android/ui/activity/MoveActivity.java

@@ -0,0 +1,568 @@
+/* ownCloud Android client application
+ *   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,
+ *   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.activity;
+
+import java.io.IOException;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+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.CreateFolderOperation;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.syncadapter.FileSyncAdapter;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
+import com.owncloud.android.utils.Log_OC;
+
+public class MoveActivity extends HookActivity implements FileFragment.ContainerActivity, 
+    OnClickListener, SwipeRefreshLayout.OnRefreshListener {
+
+    public static final String EXTRA_CURRENT_FOLDER = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CURRENT_FOLDER";
+    public static final String EXTRA_TARGET_FILE = UploadFilesActivity.class.getCanonicalName() + "EXTRA_TARGET_FILE";
+
+    public static final int RESULT_OK_AND_MOVE = 1;
+    
+    private SyncBroadcastReceiver mSyncBroadcastReceiver;
+
+    private static final String TAG = MoveActivity.class.getSimpleName();
+    
+    private static final String TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS";
+       
+    private boolean mSyncInProgress = false;
+
+    private Button mCancelBtn;
+    private Button mChooseBtn;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log_OC.d(TAG, "onCreate() start");
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+
+        super.onCreate(savedInstanceState); 
+
+        setContentView(R.layout.files_move);
+        
+        if (savedInstanceState == null) {
+            createFragments();
+        }
+
+        // sets callback listeners for UI elements
+        initControls();
+
+        // Action bar setup
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setDisplayShowTitleEnabled(true);
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+        setSupportProgressBarIndeterminateVisibility(mSyncInProgress);
+            // always AFTER setContentView(...) ; to work around bug in its implementation
+        
+        // sets message for empty list of folders
+        setBackgroundText();
+
+        Log_OC.d(TAG, "onCreate() end");
+        
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        getSupportActionBar().setIcon(DisplayUtils.getSeasonalIconId());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    /**
+     *  Called when the ownCloud {@link Account} associated to the Activity was just updated.
+     */
+    @Override
+    protected void onAccountSet(boolean stateWasRecovered) {
+        super.onAccountSet(stateWasRecovered);
+        if (getAccount() != null) {
+            
+            updateFileFromDB();
+            
+            OCFile folder = getFile();
+            if (folder == null || !folder.isFolder()) {
+                // fall back to root folder
+                setFile(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
+                folder = getFile();
+            }
+            
+            if (!stateWasRecovered) {
+                OCFileListFragment listOfFolders = getListOfFilesFragment(); 
+                listOfFolders.listDirectory(folder);   
+                
+                startSyncFolderOperation(folder);
+            }
+            
+            updateNavigationElementsInActionBar();
+        }
+    }
+
+    private void createFragments() {
+        OCFileListFragment listOfFiles = new OCFileListFragment();
+        Bundle args = new Bundle();
+        args.putBoolean(OCFileListFragment.ARG_JUST_FOLDERS, true);
+        args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, false);
+        listOfFiles.setArguments(args);
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
+        transaction.commit();
+    }
+
+    /**
+     * Show a text message on screen view for notifying user if content is
+     * loading or folder is empty
+     */
+    private void setBackgroundText() {
+        OCFileListFragment listFragment = getListOfFilesFragment();
+        if (listFragment != null) {
+            int message = R.string.file_list_loading;
+            if (!mSyncInProgress) {
+                // In case folder list is empty
+                message = R.string.file_list_empty_moving;
+            }
+            listFragment.setMessageForEmptyList(getString(message));
+        } else {
+            Log.e(TAG, "OCFileListFragment is null");
+        }
+    }
+
+    private OCFileListFragment getListOfFilesFragment() {
+        Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(MoveActivity.TAG_LIST_OF_FOLDERS);
+        if (listOfFiles != null) {
+            return (OCFileListFragment)listOfFiles;
+        }
+        Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!");
+        return null;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * Updates action bar and second fragment, if in dual pane mode.
+     */
+    @Override
+    public void onBrowsedDownTo(OCFile directory) {
+        setFile(directory);
+        updateNavigationElementsInActionBar();
+        // Sync Folder
+        startSyncFolderOperation(directory);
+        
+    }
+
+    
+    public void startSyncFolderOperation(OCFile folder) {
+        long currentSyncTime = System.currentTimeMillis(); 
+        
+        mSyncInProgress = true;
+                
+        // perform folder synchronization
+        RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder,  
+                                                                        currentSyncTime, 
+                                                                        false,
+                                                                        getFileOperationsHelper().isSharedSupported(),
+                                                                        getStorageManager(), 
+                                                                        getAccount(), 
+                                                                        getApplicationContext()
+                                                                      );
+        synchFolderOp.execute(getAccount(), this, null, null);
+        
+        setSupportProgressBarIndeterminateVisibility(true);
+
+        setBackgroundText();
+    }
+
+    @Override
+    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_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED);
+        syncIntentFilter.addAction(SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
+        mSyncBroadcastReceiver = new SyncBroadcastReceiver();
+        registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+        
+        Log_OC.d(TAG, "onResume() end");
+    }
+    
+    @Override
+    protected void onPause() {
+        Log_OC.e(TAG, "onPause() start");
+        if (mSyncBroadcastReceiver != null) {
+            unregisterReceiver(mSyncBroadcastReceiver);
+            //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
+            mSyncBroadcastReceiver = null;
+        }
+        
+        Log_OC.d(TAG, "onPause() end");
+        super.onPause();
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getSherlock().getMenuInflater();
+        inflater.inflate(R.menu.main_menu, menu);
+        menu.findItem(R.id.action_upload).setVisible(false);
+        menu.findItem(R.id.action_settings).setVisible(false);
+        menu.findItem(R.id.action_sync_account).setVisible(false);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean retval = true;
+        switch (item.getItemId()) {
+        case R.id.action_create_dir: {
+            CreateFolderDialogFragment dialog = 
+                    CreateFolderDialogFragment.newInstance(getCurrentFolder());
+            dialog.show(
+                    getSupportFragmentManager(), 
+                    CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT
+            );
+            break;
+        }
+        case android.R.id.home: {
+            OCFile currentDir = getCurrentFolder();
+            if(currentDir != null && currentDir.getParentId() != 0) {
+                onBackPressed();
+            }
+            break;
+        }
+        default:
+            retval = super.onOptionsItemSelected(item);
+        }
+        return retval;
+    }
+
+    private OCFile getCurrentFolder() {
+        OCFile file = getFile();
+        if (file != null) {
+            if (file.isFolder()) {
+                return file;
+            } else if (getStorageManager() != null) {
+                String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+                return getStorageManager().getFileByPath(parentPath);
+            }
+        }
+        return null;
+    }
+    
+    protected void refreshListOfFilesFragment() {
+        OCFileListFragment fileListFragment = getListOfFilesFragment();
+        if (fileListFragment != null) { 
+            fileListFragment.listDirectory();
+        }
+    }
+
+    public void browseToRoot() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment(); 
+        if (listOfFiles != null) {  // should never be null, indeed
+            OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH);
+            listOfFiles.listDirectory(root);
+            setFile(listOfFiles.getCurrentFile());
+            updateNavigationElementsInActionBar();
+            startSyncFolderOperation(root);
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {  // should never be null, indeed
+            int levelsUp = listOfFiles.onBrowseUp();
+            if (levelsUp == 0) {
+                finish();
+                return;
+            }
+            setFile(listOfFiles.getCurrentFile());
+            updateNavigationElementsInActionBar();
+        }
+    }
+
+    private void updateNavigationElementsInActionBar() {
+        ActionBar actionBar = getSupportActionBar();
+        OCFile currentDir = getCurrentFolder();
+        boolean atRoot = (currentDir == null || currentDir.getParentId() == 0);
+        actionBar.setDisplayHomeAsUpEnabled(!atRoot);
+        actionBar.setHomeButtonEnabled(!atRoot);
+        actionBar.setTitle(
+            atRoot 
+                ? getString(R.string.default_display_name_for_root_folder) 
+                : currentDir.getFileName()
+        );
+    }
+
+    /**
+     * Set per-view controllers
+     */
+    private void initControls(){
+        mCancelBtn = (Button) findViewById(R.id.move_files_btn_cancel);
+        mCancelBtn.setOnClickListener(this);
+        mChooseBtn = (Button) findViewById(R.id.move_files_btn_choose);
+        mChooseBtn.setOnClickListener(this);
+    }
+    
+    @Override
+    public void onClick(View v) {
+        if (v == mCancelBtn) {
+            finish();
+        } else if (v == mChooseBtn) {
+            Intent i = getIntent();
+            OCFile targetFile = (OCFile) i.getParcelableExtra(MoveActivity.EXTRA_TARGET_FILE);
+
+            Intent data = new Intent();
+            data.putExtra(EXTRA_CURRENT_FOLDER, getCurrentFolder());
+            data.putExtra(EXTRA_TARGET_FILE, targetFile);
+            setResult(RESULT_OK_AND_MOVE, data);
+            finish();
+        }
+    }
+    
+    
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        super.onRemoteOperationFinish(operation, result);
+        
+        if (operation instanceof CreateFolderOperation) {
+            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+            
+        }
+    }
+    
+    
+    /**
+     * Updates the view associated to the activity after the finish of an operation trying 
+     * to create a new folder.
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(
+            CreateFolderOperation operation, RemoteOperationResult result
+            ) {
+        
+        if (result.isSuccess()) {
+            dismissLoadingDialog();
+            refreshListOfFilesFragment();
+        } else {
+            dismissLoadingDialog();
+            try {
+                Toast msg = Toast.makeText(MoveActivity.this, 
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                        Toast.LENGTH_LONG); 
+                msg.show();
+
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
+    
+    
+    
+    private class SyncBroadcastReceiver extends BroadcastReceiver {
+
+        /**
+         * {@link BroadcastReceiver} to enable syncing feedback in UI
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            try {
+                String event = intent.getAction();
+                Log_OC.d(TAG, "Received broadcast " + event);
+                String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME);
+                String synchFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH); 
+                RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncAdapter.EXTRA_RESULT);
+                boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); 
+    
+                if (sameAccount) {
+                    
+                    if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) {
+                        mSyncInProgress = true;
+                        
+                    } else {
+                        OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath());
+                        OCFile currentDir = (getCurrentFolder() == null) ? null : getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
+    
+                        if (currentDir == null) {
+                            // current folder was removed from the server 
+                            Toast.makeText( MoveActivity.this, 
+                                            String.format(getString(R.string.sync_current_folder_was_removed), getCurrentFolder().getFileName()), 
+                                            Toast.LENGTH_LONG)
+                                .show();
+                            browseToRoot();
+                            
+                        } else {
+                            if (currentFile == null && !getFile().isFolder()) {
+                                // currently selected file was removed in the server, and now we know it
+                                currentFile = currentDir;
+                            }
+
+                            if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) {
+                                OCFileListFragment fileListFragment = getListOfFilesFragment();
+                                if (fileListFragment != null) {
+                                    fileListFragment.listDirectory(currentDir);
+                                }
+                            }
+                            setFile(currentFile);
+                        }
+                        
+                        mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event));
+                                
+                        if (SynchronizeFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.
+                                    equals(event) &&
+                                /// TODO refactor and make common
+                                synchResult != null && !synchResult.isSuccess() &&  
+                                (synchResult.getCode() == ResultCode.UNAUTHORIZED   || 
+                                    synchResult.isIdPRedirection()                  ||
+                                    (synchResult.isException() && synchResult.getException() 
+                                            instanceof AuthenticatorException))) {
+
+                            OwnCloudClient client = null;
+                            try {
+                                OwnCloudAccount ocAccount = 
+                                        new OwnCloudAccount(getAccount(), context);
+                                client = (OwnCloudClientManagerFactory.getDefaultSingleton().
+                                        removeClientFor(ocAccount));
+                                // TODO get rid of these exceptions
+                            } catch (AccountNotFoundException e) {
+                                e.printStackTrace();
+                            } catch (AuthenticatorException e) {
+                                e.printStackTrace();
+                            } catch (OperationCanceledException e) {
+                                e.printStackTrace();
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                            }
+                            
+                            if (client != null) {
+                                OwnCloudCredentials cred = client.getCredentials();
+                                if (cred != null) {
+                                    AccountManager am = AccountManager.get(context);
+                                    if (cred.authTokenExpires()) {
+                                        am.invalidateAuthToken(
+                                                getAccount().type, 
+                                                cred.getAuthToken()
+                                        );
+                                    } else {
+                                        am.clearPassword(getAccount());
+                                    }
+                                }
+                            }
+                            
+                            requestCredentialsUpdate();
+                            
+                        }
+                    }
+                    removeStickyBroadcast(intent);
+                    Log_OC.d(TAG, "Setting progress visibility to " + mSyncInProgress);
+                    setSupportProgressBarIndeterminateVisibility(mSyncInProgress /*|| mRefreshSharesInProgress*/);
+
+                    setBackgroundText();
+                        
+                }
+                
+            } catch (RuntimeException e) {
+                // avoid app crashes after changing the serial id of RemoteOperationResult 
+                // in owncloud library with broadcast notifications pending to process
+                removeStickyBroadcast(intent);
+            }
+        }
+    }
+
+    
+
+    /**
+     * Shows the information of the {@link OCFile} received as a 
+     * parameter in the second fragment.
+     * 
+     * @param file          {@link OCFile} whose details will be shown
+     */
+    @Override
+    public void showDetails(OCFile file) {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+            
+    }
+
+
+    @Override
+    public void onRefresh() {
+        OCFileListFragment listOfFiles = getListOfFilesFragment();
+        if (listOfFiles != null) {
+            OCFile folder = listOfFiles.getCurrentFile();
+            if (folder != null) {
+                startSyncFolderOperation(folder);
+            }
+        }
+    }
+
+}

+ 29 - 1
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -53,12 +53,18 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
     private Context mContext;
     private OCFile mFile = null;
     private Vector<OCFile> mFiles = null;
+    private boolean mJustFolders;
 
     private FileDataStorageManager mStorageManager;
     private Account mAccount;
     private ComponentsGetter mTransferServiceGetter;
     
-    public FileListListAdapter(Context context, ComponentsGetter transferServiceGetter) {
+    public FileListListAdapter(
+            boolean justFolders, 
+            Context context, 
+            ComponentsGetter transferServiceGetter
+            ) {
+        mJustFolders = justFolders;
         mContext = context;
         mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
         mTransferServiceGetter = transferServiceGetter;
@@ -231,12 +237,34 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         }
         if (mStorageManager != null) {
             mFiles = mStorageManager.getFolderContent(mFile);
+            if (mJustFolders) {
+                mFiles = getFolders(mFiles);
+            }
         } else {
             mFiles = null;
         }
         notifyDataSetChanged();
     }
     
+    
+    /**
+     * Filter for getting only the folders
+     * @param files
+     * @return Vector<OCFile>
+     */
+    public Vector<OCFile> getFolders(Vector<OCFile> files) {
+        Vector<OCFile> ret = new Vector<OCFile>(); 
+        OCFile current = null; 
+        for (int i=0; i<files.size(); i++) {
+            current = files.get(i);
+            if (current.isFolder()) {
+                ret.add(current);
+            }
+        }
+        return ret;
+    }
+    
+    
     /**
      * Check if parent folder does not include 'S' permission and if file/folder
      * is shared with me

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

@@ -45,6 +45,8 @@ public class CreateFolderDialogFragment
 extends SherlockDialogFragment implements DialogInterface.OnClickListener {
 
     private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER";
+    
+    public static final String CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT";
 
     /**
      * Public factory method to create new CreateFolderDialogFragment instances.

+ 109 - 2
src/com/owncloud/android/ui/fragment/ExtendedListFragment.java

@@ -18,6 +18,8 @@
 
 package com.owncloud.android.ui.fragment;
 
+import java.util.ArrayList;
+
 import android.os.Bundle;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.view.LayoutInflater;
@@ -37,11 +39,17 @@ import com.owncloud.android.utils.Log_OC;
 /**
  *  TODO extending SherlockListFragment instead of SherlockFragment 
  */
-public class ExtendedListFragment extends SherlockFragment implements OnItemClickListener, SwipeRefreshLayout.OnRefreshListener{
+public class ExtendedListFragment extends SherlockFragment 
+implements OnItemClickListener, SwipeRefreshLayout.OnRefreshListener {
     
     private static final String TAG = ExtendedListFragment.class.getSimpleName();
 
     private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION"; 
+    private static final String KEY_INDEXES = "INDEXES";
+    private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
+    private static final String KEY_TOPS = "TOPS";
+    private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
+    private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
 
     protected ExtendedListView mList;
     
@@ -49,6 +57,15 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
     private SwipeRefreshLayout mRefreshEmptyLayout;
     private TextView mEmptyListMessage;
     
+    // Save the state of the scroll in browsing
+    private ArrayList<Integer> mIndexes;
+    private ArrayList<Integer> mFirstPositions;
+    private ArrayList<Integer> mTops;
+    private int mHeightCell = 0;
+
+    private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = null;
+    
+    
     public void setListAdapter(ListAdapter listAdapter) {
         mList.setAdapter(listAdapter);
         mList.invalidate();
@@ -62,7 +79,6 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         Log_OC.e(TAG, "onCreateView");
-        //mList = new ExtendedListView(getActivity());
         
         View v = inflater.inflate(R.layout.list_fragment, null);
         mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
@@ -90,11 +106,39 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
     }
 
     
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        
+        if (savedInstanceState != null) {
+            mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES);
+            mFirstPositions = savedInstanceState.getIntegerArrayList(KEY_FIRST_POSITIONS);
+            mTops = savedInstanceState.getIntegerArrayList(KEY_TOPS);
+            mHeightCell = savedInstanceState.getInt(KEY_HEIGHT_CELL);
+            setMessageForEmptyList(savedInstanceState.getString(KEY_EMPTY_LIST_MESSAGE));
+            
+        } else {
+            mIndexes = new ArrayList<Integer>();
+            mFirstPositions = new ArrayList<Integer>();
+            mTops = new ArrayList<Integer>();
+            mHeightCell = 0;
+        }
+    }    
+    
+    
     @Override
     public void onSaveInstanceState(Bundle savedInstanceState) {
         super.onSaveInstanceState(savedInstanceState);
         Log_OC.e(TAG, "onSaveInstanceState()");
         savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
+        savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
+        savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
+        savedInstanceState.putIntegerArrayList(KEY_TOPS, mTops);
+        savedInstanceState.putInt(KEY_HEIGHT_CELL, mHeightCell);
+        savedInstanceState.putString(KEY_EMPTY_LIST_MESSAGE, getEmptyViewText());
     }
 
     
@@ -126,6 +170,60 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
         }
     }
 
+
+    /*
+     * Restore index and position
+     */
+    protected void restoreIndexAndTopPosition() {
+        if (mIndexes.size() > 0) {  
+            // needs to be checked; not every browse-up had a browse-down before 
+            
+            int index = mIndexes.remove(mIndexes.size() - 1);
+            
+            int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
+            
+            int top = mTops.remove(mTops.size() - 1);
+            
+            mList.setSelectionFromTop(firstPosition, top);
+            
+            // Move the scroll if the selection is not visible
+            int indexPosition = mHeightCell*index;
+            int height = mList.getHeight();
+            
+            if (indexPosition > height) {
+                if (android.os.Build.VERSION.SDK_INT >= 11)
+                {
+                    mList.smoothScrollToPosition(index); 
+                }
+                else if (android.os.Build.VERSION.SDK_INT >= 8)
+                {
+                    mList.setSelectionFromTop(index, 0);
+                }
+                
+            }
+        }
+    }
+    
+    /*
+     * Save index and top position
+     */
+    protected void saveIndexAndTopPosition(int index) {
+        
+        mIndexes.add(index);
+        
+        int firstPosition = mList.getFirstVisiblePosition();
+        mFirstPositions.add(firstPosition);
+        
+        View view = mList.getChildAt(0);
+        int top = (view == null) ? 0 : view.getTop() ;
+
+        mTops.add(top);
+        
+        // Save the height of a cell
+        mHeightCell = (view == null || mHeightCell != 0) ? mHeightCell : view.getHeight();
+    }
+    
+    
     @Override
     public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
         // to be @overriden  
@@ -136,7 +234,16 @@ public class ExtendedListFragment extends SherlockFragment implements OnItemClic
         // to be @overriden
         mRefreshLayout.setRefreshing(false);
         mRefreshEmptyLayout.setRefreshing(false);
+        
+        if (mOnRefreshListener != null) {
+            mOnRefreshListener.onRefresh();
+        }
+    }
+    
+    public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
+        mOnRefreshListener = listener;
     }
+    
 
     /**
      * Enables swipe gesture

+ 7 - 0
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -191,6 +191,13 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
             item.setVisible(false);
             item.setEnabled(false);
         }
+
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
     }
 
     

+ 6 - 1
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java

@@ -90,7 +90,7 @@ public class LocalFileListFragment extends ExtendedListFragment {
     public void onActivityCreated(Bundle savedInstanceState) {
         Log_OC.i(TAG, "onActivityCreated() start");
         
-        super.onCreate(savedInstanceState);
+        super.onActivityCreated(savedInstanceState);
         mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity());
         setListAdapter(mAdapter);
         
@@ -111,6 +111,8 @@ public class LocalFileListFragment extends ExtendedListFragment {
                 listDirectory(file);
                 // notify the click to container Activity
                 mContainerActivity.onDirectoryClick(file);
+                // save index and top position
+                saveIndexAndTopPosition(position);
             
             } else {    /// Click on a file
                 ImageView checkBoxV = (ImageView) v.findViewById(R.id.custom_checkbox);
@@ -140,6 +142,9 @@ public class LocalFileListFragment extends ExtendedListFragment {
             parentDir = mDirectory.getParentFile();  // can be null
         }
         listDirectory(parentDir);
+
+        // restore index and top position
+        restoreIndexAndTopPosition();
     }
 
     

+ 81 - 148
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -18,10 +18,11 @@
 package com.owncloud.android.ui.fragment;
 
 import java.io.File;
-import java.util.ArrayList;
 
 import android.app.Activity;
+import android.content.Intent;
 import android.os.Bundle;
+import android.support.v4.widget.SwipeRefreshLayout;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -34,6 +35,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.FileMenuFilter;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.activity.MoveActivity;
 import com.owncloud.android.ui.adapter.FileListListAdapter;
 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
@@ -55,15 +57,14 @@ public class OCFileListFragment extends ExtendedListFragment {
     
     private static final String TAG = OCFileListFragment.class.getSimpleName();
 
-    private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ? OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
-    private static final String EXTRA_FILE = MY_PACKAGE + ".extra.FILE";
+    private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
+            OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
+            
+    public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
+    public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
+            
+    private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
 
-    private static final String KEY_INDEXES = "INDEXES";
-    private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
-    private static final String KEY_TOPS = "TOPS";
-    private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
-    private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
-    
     private FileFragment.ContainerActivity mContainerActivity;
    
     private OCFile mFile = null;
@@ -71,12 +72,6 @@ public class OCFileListFragment extends ExtendedListFragment {
     
     private OCFile mTargetFile;
 
-    // Save the state of the scroll in browsing
-    private ArrayList<Integer> mIndexes;
-    private ArrayList<Integer> mFirstPositions;
-    private ArrayList<Integer> mTops;
-
-    private int mHeightCell = 0;
     
     /**
      * {@inheritDoc}
@@ -87,15 +82,24 @@ public class OCFileListFragment extends ExtendedListFragment {
         Log_OC.e(TAG, "onAttach");
         try {
             mContainerActivity = (FileFragment.ContainerActivity) activity;
+            
         } catch (ClassCastException e) {
             throw new ClassCastException(activity.toString() + " must implement " + 
                     FileFragment.ContainerActivity.class.getSimpleName());
         }
+        try {
+            setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) activity);
+            
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + 
+                    SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
+        }
     }
 
     
     @Override
     public void onDetach() {
+        setOnRefreshListener(null);
         mContainerActivity = null;
         super.onDetach();
     }
@@ -108,26 +112,17 @@ public class OCFileListFragment extends ExtendedListFragment {
         super.onActivityCreated(savedInstanceState);
         Log_OC.e(TAG, "onActivityCreated() start");
         
-        mAdapter = new FileListListAdapter(getSherlockActivity(), mContainerActivity); 
-                
         if (savedInstanceState != null) {
-            mFile = savedInstanceState.getParcelable(EXTRA_FILE);
-            mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES);
-            mFirstPositions = savedInstanceState.getIntegerArrayList(KEY_FIRST_POSITIONS);
-            mTops = savedInstanceState.getIntegerArrayList(KEY_TOPS);
-            mHeightCell = savedInstanceState.getInt(KEY_HEIGHT_CELL);
-            setMessageForEmptyList(savedInstanceState.getString(KEY_EMPTY_LIST_MESSAGE));
-            
-        } else {
-            mIndexes = new ArrayList<Integer>();
-            mFirstPositions = new ArrayList<Integer>();
-            mTops = new ArrayList<Integer>();
-            mHeightCell = 0;
-            
+            mFile = savedInstanceState.getParcelable(KEY_FILE);
         }
         
-        mAdapter = new FileListListAdapter(getSherlockActivity(), mContainerActivity);
-        
+        Bundle args = getArguments();
+        boolean justFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false); 
+        mAdapter = new FileListListAdapter(
+                justFolders,
+                getSherlockActivity(), 
+                mContainerActivity
+        );
         setListAdapter(mAdapter);
         
         registerForContextMenu(getListView());
@@ -140,19 +135,14 @@ public class OCFileListFragment extends ExtendedListFragment {
     @Override
     public void onSaveInstanceState (Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putParcelable(EXTRA_FILE, mFile);
-        outState.putIntegerArrayList(KEY_INDEXES, mIndexes);
-        outState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
-        outState.putIntegerArrayList(KEY_TOPS, mTops);
-        outState.putInt(KEY_HEIGHT_CELL, mHeightCell);
-        outState.putString(KEY_EMPTY_LIST_MESSAGE, getEmptyViewText());
+        outState.putParcelable(KEY_FILE, mFile);
     }
     
     /**
      * Call this, when the user presses the up button.
      * 
-     * Tries to move up the current folder one level. If the parent folder was removed from the database, 
-     * it continues browsing up until finding an existing folders.
+     * Tries to move up the current folder one level. If the parent folder was removed from the 
+     * database, it continues browsing up until finding an existing folders.
      * 
      * return       Count of folder levels browsed up.
      */
@@ -166,25 +156,25 @@ public class OCFileListFragment extends ExtendedListFragment {
             String parentPath = null;
             if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
                 parentPath = new File(mFile.getRemotePath()).getParent();
-                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
+                	parentPath + OCFile.PATH_SEPARATOR;
                 parentDir = storageManager.getFileByPath(parentPath);
                 moveCount++;
             } else {
-                parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);    // never returns null; keep the path in root folder
+                parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
             }
             while (parentDir == null) {
                 parentPath = new File(parentPath).getParent();
-                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+                parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : 
+                	parentPath + OCFile.PATH_SEPARATOR;
                 parentDir = storageManager.getFileByPath(parentPath);
                 moveCount++;
             }   // exit is granted because storageManager.getFileByPath("/") never returns null
-            mFile = parentDir;           
-        }
-        
-        if (mFile != null) {
+            mFile = parentDir;
+            
             listDirectory(mFile);
 
-            ((FileDisplayActivity)mContainerActivity).startSyncFolderOperation(mFile);
+            onRefresh();
             
             // restore index and top position
             restoreIndexAndTopPosition();
@@ -194,58 +184,6 @@ public class OCFileListFragment extends ExtendedListFragment {
         return moveCount;
     }
     
-    /*
-     * Restore index and position
-     */
-    private void restoreIndexAndTopPosition() {
-        if (mIndexes.size() > 0) {  
-            // needs to be checked; not every browse-up had a browse-down before 
-            
-            int index = mIndexes.remove(mIndexes.size() - 1);
-            
-            int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
-            
-            int top = mTops.remove(mTops.size() - 1);
-            
-            mList.setSelectionFromTop(firstPosition, top);
-            
-            // Move the scroll if the selection is not visible
-            int indexPosition = mHeightCell*index;
-            int height = mList.getHeight();
-            
-            if (indexPosition > height) {
-                if (android.os.Build.VERSION.SDK_INT >= 11)
-                {
-                    mList.smoothScrollToPosition(index); 
-                }
-                else if (android.os.Build.VERSION.SDK_INT >= 8)
-                {
-                    mList.setSelectionFromTop(index, 0);
-                }
-                
-            }
-        }
-    }
-    
-    /*
-     * Save index and top position
-     */
-    private void saveIndexAndTopPosition(int index) {
-        
-        mIndexes.add(index);
-        
-        int firstPosition = mList.getFirstVisiblePosition();
-        mFirstPositions.add(firstPosition);
-        
-        View view = mList.getChildAt(0);
-        int top = (view == null) ? 0 : view.getTop() ;
-
-        mTops.add(top);
-        
-        // Save the height of a cell
-        mHeightCell = (view == null || mHeightCell != 0) ? mHeightCell : view.getHeight();
-    }
-    
     @Override
     public void onItemClick(AdapterView<?> l, View v, int position, long id) {
         OCFile file = (OCFile) mAdapter.getItem(position);
@@ -253,7 +191,7 @@ public class OCFileListFragment extends ExtendedListFragment {
             if (file.isFolder()) { 
                 // update state and view of this fragment
                 listDirectory(file);
-                // then, notify parent activity to let it update its state and view, and other fragments
+                // then, notify parent activity to let it update its state and view
                 mContainerActivity.onBrowsedDownTo(file);
                 // save index and top position
                 saveIndexAndTopPosition(position);
@@ -288,42 +226,46 @@ public class OCFileListFragment extends ExtendedListFragment {
      * {@inheritDoc}
      */
     @Override
-    public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+    public void onCreateContextMenu (
+            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
-        MenuInflater inflater = getSherlockActivity().getMenuInflater();
-        inflater.inflate(R.menu.file_actions_menu, menu);
-        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
-        OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
-        
-        if (mContainerActivity.getStorageManager() != null) {
-            FileMenuFilter mf = new FileMenuFilter(
-                targetFile,
-                mContainerActivity.getStorageManager().getAccount(),
-                mContainerActivity,
-                getSherlockActivity()
-            );
-            mf.filter(menu);
-        }
-        
-        /// 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);
-        }
-        /// 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);
+        Bundle args = getArguments();
+        boolean allowContextualActions = 
+                (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true); 
+        if (allowContextualActions) {
+            MenuInflater inflater = getSherlockActivity().getMenuInflater();
+            inflater.inflate(R.menu.file_actions_menu, menu);
+            AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+            OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
+            
+            if (mContainerActivity.getStorageManager() != null) {
+                FileMenuFilter mf = new FileMenuFilter(
+                    targetFile,
+                    mContainerActivity.getStorageManager().getAccount(),
+                    mContainerActivity,
+                    getSherlockActivity()
+                );
+                mf.filter(menu);
+            }
+            
+            /// 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);
             }
+            /// 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);
+                }
+            }
         }
-        
-
     }
     
     
@@ -378,6 +320,14 @@ public class OCFileListFragment extends ExtendedListFragment {
                 }
                 return true;
             }
+            case R.id.action_move: {
+                Intent action = new Intent(getActivity(), MoveActivity.class);
+
+                // Pass mTargetFile that contains info of selected file/folder
+                action.putExtra(MoveActivity.EXTRA_TARGET_FILE, mTargetFile);
+                getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
+                return true;
+            }
             default:
                 return super.onContextItemSelected(item); 
         }
@@ -436,21 +386,4 @@ public class OCFileListFragment extends ExtendedListFragment {
         }
     }
 
-
-    @Override
-    public void onRefresh() {
-        super.onRefresh();
-        
-        if (mFile != null) {
-            // Refresh mFile
-            mFile = mContainerActivity.getStorageManager().getFileById(mFile.getFileId());
-
-            listDirectory(mFile);
-            
-            ((FileDisplayActivity)mContainerActivity).startSyncFolderOperation(mFile);
-        }
-    }
-    
-    
-    
 }

+ 7 - 0
src/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -232,6 +232,13 @@ public class PreviewImageFragment extends FileFragment {
             item.setVisible(false);
             item.setEnabled(false);
         }
+
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
         
     }
 

+ 7 - 0
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -289,6 +289,13 @@ public class PreviewMediaFragment extends FileFragment implements
             item.setVisible(false);
             item.setEnabled(false);
         }
+
+        // additional restriction for this fragment
+        item = menu.findItem(R.id.action_move);
+        if (item != null) {
+            item.setVisible(false);
+            item.setEnabled(false);
+        }
     }
     
     

+ 20 - 0
src/com/owncloud/android/utils/ErrorMessageAdapter.java

@@ -32,6 +32,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo
 import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.CreateShareOperation;
 import com.owncloud.android.operations.DownloadFileOperation;
+import com.owncloud.android.operations.MoveFileOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
@@ -186,6 +187,25 @@ public class ErrorMessageAdapter {
                 // Show a Message, operation finished without success
                 message = res.getString(R.string.unshare_link_file_error);
             }
+        } else if (operation instanceof MoveFileOperation) {
+
+            if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                message = res.getString(R.string.move_file_not_found);
+                
+            } else if (result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT)  {
+                message = res.getString(R.string.move_file_invalid_into_descendent);
+
+            } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
+                message = res.getString(R.string.move_file_invalid_overwrite);
+
+            } else if (result.getCode() == ResultCode.FORBIDDEN) {
+                message = String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.forbidden_permissions_move));
+
+            }else {    // Generic error
+                // Show a Message, operation finished without success
+                message = res.getString(R.string.move_file_error);
+            }
         }
         
         return message;