/** 'True' means that the remote folder changed and should be fetched */
private boolean mRemoteFolderChanged;
- private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private List<OCFile> mFilesForDirectDownload;
// to avoid extra PROPFINDs when there was no change in the folder
private List<SyncOperation> mFoldersToWalkDown;
+ private final AtomicBoolean mCancellationRequested;
/**
* Creates a new instance of {@link SynchronizeFolderOperation}.
mAccount = account;
mContext = context;
mRemoteFolderChanged = false;
+ mFilesForDirectDownload = new Vector<OCFile>();
mFilesToSyncContentsWithoutUpload = new Vector<SyncOperation>();
mFavouriteFilesToSyncContents = new Vector<SyncOperation>();
mFoldersToWalkDown = new Vector<SyncOperation>();
-
+ mCancellationRequested = new AtomicBoolean(false);
}
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 (mFilesForDirectDownload.isEmpty()) {
+ sendBroadcastForNotifyingUIUpdate(result.isSuccess());
+ }
}
- if (result.isSuccess()) {
- syncContents(client);
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
}
+
+ } catch (OperationCancelledException e) {
+ result = new RemoteOperationResult(e);
+
+ // Needed in case that cancellation occurs before starting any download.
+ // If not, yellow arrow continues being shown.
+ sendBroadcastForNotifyingUIUpdate(result.isSuccess());
+
+ /// cancellation of download needs to be done separately in any case; a SynchronizeFolderOperation
+ // may finish much sooner than the real download of the files in the folder
+ Intent intent = new Intent(mContext, FileDownloader.class);
+ intent.setAction(FileDownloader.ACTION_CANCEL_FILE_DOWNLOAD);
+ intent.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+ intent.putExtra(FileDownloader.EXTRA_FILE, mLocalFolder);
+ mContext.startService(intent);
}
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);
Log_OC.e(TAG, "Checked " + mAccount.name + mRemotePath + " : " +
result.getLogMessage());
}
+
+ sendBroadcastForNotifyingUIUpdate(result.isSuccess());
}
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);
* retrieved.
* @return 'True' when any change was made in the local data, 'false' otherwise
*/
- private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client) {
+ private void synchronizeData(ArrayList<Object> folderAndFiles, OwnCloudClient client)
+ throws OperationCancelledException {
FileDataStorageManager storageManager = getStorageManager();
// parse data from remote folder
+ " changed - starting update of local data ");
List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
+ mFilesForDirectDownload.clear();
mFilesToSyncContentsWithoutUpload.clear();
mFavouriteFilesToSyncContents.clear();
- mFoldersToWalkDown.clear();
+
+ synchronized(mFoldersToWalkDown) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ mFoldersToWalkDown.clear();
+ }
// get current data about local contents of the folder to synchronize
List<OCFile> localFiles = storageManager.getFolderContent(mLocalFolder);
mAccount,
mCurrentSyncTime
);
- mFoldersToWalkDown.add(synchFolderOp);
-
+
+ synchronized(mFoldersToWalkDown) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ mFoldersToWalkDown.add(synchFolderOp);
+ }
+
} else if (remoteFile.keepInSync()) {
/// prepare content synchronization for kept-in-sync files
SynchronizeFileOperation operation = new SynchronizeFileOperation(
}
- private void prepareOpsFromLocalKnowledge() {
+ private void prepareOpsFromLocalKnowledge() throws OperationCancelledException {
List<OCFile> children = getStorageManager().getFolderContent(mLocalFolder);
for (OCFile child : children) {
/// classify file to sync/download contents later
mAccount,
mCurrentSyncTime
);
- mFoldersToWalkDown.add(synchFolderOp);
-
+
+ synchronized(mFoldersToWalkDown) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
+ mFoldersToWalkDown.add(synchFolderOp);
+ }
+
} else {
/// prepare limited synchronization for regular files
if (!child.isDown()) {
}
- private void syncContents(OwnCloudClient client) {
+ private void syncContents(OwnCloudClient client) throws OperationCancelledException {
startDirectDownloads();
startContentSynchronizations(mFilesToSyncContentsWithoutUpload, client);
startContentSynchronizations(mFavouriteFilesToSyncContents, client);
- walkSubfolders(mFoldersToWalkDown, client); // this must be the last!
+ walkSubfolders(client); // this must be the last!
}
- private void startDirectDownloads() {
+ private void startDirectDownloads() throws OperationCancelledException {
for (OCFile file : mFilesForDirectDownload) {
+ 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);
* @param filesToSyncContents Synchronization operations to execute.
* @param client Interface to the remote ownCloud server.
*/
- private void startContentSynchronizations(List<SyncOperation> filesToSyncContents, OwnCloudClient client) {
+ private void startContentSynchronizations(List<SyncOperation> filesToSyncContents, OwnCloudClient client)
+ throws OperationCancelledException {
+
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) {
}
- private void walkSubfolders(List<SyncOperation> foldersToWalkDown, OwnCloudClient client) {
+ private void walkSubfolders(OwnCloudClient client) throws OperationCancelledException {
RemoteOperationResult contentsResult = null;
- for (SyncOperation op: foldersToWalkDown) {
+ for (SyncOperation op: mFoldersToWalkDown) {
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
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
}
}
-
+
/**
* Creates and populates a new {@link com.owncloud.android.datamodel.OCFile} object with the data read from the server.
*
}
}
+ private void sendBroadcastForNotifyingUIUpdate(boolean result) {
+ // Send a broadcast message for notifying UI update
+ Intent uiUpdate = new Intent(FileDownloader.getDownloadFinishMessage());
+ uiUpdate.putExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, result);
+ uiUpdate.putExtra(FileDownloader.ACCOUNT_NAME, mAccount.name);
+ uiUpdate.putExtra(FileDownloader.EXTRA_REMOTE_PATH, mRemotePath);
+ uiUpdate.putExtra(FileDownloader.EXTRA_FILE_PATH, mLocalFolder.getRemotePath());
+ mContext.sendStickyBroadcast(uiUpdate);
+ }
+
/**
* Cancel operation
*/
- public void cancel(){
- // WIP Cancel the sync operation
+ public void cancel() {
mCancellationRequested.set(true);
+
+ synchronized(mFoldersToWalkDown) {
+ // cancel 'child' synchronizations
+ for (SyncOperation synchOp : mFoldersToWalkDown) {
+ ((SynchronizeFolderOperation) synchOp).cancel();
+ }
+ }
}
+ public String getFolderPath() {
+ String path = mLocalFolder.getStoragePath();
+ if (path != null && path.length() > 0) {
+ return path;
+ }
+ return FileStorageUtils.getDefaultSavePathFor(mAccount.name, mLocalFolder);
+ }
}