From: David A. Velasco Date: Thu, 3 Oct 2013 10:38:09 +0000 (+0200) Subject: Merge branch 'fixed_permanent_redirections' into refresh_folder_contents_when_browsed... X-Git-Tag: oc-android-1.5.5~155^2~26 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/8a27bf186a3985571447d364cc5989e2b8428a2c?hp=dad222191608dd903e7247615fe9abc1b6c74e39 Merge branch 'fixed_permanent_redirections' into refresh_folder_contents_when_browsed_into --- diff --git a/res/values/strings.xml b/res/values/strings.xml index 0872084a..400684b7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -129,6 +129,7 @@ Some local files were forgotten %1$d files out of the %2$s directory could not be copied into As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to. + Current folder was removed "Move all" "All files were moved" "Some files could not be moved" diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java index 5f6321d8..c60cdacc 100644 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -126,7 +126,7 @@ public class FileDataStorageManager implements DataStorageManager { cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); - if (file.getParentId() != 0) + if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID) cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); if (!file.isDirectory()) @@ -135,6 +135,7 @@ public class FileDataStorageManager implements DataStorageManager { cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties()); cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData()); cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); boolean sameRemotePath = fileExists(file.getRemotePath()); boolean changesSizeOfAncestors = false; @@ -222,7 +223,7 @@ public class FileDataStorageManager implements DataStorageManager { cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); - if (file.getParentId() != 0) + if (file.getParentId() != DataStorageManager.ROOT_PARENT_ID) cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); if (!file.isDirectory()) @@ -231,6 +232,7 @@ public class FileDataStorageManager implements DataStorageManager { cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties()); cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData()); cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); if (fileExists(file.getRemotePath())) { OCFile oldFile = getFileByPath(file.getRemotePath()); @@ -472,6 +474,8 @@ public class FileDataStorageManager implements DataStorageManager { getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA))); file.setKeepInSync(c.getInt( c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); + file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG))); + } return file; } @@ -674,7 +678,7 @@ public class FileDataStorageManager implements DataStorageManager { OCFile file; - while (parentId != 0) { + while (parentId != DataStorageManager.ROOT_PARENT_ID) { // Update the size of the parent calculateFolderSize(parentId); diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 6b8e1785..87a38a69 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -60,6 +60,7 @@ public class OCFile implements Parcelable, Comparable { private String mEtag; + /** * Create new {@link OCFile} with given path. * @@ -95,6 +96,7 @@ public class OCFile implements Parcelable, Comparable { mKeepInSync = source.readInt() == 1; mLastSyncDateForProperties = source.readLong(); mLastSyncDateForData = source.readLong(); + mEtag = source.readString(); } @Override @@ -112,6 +114,7 @@ public class OCFile implements Parcelable, Comparable { dest.writeInt(mKeepInSync ? 1 : 0); dest.writeLong(mLastSyncDateForProperties); dest.writeLong(mLastSyncDateForData); + dest.writeString(mEtag); } /** @@ -319,6 +322,7 @@ public class OCFile implements Parcelable, Comparable { mLastSyncDateForData = 0; mKeepInSync = false; mNeedsUpdating = false; + mEtag = null; } /** @@ -439,8 +443,8 @@ public class OCFile implements Parcelable, Comparable { @Override public String toString() { - String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s]"; - asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync)); + String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, keepInSinc=%s etag=%s]"; + asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mKeepInSync), mEtag); return asString; } @@ -448,6 +452,10 @@ public class OCFile implements Parcelable, Comparable { return mEtag; } + public void setEtag(String etag) { + this.mEtag = etag; + } + public long getLocalModificationTimestamp() { if (mLocalPath != null && mLocalPath.length() > 0) { File f = new File(mLocalPath); diff --git a/src/com/owncloud/android/db/ProviderMeta.java b/src/com/owncloud/android/db/ProviderMeta.java index b8058b89..521d4bbd 100644 --- a/src/com/owncloud/android/db/ProviderMeta.java +++ b/src/com/owncloud/android/db/ProviderMeta.java @@ -31,7 +31,7 @@ public class ProviderMeta { public static final String AUTHORITY_FILES = "org.owncloud"; public static final String DB_FILE = "owncloud.db"; public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 4; + public static final int DB_VERSION = 5; private ProviderMeta() { } @@ -61,6 +61,7 @@ public class ProviderMeta { public static final String FILE_LAST_SYNC_DATE = "last_sync_date"; // _for_properties, but let's keep it as it is public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data"; public static final String FILE_KEEP_IN_SYNC = "keep_in_sync"; + public static final String FILE_ETAG = "etag"; public static final String DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc"; diff --git a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java index 6eb6ec7b..fa8662f3 100644 --- a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java +++ b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java @@ -54,8 +54,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { Log_OC.d(TAG, "Received: " + intent.getAction()); if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) { handleConnectivityAction(context, intent); - } else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH && - intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) { + }else if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) { handleNewPhotoAction(context, intent); Log_OC.d(TAG, "UNOFFICIAL processed: com.android.camera.NEW_PICTURE"); } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) { diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 0f1e9cdb..c606b687 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -78,7 +78,6 @@ import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.InstantUploadActivity; import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; -import com.owncloud.android.utils.FileStorageUtils; import eu.alefzero.webdav.WebdavClient; @@ -272,7 +271,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe if (isInstant) { newUpload.setRemoteFolderToBeCreated(); } - mPendingUploads.putIfAbsent(uploadKey, newUpload); + mPendingUploads.putIfAbsent(uploadKey, newUpload); // Grants that the file only upload once time + newUpload.addDatatransferProgressListener(this); newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder); requestedUploads.add(uploadKey); diff --git a/src/com/owncloud/android/operations/ExistenceCheckOperation.java b/src/com/owncloud/android/operations/ExistenceCheckOperation.java index e404a6f8..136fe224 100644 --- a/src/com/owncloud/android/operations/ExistenceCheckOperation.java +++ b/src/com/owncloud/android/operations/ExistenceCheckOperation.java @@ -23,6 +23,7 @@ import org.apache.commons.httpclient.methods.HeadMethod; import com.owncloud.android.Log_OC; import eu.alefzero.webdav.WebdavClient; +import eu.alefzero.webdav.WebdavUtils; import android.content.Context; import android.net.ConnectivityManager; @@ -65,16 +66,16 @@ public class ExistenceCheckOperation extends RemoteOperation { RemoteOperationResult result = null; HeadMethod head = null; try { - head = new HeadMethod(client.getBaseUri() + mPath); + head = new HeadMethod(client.getBaseUri() + WebdavUtils.encodePath(mPath)); int status = client.executeMethod(head, TIMEOUT, TIMEOUT); client.exhaustResponse(head.getResponseBodyAsStream()); boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent); result = new RemoteOperationResult(success, status, head.getResponseHeaders()); - Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":"")); + Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":"")); } catch (Exception e) { result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException()); } finally { if (head != null) diff --git a/src/com/owncloud/android/operations/RemoteOperation.java b/src/com/owncloud/android/operations/RemoteOperation.java index 4d7bceef..e05dadff 100644 --- a/src/com/owncloud/android/operations/RemoteOperation.java +++ b/src/com/owncloud/android/operations/RemoteOperation.java @@ -136,14 +136,8 @@ public abstract class RemoteOperation implements Runnable { mCallerActivity = callerActivity; mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below - if (listener == null) { - throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result"); - } mListener = listener; - if (listenerHandler == null) { - throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread"); - } mListenerHandler = listenerHandler; Thread runnerThread = new Thread(this); diff --git a/src/com/owncloud/android/operations/RemoteOperationResult.java b/src/com/owncloud/android/operations/RemoteOperationResult.java index 999974cf..ca88210d 100644 --- a/src/com/owncloud/android/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/operations/RemoteOperationResult.java @@ -60,6 +60,7 @@ public class RemoteOperationResult implements Serializable { OK, OK_SSL, OK_NO_SSL, + OK_NO_CHANGES_ON_DIR, UNHANDLED_HTTP_CODE, UNAUTHORIZED, FILE_NOT_FOUND, @@ -98,7 +99,7 @@ public class RemoteOperationResult implements Serializable { public RemoteOperationResult(ResultCode code) { mCode = code; - mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL); + mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL || code == ResultCode.OK_NO_SSL || code == ResultCode.OK_NO_CHANGES_ON_DIR); } private RemoteOperationResult(boolean success, int httpCode) { diff --git a/src/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/com/owncloud/android/operations/SynchronizeFileOperation.java index 5be116bc..cb4485e2 100644 --- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -215,6 +215,8 @@ public class SynchronizeFileOperation extends RemoteOperation { file.setFileLength(we.contentLength()); file.setMimetype(we.contentType()); file.setModificationTimestamp(we.modifiedTimestamp()); + file.setEtag(we.etag()); + return file; } diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 67c7389e..3c9c6544 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -23,23 +23,25 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; -import org.apache.commons.httpclient.Header; import org.apache.http.HttpStatus; 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 com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.syncadapter.FileSyncService; import com.owncloud.android.utils.FileStorageUtils; import eu.alefzero.webdav.WebdavClient; @@ -65,6 +67,9 @@ public class SynchronizeFolderOperation extends RemoteOperation { /** Id of the folder to synchronize in the local database */ private long mParentId; + /** Boolean to indicate if is mandatory to update the folder */ + private boolean mEnforceMetadataUpdate; + /** Access to the local database */ private DataStorageManager mStorageManager; @@ -83,16 +88,22 @@ public class SynchronizeFolderOperation extends RemoteOperation { private Map mForgottenLocalFiles; + private boolean mSyncFullAccount; + public SynchronizeFolderOperation( String remotePath, long currentSyncTime, - long parentId, + long parentId, + boolean enforceMetadataUpdate, + boolean syncFullAccount, DataStorageManager dataStorageManager, Account account, Context context ) { mRemotePath = remotePath; mCurrentSyncTime = currentSyncTime; mParentId = parentId; + mEnforceMetadataUpdate = enforceMetadataUpdate; + mSyncFullAccount = syncFullAccount; mStorageManager = dataStorageManager; mAccount = account; mContext = context; @@ -121,136 +132,177 @@ public class SynchronizeFolderOperation extends RemoteOperation { return mChildren; } - + public String getRemotePath() { + return mRemotePath; + } + + public long getParentId() { + return mParentId; + } + @Override protected RemoteOperationResult run(WebdavClient client) { RemoteOperationResult result = null; mFailsInFavouritesFound = 0; mConflictsFound = 0; mForgottenLocalFiles.clear(); - + boolean dirChanged = false; + // code before in FileSyncAdapter.fetchData PropFindMethod query = null; try { Log_OC.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath); - + // remote request query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath)); int status = client.executeMethod(query); - + // check and process response - /// TODO take into account all the possible status per child-resource if (isMultiStatus(status)) { MultiStatus resp = query.getResponseBodyAsMultiStatus(); - - // synchronize properties of the parent folder, if necessary - if (mParentId == DataStorageManager.ROOT_PARENT_ID) { - WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getBaseUri().getPath()); - OCFile parent = fillOCFile(we); + + // synchronize properties of the parent folder, if necessary + WebdavEntry we = new WebdavEntry(resp.getResponses()[0], client.getBaseUri().getPath()); + + // Properties of server folder + OCFile parent = fillOCFile(we); + // Properties of local folder + OCFile localParent = mStorageManager.getFileByPath(mRemotePath); + if (localParent == null || !(parent.getEtag().equalsIgnoreCase(localParent.getEtag())) || mEnforceMetadataUpdate) { + if (localParent != null) { + parent.setParentId(localParent.getParentId()); + } mStorageManager.saveFile(parent); - mParentId = parent.getFileId(); + if (mParentId == DataStorageManager.ROOT_PARENT_ID) + mParentId = parent.getFileId(); + dirChanged = true; } - - // read contents in folder - List updatedFiles = new Vector(resp.getResponses().length - 1); - List filesToSyncContents = new Vector(); - for (int i = 1; i < resp.getResponses().length; ++i) { - /// new OCFile instance with the data from the server - WebdavEntry we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath()); - OCFile file = fillOCFile(we); - - /// set data about local state, keeping unchanged former data if existing - file.setLastSyncDateForProperties(mCurrentSyncTime); - OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath()); - if (oldFile != null) { - file.setKeepInSync(oldFile.keepInSync()); - file.setLastSyncDateForData(oldFile.getLastSyncDateForData()); - file.setModificationTimestampAtLastSyncForData(oldFile.getModificationTimestampAtLastSyncForData()); // must be kept unchanged when the file contents are not updated - checkAndFixForeignStoragePath(oldFile); - file.setStoragePath(oldFile.getStoragePath()); - } - /// scan default location if local copy of file is not linked in OCFile instance - if (file.getStoragePath() == null && !file.isDirectory()) { - File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)); - if (f.exists()) { - file.setStoragePath(f.getAbsolutePath()); - file.setLastSyncDateForData(f.lastModified()); + if (dirChanged) { + // read contents in folder + List filesOnServer = new ArrayList (); // Contains the lists of files on server + List updatedFiles = new Vector(resp.getResponses().length - 1); + List filesToSyncContents = new Vector(); + for (int i = 1; i < resp.getResponses().length; ++i) { + /// new OCFile instance with the data from the server + we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath()); + OCFile file = fillOCFile(we); + + filesOnServer.add(file.getRemotePath()); // Registry the file in the list + + /// set data about local state, keeping unchanged former data if existing + file.setLastSyncDateForProperties(mCurrentSyncTime); + OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath()); + + // Check if it is needed to synchronize the folder + if (oldFile != null) { + if (!file.getEtag().equalsIgnoreCase(oldFile.getEtag())) { + } + } + + if (oldFile != null) { + file.setKeepInSync(oldFile.keepInSync()); + file.setLastSyncDateForData(oldFile.getLastSyncDateForData()); + file.setModificationTimestampAtLastSyncForData(oldFile.getModificationTimestampAtLastSyncForData()); // must be kept unchanged when the file contents are not updated + checkAndFixForeignStoragePath(oldFile); + file.setStoragePath(oldFile.getStoragePath()); + if (file.isDirectory()) + file.setEtag(oldFile.getEtag()); + } else + if (file.isDirectory()) + file.setEtag(""); + + /// scan default location if local copy of file is not linked in OCFile instance + if (file.getStoragePath() == null && !file.isDirectory()) { + File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)); + if (f.exists()) { + file.setStoragePath(f.getAbsolutePath()); + file.setLastSyncDateForData(f.lastModified()); + } } + + /// prepare content synchronization for kept-in-sync files + if (file.keepInSync()) { + SynchronizeFileOperation operation = new SynchronizeFileOperation( oldFile, + file, + mStorageManager, + mAccount, + true, + false, + mContext + ); + filesToSyncContents.add(operation); + } + + updatedFiles.add(file); } - - /// prepare content synchronization for kept-in-sync files - if (file.keepInSync()) { - SynchronizeFileOperation operation = new SynchronizeFileOperation( oldFile, - file, - mStorageManager, - mAccount, - true, - false, - mContext - ); - filesToSyncContents.add(operation); - } - - updatedFiles.add(file); - } - - // save updated contents in local database; all at once, trying to get a best performance in database update (not a big deal, indeed) - mStorageManager.saveFiles(updatedFiles); - - // request for the synchronization of files AFTER saving last properties - SynchronizeFileOperation op = null; - RemoteOperationResult contentsResult = null; - for (int i=0; i < filesToSyncContents.size(); i++) { - op = filesToSyncContents.get(i); - contentsResult = op.execute(client); // returns without waiting for upload or download finishes - if (!contentsResult.isSuccess()) { - if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) { - mConflictsFound++; - } else { - mFailsInFavouritesFound++; - if (contentsResult.getException() != null) { - Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); + + // save updated contents in local database; all at once, trying to get a best performance in database update (not a big deal, indeed) + mStorageManager.saveFiles(updatedFiles); + + // request for the synchronization of files AFTER saving last properties + RemoteOperationResult contentsResult = null; + for (SynchronizeFileOperation op: filesToSyncContents) { + contentsResult = op.execute(client); // returns without waiting for upload or download finishes + if (!contentsResult.isSuccess()) { + if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) { + mConflictsFound++; } else { - Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); + mFailsInFavouritesFound++; + if (contentsResult.getException() != null) { + Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); + } else { + Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); + } } + } // won't let these fails break the synchronization process + } + + // removal of obsolete files + mChildren = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId)); + OCFile file; + String currentSavePath = FileStorageUtils.getSavePath(mAccount.name); + for (int i=0; i < mChildren.size(); ) { + file = mChildren.get(i); + if (file.getLastSyncDateForProperties() != mCurrentSyncTime) { + Log_OC.d(TAG, "removing file: " + file); + mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath))); + mChildren.remove(i); + } else { + i++; } - } // won't let these fails break the synchronization process + } + + } else { + client.exhaustResponse(query.getResponseBodyAsStream()); } + + + // prepare result object + if (!dirChanged) { + result = new RemoteOperationResult(ResultCode.OK_NO_CHANGES_ON_DIR); + mChildren = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId)); + + } else { + if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be different result, but will do the job - - // removal of obsolete files - mChildren = mStorageManager.getDirectoryContent(mStorageManager.getFileById(mParentId)); - OCFile file; - String currentSavePath = FileStorageUtils.getSavePath(mAccount.name); - for (int i=0; i < mChildren.size(); ) { - file = mChildren.get(i); - if (file.getLastSyncDateForProperties() != mCurrentSyncTime) { - Log_OC.d(TAG, "removing file: " + file); - mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath))); - mChildren.remove(i); } else { - i++; + result = new RemoteOperationResult(true, status, query.getResponseHeaders()); } } } else { - client.exhaustResponse(query.getResponseBodyAsStream()); - } - - // prepare result object - if (isMultiStatus(status)) { - if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { - result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be different result, but will do the job - - } else { - result = new RemoteOperationResult(true, status, query.getResponseHeaders()); + if (status == HttpStatus.SC_NOT_FOUND) { + OCFile dir = mStorageManager.getFileByPath(mRemotePath); + if (dir != null) { + String currentSavePath = FileStorageUtils.getSavePath(mAccount.name); + mStorageManager.removeDirectory(dir, true, (dir.isDown() && dir.getStoragePath().startsWith(currentSavePath))); + } } - } else { result = new RemoteOperationResult(false, status, query.getResponseHeaders()); } - - - + } catch (Exception e) { result = new RemoteOperationResult(e); @@ -259,19 +311,23 @@ public class SynchronizeFolderOperation extends RemoteOperation { if (query != null) query.releaseConnection(); // let the connection available for other methods if (result.isSuccess()) { - Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.i(TAG, "Synchroned " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); } else { if (result.isException()) { - Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + Log_OC.e(TAG, "Synchroned " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); } else { - Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + Log_OC.e(TAG, "Synchroned " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); } } + + if (!mSyncFullAccount) { + sendStickyBroadcast(false, mRemotePath, result); + } } - + return result; } - + public boolean isMultiStatus(int status) { return (status == HttpStatus.SC_MULTI_STATUS); @@ -291,6 +347,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { file.setMimetype(we.contentType()); file.setModificationTimestamp(we.modifiedTimestamp()); file.setParentId(mParentId); + file.setEtag(we.etag()); return file; } @@ -301,7 +358,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { * * If the copy fails, the link to the local file is nullified. The account of forgotten files is kept in * {@link #mForgottenLocalFiles} - * + *) * @param file File to check and fix. */ private void checkAndFixForeignStoragePath(OCFile file) { @@ -358,5 +415,23 @@ public class SynchronizeFolderOperation extends RemoteOperation { } } + /** + * Sends a message to any application component interested in the progress of the synchronization. + * + * @param inProgress 'True' when the synchronization progress is not finished. + * @param dirRemotePath Remote path of a folder that was just synchronized (with or without success) + */ + private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) { + Intent i = new Intent(FileSyncService.SYNC_MESSAGE); + i.putExtra(FileSyncService.IN_PROGRESS, inProgress); + i.putExtra(FileSyncService.ACCOUNT_NAME, mAccount.name); + if (dirRemotePath != null) { + i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath); + } + if (result != null) { + i.putExtra(FileSyncService.SYNC_RESULT, result); + } + mContext.sendStickyBroadcast(i); + } } diff --git a/src/com/owncloud/android/providers/FileContentProvider.java b/src/com/owncloud/android/providers/FileContentProvider.java index bd2b8072..cc70d631 100644 --- a/src/com/owncloud/android/providers/FileContentProvider.java +++ b/src/com/owncloud/android/providers/FileContentProvider.java @@ -78,6 +78,8 @@ public class FileContentProvider extends ContentProvider { ProviderTableMeta.FILE_KEEP_IN_SYNC); mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, ProviderTableMeta.FILE_ACCOUNT_OWNER); + mProjectionMap.put(ProviderTableMeta.FILE_ETAG, + ProviderTableMeta.FILE_ETAG); } private static final int SINGLE_FILE = 1; @@ -229,7 +231,8 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, " - + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );" + + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, " + + ProviderTableMeta.FILE_ETAG + " TEXT );" ); } @@ -283,8 +286,24 @@ public class FileContentProvider extends ContentProvider { } if (!upgraded) Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); + + if (oldVersion < 5 && newVersion >= 5) { + Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade"); + db.beginTransaction(); + try { + db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " + + " DEFAULT NULL"); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + if (!upgraded) + Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); } - } } diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java index 49f88f97..8e7ac4c1 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -38,7 +38,6 @@ import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.operations.UpdateOCVersionOperation; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity; -import com.owncloud.android.utils.FileStorageUtils; import android.accounts.Account; import android.accounts.AccountsException; @@ -194,10 +193,14 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) return; + boolean enforceMetadataUpdate = (parentId == DataStorageManager.ROOT_PARENT_ID); + // perform folder synchronization SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, mCurrentSyncTime, parentId, + enforceMetadataUpdate, + true, getStorageManager(), getAccount(), getContext() diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index db47d465..2d44f135 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -22,8 +22,8 @@ import java.io.File; import android.accounts.Account; import android.app.AlertDialog; -import android.app.ProgressDialog; import android.app.Dialog; +import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -72,15 +72,16 @@ import com.owncloud.android.operations.CreateFolderOperation; import com.owncloud.android.operations.OnRemoteOperationListener; import com.owncloud.android.operations.RemoteOperation; import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.operations.RemoveFileOperation; import com.owncloud.android.operations.RenameFileOperation; import com.owncloud.android.operations.SynchronizeFileOperation; -import com.owncloud.android.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.syncadapter.FileSyncService; import com.owncloud.android.ui.dialog.EditNameDialog; +import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; import com.owncloud.android.ui.dialog.LoadingDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog; -import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener; import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.FileFragment; @@ -117,6 +118,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa private View mRightFragmentContainer; private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW"; + private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS"; public static final int DIALOG_SHORT_WAIT = 0; private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1; @@ -137,6 +139,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa private OCFile mWaitingToPreview; private Handler mHandler; + + private boolean mSyncInProgress = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -166,10 +170,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa /// Load of saved instance state if(savedInstanceState != null) { mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW); - + mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS); + } else { mWaitingToPreview = null; - } + mSyncInProgress = false; + } /// USER INTERFACE @@ -185,7 +191,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa // Action bar setup mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation - setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to work around bug in its implementation + setSupportProgressBarIndeterminateVisibility(mSyncInProgress); // always AFTER setContentView(...) ; to work around bug in its implementation Log_OC.d(TAG, "onCreate() end"); } @@ -458,8 +464,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa FileFragment second = getSecondFragment(); OCFile currentDir = getCurrentDir(); if((currentDir != null && currentDir.getParentId() != 0) || - (second != null && second.getFile() != null)) { + (second != null && second.getFile() != null)) { onBackPressed(); + } break; } @@ -602,6 +609,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa setFile(listOfFiles.getCurrentFile()); } cleanSecondFragment(); + } @Override @@ -610,6 +618,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa Log_OC.e(TAG, "onSaveInstanceState() start"); super.onSaveInstanceState(outState); outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview); + outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress); + Log_OC.d(TAG, "onSaveInstanceState() end"); } @@ -854,36 +864,73 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME); Log_OC.d(TAG, "sync of account " + accountName + " is in_progress: " + inProgress); - + + RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); + if (getAccount() != null && accountName.equals(getAccount().name)) { String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); + /* boolean fillBlankRoot = false; - OCFile currentDir = getCurrentDir(); if (currentDir == null) { currentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); fillBlankRoot = (currentDir != null); } + */ - if ((synchFolderRemotePath != null && currentDir != null && (currentDir.getRemotePath().equals(synchFolderRemotePath))) - || fillBlankRoot ) { - if (!fillBlankRoot) - currentDir = getStorageManager().getFileByPath(synchFolderRemotePath); + OCFile currentDir = mStorageManager.getFileById(getCurrentDir().getFileId()); + if (currentDir == null) { + // current folder was removed from the server + Toast.makeText(FileDisplayActivity.this, getString(R.string.sync_current_folder_was_removed), Toast.LENGTH_LONG) + .show(); + onBackPressed(); + + } else if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) { + + /*OCFile synchDir = getStorageManager().getFileByPath(synchFolderRemotePath); + //boolean needToRefresh = false; + if (synchDir == null) { + // after synchronizing the current folder does not exist (was deleted in the server) ; need to move to other + /* + String synchPath = synchFolderRemotePath; + do { + String synchParentPath = new File(synchPath).getParent(); + synchParentPath = synchParentPath.endsWith(OCFile.PATH_SEPARATOR) ? synchParentPath : synchParentPath + OCFile.PATH_SEPARATOR; + synchDir = getStorageManager().getFileByPath(synchParentPath); + popDirname(); + synchPath = synchParentPath; + } while (synchDir == null); // sooner of later will get ROOT, that never is null + currentDir = synchDir; + *-/ + Toast.makeText(FileDisplayActivity.this, + String.format(getString(R.string.sync_current_folder_was_removed), "LOLO"), + Toast.LENGTH_LONG).show(); + //needToRefresh = true; + onBackPressed(); + } else {*/ + OCFileListFragment fileListFragment = getListOfFilesFragment(); if (fileListFragment != null) { fileListFragment.listDirectory(currentDir); } - if (getSecondFragment() == null) + //boolean existsSecondFragment = (getSecondFragment() != null); + //if (!existsSecondFragment) { + if (getSecondFragment() == null) { setFile(currentDir); + } + //updateFragmentsVisibility(existsSecondFragment); + //updateNavigationElementsInActionBar(existsSecondFragment ? getFile() : null); } setSupportProgressBarIndeterminateVisibility(inProgress); removeStickyBroadcast(intent); + + mSyncInProgress = inProgress; } - RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); + if (synchResult != null) { if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) { mLastSslUntrustedServerResult = synchResult; @@ -892,7 +939,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } } } - + private class UploadFinishReceiver extends BroadcastReceiver { /** @@ -966,6 +1013,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa public void onBrowsedDownTo(OCFile directory) { pushDirname(directory); cleanSecondFragment(); + + // Sync Folder + startSyncFolderOperation(directory.getRemotePath(), directory.getFileId()); + } /** @@ -1054,6 +1105,19 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } +// private void updateDisplayHomeAtSync(){ +// ActionBar actionBar = getSupportActionBar(); +// OCFile currentDir = getCurrentDir(); +// if (currentDir.getParentId() != DataStorageManager.ROOT_PARENT_ID) { +// actionBar.setHomeButtonEnabled(!mSyncInProgress); +// actionBar.setDisplayHomeAsUpEnabled(!mSyncInProgress); +// } +// else { +// actionBar.setHomeButtonEnabled(true); +// actionBar.setDisplayHomeAsUpEnabled(false); +// } +// } +// /** * {@inheritDoc} */ @@ -1174,7 +1238,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } else if (operation instanceof CreateFolderOperation) { onCreateFolderOperationFinish((CreateFolderOperation)operation, result); - } + + } } @@ -1222,7 +1287,6 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa refeshListOfFilesFragment(); } else { - //dismissDialog(DIALOG_SHORT_WAIT); dismissLoadingDialog(); try { Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); @@ -1283,10 +1347,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, getAccount()); startActivity(i); - } else { - Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } + } } else { if (operation.transferWasRequested()) { @@ -1363,5 +1424,37 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa } return null; } + + public void startSyncFolderOperation(String remotePath, long parentId) { + long currentSyncTime = System.currentTimeMillis(); + + mSyncInProgress = true; + + // perform folder synchronization + RemoteOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, + currentSyncTime, + parentId, + false, + false, + getStorageManager(), + getAccount(), + getApplicationContext() + ); + synchFolderOp.execute(getAccount(), this, null, null, this); + + setSupportProgressBarIndeterminateVisibility(true); + } + +// public void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) { +// int childCount = viewGroup.getChildCount(); +// for (int i = 0; i < childCount; i++) { +// View view = viewGroup.getChildAt(i); +// view.setEnabled(enabled); +// view.setClickable(!enabled); +// if (view instanceof ViewGroup) { +// enableDisableViewGroup((ViewGroup) view, enabled); +// } +// } +// } } diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java index 5380a883..b5f1186d 100644 --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -829,10 +829,7 @@ public class FileDetailFragment extends FileFragment implements i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount); startActivity(i); - } else { - Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } + } if (file.isDown()) { setButtonsForDown(); diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index be596eb1..9db05005 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -128,10 +128,22 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName if(mFile != null){ DataStorageManager storageManager = mContainerActivity.getStorageManager(); - parentDir = storageManager.getFileById(mFile.getParentId()); - mFile = parentDir; + if (mFile.getParentId() == 0) { + parentDir = storageManager.getFileById(1); + } + else { + parentDir = storageManager.getFileById(mFile.getParentId()); + } + + mFile = parentDir; } - listDirectory(parentDir); + + if (mFile != null) { + listDirectory(mFile); + + mContainerActivity.startSyncFolderOperation(mFile.getRemotePath(), mFile.getFileId()); + } + } @Override @@ -371,7 +383,6 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName mList.setSelectionFromTop(0, 0); } mFile = directory; - } } @@ -396,6 +407,8 @@ public class OCFileListFragment extends ExtendedListFragment implements EditName public void startMediaPreview(OCFile file, int i, boolean b); public void startImagePreview(OCFile file); + + public void startSyncFolderOperation(String remotePath, long parentId); /** * Getter for the current DataStorageManager in the container activity diff --git a/src/eu/alefzero/webdav/WebdavEntry.java b/src/eu/alefzero/webdav/WebdavEntry.java index 46923c66..665a850c 100644 --- a/src/eu/alefzero/webdav/WebdavEntry.java +++ b/src/eu/alefzero/webdav/WebdavEntry.java @@ -28,7 +28,7 @@ import com.owncloud.android.Log_OC; import android.net.Uri; public class WebdavEntry { - private String mName, mPath, mUri, mContentType; + private String mName, mPath, mUri, mContentType, mEtag; private long mContentLength, mCreateTimestamp, mModifiedTimestamp; public WebdavEntry(MultiStatusResponse ms, String splitElement) { @@ -42,8 +42,10 @@ public class WebdavEntry { DavPropertySet propSet = ms.getProperties(status); @SuppressWarnings("rawtypes") DavProperty prop = propSet.get(DavPropertyName.DISPLAYNAME); - if (prop != null) + if (prop != null) { mName = (String) prop.getName().toString(); + mName = mName.substring(1, mName.length()-1); + } else { String[] tmp = mPath.split("/"); if (tmp.length > 0) @@ -87,6 +89,12 @@ public class WebdavEntry { .parseResponseDate((String) prop.getValue()); mCreateTimestamp = (d != null) ? d.getTime() : 0; } + + prop = propSet.get(DavPropertyName.GETETAG); + if (prop != null) { + mEtag = (String) prop.getValue(); + mEtag = mEtag.substring(1, mEtag.length()-1); + } } else { Log_OC.e("WebdavEntry", @@ -129,6 +137,10 @@ public class WebdavEntry { public long modifiedTimestamp() { return mModifiedTimestamp; } + + public String etag() { + return mEtag; + } private void resetData() { mName = mUri = mContentType = null;