X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/737381eaad33262ebd06cd2a4954f1baa19dead4..refs/heads/sdcard-save:/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 957cf627..675295a3 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, @@ -17,11 +20,19 @@ package com.owncloud.android.operations; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + import android.accounts.Account; import android.content.Context; import android.content.Intent; import android.util.Log; + import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; @@ -34,14 +45,9 @@ 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; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Vector; import java.util.concurrent.atomic.AtomicBoolean; //import android.support.v4.content.LocalBroadcastManager; @@ -54,9 +60,8 @@ import java.util.concurrent.atomic.AtomicBoolean; * Fetches the list and properties of the files contained in the given folder, including their * properties, and updates the local database with them. * - * Does NOT enter in the child folders to synchronize their contents also. - * - * @author David A. Velasco + * Does NOT enter in the child folders to synchronize their contents also, BUT requests for a new operation instance + * doing so. */ public class SynchronizeFolderOperation extends SyncOperation { @@ -92,14 +97,9 @@ public class SynchronizeFolderOperation extends SyncOperation { private List mFilesForDirectDownload; // to avoid extra PROPFINDs when there was no change in the folder - private List mFilesToSyncContentsWithoutUpload; - // this will go out when 'folder synchronization' replaces 'folder download'; step by step - - private List mFavouriteFilesToSyncContents; + private List mFilesToSyncContents; // this will be used for every file when 'folder synchronization' replaces 'folder download' - private List mFoldersToWalkDown; - private final AtomicBoolean mCancellationRequested; /** @@ -110,16 +110,15 @@ 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; mContext = context; mRemoteFolderChanged = false; mFilesForDirectDownload = new Vector(); - mFilesToSyncContentsWithoutUpload = new Vector(); - mFavouriteFilesToSyncContents = new Vector(); - mFoldersToWalkDown = new Vector(); + mFilesToSyncContents = new Vector(); mCancellationRequested = new AtomicBoolean(false); } @@ -161,9 +160,6 @@ public class SynchronizeFolderOperation extends SyncOperation { syncContents(client); } - if (mFilesForDirectDownload.isEmpty()) { - sendBroadcastForNotifyingUIUpdate(result.isSuccess()); - } } if (mCancellationRequested.get()) { @@ -172,21 +168,14 @@ public class SynchronizeFolderOperation extends SyncOperation { } catch (OperationCancelledException e) { result = new RemoteOperationResult(e); - - /// 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) throws OperationCancelledException { + private RemoteOperationResult checkForChanges(OwnCloudClient client) + throws OperationCancelledException { Log_OC.d(TAG, "Checking changes in " + mAccount.name + mRemotePath); mRemoteFolderChanged = true; @@ -224,14 +213,14 @@ public class SynchronizeFolderOperation extends SyncOperation { result.getLogMessage()); } - sendBroadcastForNotifyingUIUpdate(result.isSuccess()); } return result; } - private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) throws OperationCancelledException { + private RemoteOperationResult fetchAndSyncRemoteFolder(OwnCloudClient client) + throws OperationCancelledException { if (mCancellationRequested.get()) { throw new OperationCancelledException(); } @@ -263,7 +252,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) ) ); @@ -288,7 +278,7 @@ public class SynchronizeFolderOperation extends SyncOperation { FileDataStorageManager storageManager = getStorageManager(); // parse data from remote folder - OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0)); + OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(0)); remoteFolder.setParentId(mLocalFolder.getParentId()); remoteFolder.setFileId(mLocalFolder.getFileId()); @@ -297,109 +287,93 @@ public class SynchronizeFolderOperation extends SyncOperation { List updatedFiles = new Vector(folderAndFiles.size() - 1); mFilesForDirectDownload.clear(); - mFilesToSyncContentsWithoutUpload.clear(); - mFavouriteFilesToSyncContents.clear(); + mFilesToSyncContents.clear(); - synchronized(mFoldersToWalkDown) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - mFoldersToWalkDown.clear(); + if (mCancellationRequested.get()) { + throw new OperationCancelledException(); } // get current data about local contents of the folder to synchronize - List localFiles = storageManager.getFolderContent(mLocalFolder); + // TODO Enable when "On Device" is recovered ? + List localFiles = storageManager.getFolderContent(mLocalFolder/*, false*/); Map localFilesMap = new HashMap(localFiles.size()); for (OCFile file : localFiles) { localFilesMap.put(file.getRemotePath(), file); } // loop to synchronize every child - OCFile remoteFile = null, localFile = null; + OCFile remoteFile = null, localFile = null, updatedFile = null; + RemoteFile r; for (int i=1; i children = getStorageManager().getFolderContent(mLocalFolder); + // TODO Enable when "On Device" is recovered ? + List children = getStorageManager().getFolderContent(mLocalFolder/*, false*/); 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 - ); - - synchronized(mFoldersToWalkDown) { + synchronized(mCancellationRequested) { if (mCancellationRequested.get()) { throw new OperationCancelledException(); } - mFoldersToWalkDown.add(synchFolderOp); + startSyncFolderOperation(child.getRemotePath()); } } else { - /// prepare limited synchronization for regular files + /// synchronization for regular files if (!child.isDown()) { mFilesForDirectDownload.add(child); + + } else { + /// this should result in direct upload of files that were locally modified + SynchronizeFileOperation operation = new SynchronizeFileOperation( + child, + (child.getEtagInConflict() != null ? child : null), + mAccount, + true, + mContext + ); + mFilesToSyncContents.add(operation); + } + } } } @@ -440,21 +421,21 @@ public class SynchronizeFolderOperation extends SyncOperation { private void syncContents(OwnCloudClient client) throws OperationCancelledException { startDirectDownloads(); - startContentSynchronizations(mFilesToSyncContentsWithoutUpload, client); - startContentSynchronizations(mFavouriteFilesToSyncContents, client); - walkSubfolders(client); // this must be the last! + startContentSynchronizations(mFilesToSyncContents, client); } private void startDirectDownloads() throws OperationCancelledException { for (OCFile file : mFilesForDirectDownload) { - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); + 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); } - Intent i = new Intent(mContext, FileDownloader.class); - i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); - i.putExtra(FileDownloader.EXTRA_FILE, file); - mContext.startService(i); } } @@ -468,9 +449,11 @@ 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()) { @@ -495,50 +478,11 @@ public class SynchronizeFolderOperation extends SyncOperation { } } - - private void walkSubfolders(OwnCloudClient client) throws OperationCancelledException { - RemoteOperationResult contentsResult = null; - 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 - 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. - * - * @param remote remote file read from the server (remote file or folder). - * @return New OCFile instance representing the remote resource described by we. - */ - private OCFile fillOCFile(RemoteFile remote) { - OCFile file = new OCFile(remote.getRemotePath()); - file.setCreationTimestamp(remote.getCreationTimestamp()); - file.setFileLength(remote.getLength()); - file.setMimetype(remote.getMimeType()); - file.setModificationTimestamp(remote.getModifiedTimestamp()); - file.setEtag(remote.getEtag()); - file.setPermissions(remote.getPermissions()); - file.setRemoteId(remote.getRemoteId()); - return file; - } - - - /** * 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. */ @@ -552,29 +496,12 @@ public class SynchronizeFolderOperation extends SyncOperation { } } - 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() { mCancellationRequested.set(true); - - synchronized(mFoldersToWalkDown) { - // cancel 'child' synchronizations - for (SyncOperation synchOp : mFoldersToWalkDown) { - ((SynchronizeFolderOperation) synchOp).cancel(); - } - } } public String getFolderPath() { @@ -584,4 +511,16 @@ public class SynchronizeFolderOperation extends SyncOperation { } 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; + } }