X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/bd38627e14eeb75039be0c46717b7c7e8f783923..ff2271a8c531efe4c2602c63934eca568c397510:/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 b25fa1b8..71c6d437 100644 --- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -23,10 +23,15 @@ import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; import android.accounts.Account; +import android.content.Context; +import android.content.Intent; import android.util.Log; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import eu.alefzero.webdav.WebdavClient; import eu.alefzero.webdav.WebdavEntry; @@ -35,49 +40,111 @@ import eu.alefzero.webdav.WebdavUtils; public class SynchronizeFileOperation extends RemoteOperation { private String TAG = SynchronizeFileOperation.class.getSimpleName(); - private String mRemotePath; - private DataStorageManager mStorageManager; - private Account mAccount; + private boolean mSyncFileContents; + private boolean mLocalChangeAlreadyKnown; + private Context mContext; + + private boolean mTransferWasRequested = false; public SynchronizeFileOperation( String remotePath, DataStorageManager dataStorageManager, - Account account) { + Account account, + boolean syncFileContents, + boolean localChangeAlreadyKnown, + Context context) { + mRemotePath = remotePath; mStorageManager = dataStorageManager; mAccount = account; + mSyncFileContents = syncFileContents; + mLocalChangeAlreadyKnown = localChangeAlreadyKnown; + mContext = context; } + @Override protected RemoteOperationResult run(WebdavClient client) { + PropFindMethod propfind = null; RemoteOperationResult result = null; + mTransferWasRequested = false; try { - propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath)); - int status = client.executeMethod(propfind); - boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS; - Boolean isConflict = Boolean.FALSE; - if (isMultiStatus) { - MultiStatus resp = propfind.getResponseBodyAsMultiStatus(); - WebdavEntry we = new WebdavEntry(resp.getResponses()[0], + OCFile localFile = mStorageManager.getFileByPath(mRemotePath); + + if (!localFile.isDown()) { + /// easy decision + requestForDownload(localFile); + result = new RemoteOperationResult(ResultCode.OK); + + } else { + /// local copy in the device -> need to think a bit more before do nothing + + propfind = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath)); + int status = client.executeMethod(propfind); + boolean isMultiStatus = status == HttpStatus.SC_MULTI_STATUS; + if (isMultiStatus) { + MultiStatus resp = propfind.getResponseBodyAsMultiStatus(); + WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getBaseUri().getPath()); - OCFile file = fillOCFile(we); - OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath()); - if (oldFile.getFileLength() != file.getFileLength() || - oldFile.getModificationTimestamp() != file.getModificationTimestamp()) { - isConflict = Boolean.TRUE; - } + OCFile serverFile = fillOCFile(we); + + /// check changes in server and local file + boolean serverChanged = false; + if (serverFile.getEtag() != null) { + serverChanged = (!serverFile.getEtag().equals(localFile.getEtag())); + } else { + // server without etags + serverChanged = (serverFile.getModificationTimestamp() > localFile.getModificationTimestamp()); + } + boolean localChanged = (mLocalChangeAlreadyKnown || localFile.getLocalModificationTimestamp() > localFile.getLastSyncDateForData()); + + /// decide action to perform depending upon changes + if (localChanged && serverChanged) { + // conflict + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); + + } else if (localChanged) { + if (mSyncFileContents) { + requestForUpload(localFile); + // 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 + // that an upload is necessary (for instance, in FileObserverService). + } + result = new RemoteOperationResult(ResultCode.OK); + + } else if (serverChanged) { + if (mSyncFileContents) { + requestForDownload(serverFile); + // 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? + serverFile.setKeepInSync(localFile.keepInSync()); + serverFile.setParentId(localFile.getParentId()); + mStorageManager.saveFile(serverFile); + + } + result = new RemoteOperationResult(ResultCode.OK); - } else { - client.exhaustResponse(propfind.getResponseBodyAsStream()); - } + } else { + // nothing changed, nothing to do + result = new RemoteOperationResult(ResultCode.OK); + } + + } else { + client.exhaustResponse(propfind.getResponseBodyAsStream()); + result = new RemoteOperationResult(false, status); + } + + } + + Log.i(TAG, "Synchronizing " + mAccount.name + ", file " + mRemotePath + ": " + result.getLogMessage()); - result = new RemoteOperationResult(isMultiStatus, status); - result.setExtraData(isConflict); - Log.i(TAG, "Synchronizing " + mAccount.name + ", file " + mRemotePath + ": " + result.getLogMessage()); } catch (Exception e) { result = new RemoteOperationResult(e); Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + mRemotePath + ": " + result.getLogMessage(), result.getException()); @@ -88,8 +155,40 @@ public class SynchronizeFileOperation extends RemoteOperation { } return result; } + /** + * Requests for an upload to the FileUploader service + * + * @param localFile OCFile object representing the file to upload + */ + private void requestForUpload(OCFile localFile) { + Intent i = new Intent(mContext, FileUploader.class); + i.putExtra(FileUploader.KEY_ACCOUNT, mAccount); + i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); + 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); + mContext.startService(i); + mTransferWasRequested = true; + } + + + /** + * Requests for a download to the FileDownloader service + * + * @param file OCFile object representing the file to download + */ + private void requestForDownload(OCFile file) { + Intent i = new Intent(mContext, FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); + i.putExtra(FileDownloader.EXTRA_FILE, file); + mContext.startService(i); + mTransferWasRequested = true; + } + + + /** * Creates and populates a new {@link OCFile} object with the data read from the server. * * @param we WebDAV entry read from the server for a WebDAV resource (remote file or folder). @@ -101,8 +200,14 @@ public class SynchronizeFileOperation extends RemoteOperation { file.setFileLength(we.contentLength()); file.setMimetype(we.contentType()); file.setModificationTimestamp(we.modifiedTimesamp()); - file.setLastSyncDate(System.currentTimeMillis()); + file.setLastSyncDateForProperties(System.currentTimeMillis()); + file.setLastSyncDateForData(0); return file; } + + public boolean transferWasRequested() { + return mTransferWasRequested; + } + }