X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/5a4b0731f05293e3c641aa87c0d564f74a6b0b42..afaa2879d192be067cae523b51dad75d89a6c6cb:/src/com/owncloud/android/operations/SynchronizeFolderOperation.java diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 534e16ab..286b5ea9 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -1,5 +1,8 @@ -/* ownCloud Android client application - * Copyright (C) 2012-2014 ownCloud Inc. +/** + * ownCloud Android client application + * + * @author David A. Velasco + * Copyright (C) 2015 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 +25,7 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; @@ -34,6 +38,7 @@ import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation; import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.services.OperationsService; import com.owncloud.android.utils.FileStorageUtils; import java.io.File; @@ -55,8 +60,6 @@ import java.util.concurrent.atomic.AtomicBoolean; * properties, and updates the local database with them. * * Does NOT enter in the child folders to synchronize their contents also. - * - * @author David A. Velasco */ public class SynchronizeFolderOperation extends SyncOperation { @@ -88,7 +91,6 @@ public class SynchronizeFolderOperation extends SyncOperation { /** 'True' means that the remote folder changed and should be fetched */ private boolean mRemoteFolderChanged; - private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); private List mFilesForDirectDownload; // to avoid extra PROPFINDs when there was no change in the folder @@ -99,8 +101,7 @@ public class SynchronizeFolderOperation extends SyncOperation { private List mFavouriteFilesToSyncContents; // this will be used for every file when 'folder synchronization' replaces 'folder download' - private List mFoldersToWalkDown; - + private final AtomicBoolean mCancellationRequested; /** * Creates a new instance of {@link SynchronizeFolderOperation}. @@ -110,7 +111,8 @@ public class SynchronizeFolderOperation extends SyncOperation { * @param account ownCloud account where the folder is located. * @param currentSyncTime Time stamp for the synchronization process in progress. */ - public SynchronizeFolderOperation(Context context, String remotePath, Account account, long currentSyncTime){ + public SynchronizeFolderOperation(Context context, String remotePath, Account account, + long currentSyncTime){ mRemotePath = remotePath; mCurrentSyncTime = currentSyncTime; mAccount = account; @@ -119,8 +121,7 @@ public class SynchronizeFolderOperation extends SyncOperation { mFilesForDirectDownload = new Vector(); mFilesToSyncContentsWithoutUpload = new Vector(); mFavouriteFilesToSyncContents = new Vector(); - mFoldersToWalkDown = new Vector(); - + mCancellationRequested = new AtomicBoolean(false); } @@ -142,41 +143,50 @@ public class SynchronizeFolderOperation extends SyncOperation { RemoteOperationResult result = null; mFailsInFileSyncsFound = 0; mConflictsFound = 0; - - synchronized(mCancellationRequested) { - if (mCancellationRequested.get()) { - return new RemoteOperationResult(new OperationCancelledException()); - } - } - - // get locally cached information about folder - mLocalFolder = getStorageManager().getFileByPath(mRemotePath); - result = checkForChanges(client); - - if (result.isSuccess()) { - if (mRemoteFolderChanged) { - result = fetchAndSyncRemoteFolder(client); + try { + // get locally cached information about folder + mLocalFolder = getStorageManager().getFileByPath(mRemotePath); + + result = checkForChanges(client); + + if (result.isSuccess()) { + if (mRemoteFolderChanged) { + result = fetchAndSyncRemoteFolder(client); + + } else { + prepareOpsFromLocalKnowledge(); + } - } else { - prepareOpsFromLocalKnowledge(); + if (result.isSuccess()) { + syncContents(client); + } + } - if (result.isSuccess()) { - syncContents(client); + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); } + + } catch (OperationCancelledException e) { + result = new RemoteOperationResult(e); } return result; } - private RemoteOperationResult checkForChanges(OwnCloudClient client) { + private RemoteOperationResult checkForChanges(OwnCloudClient client) + throws OperationCancelledException { Log_OC.d(TAG, "Checking changes in " + mAccount.name + mRemotePath); mRemoteFolderChanged = true; RemoteOperationResult result = null; + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + // remote request ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mRemotePath); result = operation.execute(client); @@ -204,13 +214,19 @@ public class SynchronizeFolderOperation extends SyncOperation { Log_OC.e(TAG, "Checked " + mAccount.name + mRemotePath + " : " + result.getLogMessage()); } + } return result; } - private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) { + private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) + throws OperationCancelledException { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + ReadRemoteFolderOperation operation = new ReadRemoteFolderOperation(mRemotePath); RemoteOperationResult result = operation.execute(client); Log_OC.d(TAG, "Synchronizing " + mAccount.name + mRemotePath); @@ -238,7 +254,8 @@ public class SynchronizeFolderOperation extends SyncOperation { storageManager.removeFolder( mLocalFolder, true, - ( mLocalFolder.isDown() && // TODO: debug, I think this is always false for folders + ( mLocalFolder.isDown() && // TODO: debug, I think this is + // always false for folders mLocalFolder.getStoragePath().startsWith(currentSavePath) ) ); @@ -258,7 +275,8 @@ public class SynchronizeFolderOperation extends SyncOperation { * retrieved. * @return 'True' when any change was made in the local data, 'false' otherwise */ - private void synchronizeData(ArrayList folderAndFiles, OwnCloudClient client) { + private void synchronizeData(ArrayList folderAndFiles, OwnCloudClient client) + throws OperationCancelledException { FileDataStorageManager storageManager = getStorageManager(); // parse data from remote folder @@ -273,7 +291,10 @@ public class SynchronizeFolderOperation extends SyncOperation { mFilesForDirectDownload.clear(); mFilesToSyncContentsWithoutUpload.clear(); mFavouriteFilesToSyncContents.clear(); - mFoldersToWalkDown.clear(); + + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } // get current data about local contents of the folder to synchronize List localFiles = storageManager.getFolderContent(mLocalFolder); @@ -311,7 +332,8 @@ public class SynchronizeFolderOperation extends SyncOperation { remoteFile.setFileLength(localFile.getFileLength()); // TODO move operations about size of folders to FileContentProvider } else if (mRemoteFolderChanged && remoteFile.isImage() && - remoteFile.getModificationTimestamp() != localFile.getModificationTimestamp()) { + remoteFile.getModificationTimestamp() != + localFile.getModificationTimestamp()) { remoteFile.setNeedsUpdateThumbnail(true); Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server"); } @@ -329,14 +351,13 @@ public class SynchronizeFolderOperation extends SyncOperation { /// classify file to sync/download contents later if (remoteFile.isFolder()) { /// to download children files recursively - SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( - mContext, - remoteFile.getRemotePath(), - mAccount, - mCurrentSyncTime - ); - mFoldersToWalkDown.add(synchFolderOp); - + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + startSyncFolderOperation(remoteFile.getRemotePath()); + } + } else if (remoteFile.keepInSync()) { /// prepare content synchronization for kept-in-sync files SynchronizeFileOperation operation = new SynchronizeFileOperation( @@ -370,20 +391,19 @@ public class SynchronizeFolderOperation extends SyncOperation { } - private void prepareOpsFromLocalKnowledge() { + private void prepareOpsFromLocalKnowledge() throws OperationCancelledException { List children = getStorageManager().getFolderContent(mLocalFolder); for (OCFile child : children) { /// classify file to sync/download contents later if (child.isFolder()) { /// to download children files recursively - SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( - mContext, - child.getRemotePath(), - mAccount, - mCurrentSyncTime - ); - mFoldersToWalkDown.add(synchFolderOp); - + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + startSyncFolderOperation(child.getRemotePath()); + } + } else { /// prepare limited synchronization for regular files if (!child.isDown()) { @@ -394,20 +414,24 @@ public class SynchronizeFolderOperation extends SyncOperation { } - private void syncContents(OwnCloudClient client) { + private void syncContents(OwnCloudClient client) throws OperationCancelledException { startDirectDownloads(); startContentSynchronizations(mFilesToSyncContentsWithoutUpload, client); startContentSynchronizations(mFavouriteFilesToSyncContents, client); - walkSubfolders(client); // this must be the last! } - private void startDirectDownloads() { + private void startDirectDownloads() throws OperationCancelledException { for (OCFile file : mFilesForDirectDownload) { - Intent i = new Intent(mContext, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); - i.putExtra(FileDownloader.EXTRA_FILE, file); - mContext.startService(i); + synchronized(mCancellationRequested) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } + Intent i = new Intent(mContext, FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); + i.putExtra(FileDownloader.EXTRA_FILE, file); + mContext.startService(i); + } } } @@ -421,9 +445,16 @@ public class SynchronizeFolderOperation extends SyncOperation { * @param filesToSyncContents Synchronization operations to execute. * @param client Interface to the remote ownCloud server. */ - private void startContentSynchronizations(List filesToSyncContents, OwnCloudClient client) { + private void startContentSynchronizations(List filesToSyncContents, + OwnCloudClient client) + throws OperationCancelledException { + + Log_OC.v(TAG, "Starting content synchronization... "); RemoteOperationResult contentsResult = null; for (SyncOperation op: filesToSyncContents) { + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); + } contentsResult = op.execute(getStorageManager(), mContext); if (!contentsResult.isSuccess()) { if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) { @@ -443,26 +474,10 @@ public class SynchronizeFolderOperation extends SyncOperation { } } - - private void walkSubfolders(OwnCloudClient client) { - RemoteOperationResult contentsResult = null; - for (SyncOperation op: mFoldersToWalkDown) { - contentsResult = op.execute(client, getStorageManager()); // to watch out: possibly deep recursion - if (!contentsResult.isSuccess()) { - // TODO - some kind of error count, and use it with notifications - if (contentsResult.getException() != null) { - Log_OC.e(TAG, "Non blocking exception : " - + contentsResult.getLogMessage(), contentsResult.getException()); - } else { - Log_OC.e(TAG, "Non blocking error : " + contentsResult.getLogMessage()); - } - } // won't let these fails break the synchronization process - } - } - - + /** - * Creates and populates a new {@link com.owncloud.android.datamodel.OCFile} object with the data read from the server. + * Creates and populates a new {@link com.owncloud.android.datamodel.OCFile} + * object with the data read from the server. * * @param remote remote file read from the server (remote file or folder). * @return New OCFile instance representing the remote resource described by we. @@ -482,8 +497,8 @@ public class SynchronizeFolderOperation extends SyncOperation { /** * Scans the default location for saving local copies of files searching for - * a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile} received as - * parameter. + * a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile} + * received as parameter. * * @param file File to associate a possible 'lost' local file. */ @@ -501,9 +516,27 @@ public class SynchronizeFolderOperation extends SyncOperation { /** * Cancel operation */ - public void cancel(){ - // WIP Cancel the sync operation + public void cancel() { mCancellationRequested.set(true); } + public String getFolderPath() { + String path = mLocalFolder.getStoragePath(); + if (path != null && path.length() > 0) { + return path; + } + return FileStorageUtils.getDefaultSavePathFor(mAccount.name, mLocalFolder); + } + + private void startSyncFolderOperation(String path){ + Intent intent = new Intent(mContext, OperationsService.class); + intent.setAction(OperationsService.ACTION_SYNC_FOLDER); + intent.putExtra(OperationsService.EXTRA_ACCOUNT, mAccount); + intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, path); + mContext.startService(intent); + } + + public String getRemotePath() { + return mRemotePath; + } }