X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/2910b006735fc7848bd7f357458332a542871bb8..HEAD:/src/com/owncloud/android/operations/SynchronizeFileOperation.java diff --git a/src/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/com/owncloud/android/operations/SynchronizeFileOperation.java index c8ee1e2c..bc0caf19 100644 --- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -1,6 +1,10 @@ -/* ownCloud Android client application +/** + * ownCloud Android client application + * + * @author David A. Velasco + * @author masensio * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2012-2014 ownCloud Inc. + * 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, @@ -36,9 +40,6 @@ import android.content.Intent; /** * Remote operation performing the read of remote file in the ownCloud server. - * - * @author David A. Velasco - * @author masensio */ public class SynchronizeFileOperation extends SyncOperation { @@ -54,12 +55,21 @@ public class SynchronizeFileOperation extends SyncOperation { private boolean mTransferWasRequested = false; + /** + * When 'false', uploads to the server are not done; only downloads or conflict detection. + * This is a temporal field. + * TODO Remove when 'folder synchronization' replaces 'folder download'. + */ + private boolean mAllowUploads; + /** - * Constructor. + * Constructor for "full synchronization mode". * - * Uses remotePath to retrieve all the data in local cache and remote server when the operation - * is executed, instead of reusing {@link OCFile} instances. + * Uses remotePath to retrieve all the data both in local cache and in the remote OC server + * when the operation is executed, instead of reusing {@link OCFile} instances. + * + * Useful for direct synchronization of a single file. * * @param * @param account ownCloud account holding the file. @@ -79,17 +89,24 @@ public class SynchronizeFileOperation extends SyncOperation { mAccount = account; mSyncFileContents = syncFileContents; mContext = context; + mAllowUploads = true; } /** - * Constructor allowing to reuse {@link OCFile} instances just queried from cache or network. + * Constructor allowing to reuse {@link OCFile} instances just queried from local cache or + * from remote OC server. + * + * Useful to include this operation as part of the synchronization of a folder + * (or a full account), avoiding the repetition of fetch operations (both in local database + * or remote server). * - * Useful for folder / account synchronizations. + * At least one of localFile or serverFile MUST NOT BE NULL. If you don't have none of them, + * use the other constructor. * - * @param localFile Data of file currently hold in device cache. MUSTN't be null. - * @param serverFile Data of file just retrieved from network. If null, will be - * retrieved from network by the operation when executed. + * @param localFile Data of file (just) retrieved from local cache/database. + * @param serverFile Data of file (just) retrieved from a remote server. If null, + * will be retrieved from network by the operation when executed. * @param account ownCloud account holding the file. * @param syncFileContents When 'true', transference of data will be started by the * operation if needed and no conflict is detected. @@ -104,10 +121,57 @@ public class SynchronizeFileOperation extends SyncOperation { mLocalFile = localFile; mServerFile = serverFile; - mRemotePath = localFile.getRemotePath(); + if (mLocalFile != null) { + mRemotePath = mLocalFile.getRemotePath(); + if (mServerFile != null && !mServerFile.getRemotePath().equals(mRemotePath)) { + throw new IllegalArgumentException("serverFile and localFile do not correspond" + + " to the same OC file"); + } + } else if (mServerFile != null) { + mRemotePath = mServerFile.getRemotePath(); + } else { + throw new IllegalArgumentException("Both serverFile and localFile are NULL"); + } mAccount = account; mSyncFileContents = syncFileContents; mContext = context; + mAllowUploads = true; + } + + + /** + * Temporal constructor. + * + * Extends the previous one to allow constrained synchronizations where uploads are never + * performed - only downloads or conflict detection. + * + * Do not use unless you are involved in 'folder synchronization' or 'folder download' work + * in progress. + * + * TODO Remove when 'folder synchronization' replaces 'folder download'. + * + * @param localFile Data of file (just) retrieved from local cache/database. + * MUSTN't be null. + * @param serverFile Data of file (just) retrieved from a remote server. + * If null, will be retrieved from network by the operation + * when executed. + * @param account ownCloud account holding the file. + * @param syncFileContents When 'true', transference of data will be started by the + * operation if needed and no conflict is detected. + * @param allowUploads When 'false', uploads to the server are not done; + * only downloads or conflict detection. + * @param context Android context; needed to start transfers. + */ + public SynchronizeFileOperation( + OCFile localFile, + OCFile serverFile, + Account account, + boolean syncFileContents, + boolean allowUploads, + Context context) { + + this(localFile, serverFile, account, syncFileContents, context); + mAllowUploads = allowUploads; } @@ -143,42 +207,52 @@ public class SynchronizeFileOperation extends SyncOperation { /// check changes in server and local file boolean serverChanged = false; - /* time for eTag is coming, but not yet - if (mServerFile.getEtag() != null) { - serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged? - } else { */ - // server without etags - serverChanged = (mServerFile.getModificationTimestamp() != mLocalFile.getModificationTimestampAtLastSyncForData()); - //} - boolean localChanged = (mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()); - // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads + if (mLocalFile.getEtag() == null || mLocalFile.getEtag().length() == 0) { + // file uploaded (null) or downloaded ("") before upgrade to version 1.8.0; check the old condition + serverChanged = mServerFile.getModificationTimestamp() != + mLocalFile.getModificationTimestampAtLastSyncForData(); + } else { + serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); + } + boolean localChanged = ( + mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData() + ); /// decide action to perform depending upon changes //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) { if (localChanged && serverChanged) { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); + getStorageManager().saveConflict(mLocalFile, mServerFile.getEtag()); } else if (localChanged) { - if (mSyncFileContents) { + if (mSyncFileContents && mAllowUploads) { requestForUpload(mLocalFile); - // the local update of file properties will be done by the FileUploader service when the upload finishes + // the local update of file properties will be done by the FileUploader + // service when the upload finishes } else { - // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid; - // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect + // NOTHING TO DO HERE: updating the properties of the file in the server + // without uploading the contents would be stupid; + // So, an instance of SynchronizeFileOperation created with + // syncFileContents == false is completely useless when we suspect // that an upload is necessary (for instance, in FileObserverService). } result = new RemoteOperationResult(ResultCode.OK); } else if (serverChanged) { + mLocalFile.setRemoteId(mServerFile.getRemoteId()); + if (mSyncFileContents) { - requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync! - // the update of local data will be done later by the FileUploader service when the upload finishes + requestForDownload(mLocalFile); // local, not server; we won't to keep + // the value of favorite! + // the update of local data will be done later by the FileUploader + // service when the upload finishes } else { // TODO CHECK: is this really useful in some point in the code? - mServerFile.setKeepInSync(mLocalFile.keepInSync()); + mServerFile.setFavorite(mLocalFile.isFavorite()); mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData()); mServerFile.setStoragePath(mLocalFile.getStoragePath()); mServerFile.setParentId(mLocalFile.getParentId()); + mServerFile.setEtag(mLocalFile.getEtag()); getStorageManager().saveFile(mServerFile); } @@ -189,11 +263,16 @@ public class SynchronizeFileOperation extends SyncOperation { result = new RemoteOperationResult(ResultCode.OK); } - } + // safe blanket: sync'ing a not in-conflict file will clean wrong conflict markers in ancestors + if (result.getCode() != ResultCode.SYNC_CONFLICT) { + getStorageManager().saveConflict(mLocalFile, null); + } + } } - Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + + ": " + result.getLogMessage()); return result; } @@ -208,7 +287,9 @@ public class SynchronizeFileOperation extends SyncOperation { Intent i = new Intent(mContext, FileUploader.class); i.putExtra(FileUploader.KEY_ACCOUNT, mAccount); i.putExtra(FileUploader.KEY_FILE, file); - /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); // doing this we would lose the value of keepInSync in the road, and maybe it's not updated in the database when the FileUploader service gets it! + /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); + // doing this we would lose the value of isFavorite in the road, and maybe + // it's not updated in the database when the FileUploader service gets it! i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/ i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);