ETag used to detect changes in remote files (not only in folders)

This commit is contained in:
David A. Velasco 2015-07-28 16:27:07 +02:00
parent c0c52fa16a
commit 5f41bb14d3
16 changed files with 105 additions and 308 deletions

View file

@ -498,10 +498,9 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
} }
public void setEtag(String etag) { public void setEtag(String etag) {
this.mEtag = etag; this.mEtag = (etag != null ? etag : "");
} }
public boolean isShareByLink() { public boolean isShareByLink() {
return mShareByLink; return mShareByLink;
} }
@ -602,4 +601,5 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
// TODO real implementation // TODO real implementation
return false; return false;
} }
} }

View file

@ -34,7 +34,6 @@ import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.ui.activity.ComponentsGetter;

View file

@ -230,30 +230,6 @@ public class FileOperationsHelper {
} }
} }
/**
* Request the synchronization of a file or the DOWNLOAD OF A FOLDER, including its contents.
*
* For files, it's the same as syncFile(OCFile file); for folders, this method does not trigger uploads for
* file locally modified.
*
* Kept 'til synchronization of full folders is considered good enough.
*
* @param file The file or folder to synchronize
*/
public void downloadFile(OCFile file) {
if (!file.isFolder()){
syncFile(file);
} else {
Intent intent = new Intent(mFileActivity, OperationsService.class);
intent.setAction(OperationsService.ACTION_DOWNLOAD_FOLDER);
intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
mFileActivity.startService(intent);
}
}
public void toggleFavorite(OCFile file, boolean isFavorite) { public void toggleFavorite(OCFile file, boolean isFavorite) {
file.setFavorite(isFavorite); file.setFavorite(isFavorite);
mFileActivity.getStorageManager().saveFile(file); mFileActivity.getStorageManager().saveFile(file);
@ -327,15 +303,6 @@ public class FileOperationsHelper {
FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder(); FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) { if (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) {
downloaderBinder.cancel(account, file); downloaderBinder.cancel(account, file);
// TODO - review why is this here, and solve in a better way
// Remove etag for parent, if file is a favorite
if (file.isFavorite()) {
OCFile parent = mFileActivity.getStorageManager().getFileById(file.getParentId());
parent.setEtag("");
mFileActivity.getStorageManager().saveFile(parent);
}
} }
FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder(); FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) { if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {

View file

@ -475,7 +475,7 @@ public class FileDownloader extends Service
file.setNeedsUpdateThumbnail(true); file.setNeedsUpdateThumbnail(true);
file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp()); file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp()); file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
// file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available file.setEtag(mCurrentDownload.getEtag());
file.setMimetype(mCurrentDownload.getMimeType()); file.setMimetype(mCurrentDownload.getMimeType());
file.setStoragePath(mCurrentDownload.getSavePath()); file.setStoragePath(mCurrentDownload.getSavePath());
file.setFileLength((new File(mCurrentDownload.getSavePath()).length())); file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));

View file

@ -688,6 +688,8 @@ public class FileUploader extends Service
if (result.isSuccess()) { if (result.isSuccess()) {
updateOCFile(file, (RemoteFile) result.getData().get(0)); updateOCFile(file, (RemoteFile) result.getData().get(0));
file.setLastSyncDateForProperties(syncDate); file.setLastSyncDateForProperties(syncDate);
} else {
Log_OC.e(TAG, "Error reading properties of file after successful upload; this is gonna hurt...");
} }
// / maybe this would be better as part of UploadFileOperation... or // / maybe this would be better as part of UploadFileOperation... or
@ -712,7 +714,7 @@ public class FileUploader extends Service
file.setMimetype(remoteFile.getMimeType()); file.setMimetype(remoteFile.getMimeType());
file.setModificationTimestamp(remoteFile.getModifiedTimestamp()); file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp()); file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
// file.setEtag(remoteFile.getEtag()); // TODO Etag, where available file.setEtag(remoteFile.getEtag());
file.setRemoteId(remoteFile.getRemoteId()); file.setRemoteId(remoteFile.getRemoteId());
} }

View file

@ -52,6 +52,7 @@ public class DownloadFileOperation extends RemoteOperation {
private OCFile mFile; private OCFile mFile;
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>(); private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private long mModificationTimestamp = 0; private long mModificationTimestamp = 0;
private String mEtag = "";
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false); private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private DownloadRemoteFileOperation mDownloadOperation; private DownloadRemoteFileOperation mDownloadOperation;
@ -127,6 +128,10 @@ public class DownloadFileOperation extends RemoteOperation {
mFile.getModificationTimestamp(); mFile.getModificationTimestamp();
} }
public String getEtag() {
return mEtag;
}
@Override @Override
protected RemoteOperationResult run(OwnCloudClient client) { protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null; RemoteOperationResult result = null;
@ -154,6 +159,7 @@ public class DownloadFileOperation extends RemoteOperation {
if (result.isSuccess()) { if (result.isSuccess()) {
mModificationTimestamp = mDownloadOperation.getModificationTimestamp(); mModificationTimestamp = mDownloadOperation.getModificationTimestamp();
mEtag = mDownloadOperation.getEtag();
newFile = new File(getSavePath()); newFile = new File(getSavePath());
newFile.getParentFile().mkdirs(); newFile.getParentFile().mkdirs();
moved = tmpFile.renameTo(newFile); moved = tmpFile.renameTo(newFile);

View file

@ -540,7 +540,7 @@ public class DownloadFolderOperation extends SyncOperation {
private void startSyncFolderOperation(String path){ private void startSyncFolderOperation(String path){
Intent intent = new Intent(mContext, OperationsService.class); Intent intent = new Intent(mContext, OperationsService.class);
intent.setAction(OperationsService.ACTION_DOWNLOAD_FOLDER); intent.setAction(OperationsService.ACTION_SYNC_FOLDER);
intent.putExtra(OperationsService.EXTRA_ACCOUNT, mAccount); intent.putExtra(OperationsService.EXTRA_ACCOUNT, mAccount);
intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, path); intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, path);
mContext.startService(intent); mContext.startService(intent);

View file

@ -20,26 +20,17 @@
package com.owncloud.android.operations; package com.owncloud.android.operations;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Vector; import java.util.Vector;
import org.apache.http.HttpStatus;
import android.accounts.Account; import android.accounts.Account;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log; import android.util.Log;
//import android.support.v4.content.LocalBroadcastManager;
import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
@ -50,7 +41,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation; import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation; import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation; import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.resources.files.RemoteFile;
@ -120,7 +110,10 @@ public class RefreshFolderOperation extends RemoteOperation {
/** 'True' means that Etag will be ignored */ /** 'True' means that Etag will be ignored */
private boolean mIgnoreETag; private boolean mIgnoreETag;
private List<SynchronizeFileOperation> mFilesToSyncContents;
// this will be used for every file when 'folder synchronization' replaces 'folder download'
/** /**
* Creates a new instance of {@link RefreshFolderOperation}. * Creates a new instance of {@link RefreshFolderOperation}.
* *
@ -154,6 +147,7 @@ public class RefreshFolderOperation extends RemoteOperation {
mForgottenLocalFiles = new HashMap<String, String>(); mForgottenLocalFiles = new HashMap<String, String>();
mRemoteFolderChanged = false; mRemoteFolderChanged = false;
mIgnoreETag = ignoreETag; mIgnoreETag = ignoreETag;
mFilesToSyncContents = new Vector<SynchronizeFileOperation>();
} }
@ -191,7 +185,7 @@ public class RefreshFolderOperation extends RemoteOperation {
mConflictsFound = 0; mConflictsFound = 0;
mForgottenLocalFiles.clear(); mForgottenLocalFiles.clear();
if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) { if (OCFile.ROOT_PATH.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
updateOCVersion(client); updateOCVersion(client);
} }
@ -201,9 +195,14 @@ public class RefreshFolderOperation extends RemoteOperation {
if (mRemoteFolderChanged) { if (mRemoteFolderChanged) {
result = fetchAndSyncRemoteFolder(client); result = fetchAndSyncRemoteFolder(client);
} else { } else {
// TODO Enable when "On Device" is recovered ? fetchFavoritesToSyncFromLocalData();
mChildren = mStorageManager.getFolderContent(mLocalFolder/*, false*/); mChildren = mStorageManager.getFolderContent(mLocalFolder/*, false*/);
} }
if (result.isSuccess()) {
// request for the synchronization of KEPT-IN-SYNC file contents
startContentSynchronizations(mFilesToSyncContents, client);
}
} }
if (!mSyncFullAccount) { if (!mSyncFullAccount) {
@ -239,9 +238,8 @@ public class RefreshFolderOperation extends RemoteOperation {
private RemoteOperationResult checkForChanges(OwnCloudClient client) { private RemoteOperationResult checkForChanges(OwnCloudClient client) {
mRemoteFolderChanged = true; mRemoteFolderChanged = true;
RemoteOperationResult result = null; RemoteOperationResult result = null;
String remotePath = null; String remotePath = mLocalFolder.getRemotePath();
remotePath = mLocalFolder.getRemotePath();
Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath); Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
// remote request // remote request
@ -264,7 +262,7 @@ public class RefreshFolderOperation extends RemoteOperation {
result = new RemoteOperationResult(ResultCode.OK); result = new RemoteOperationResult(ResultCode.OK);
Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " + Log_OC.i(TAG, "Checked " + mAccount.name + remotePath + " : " +
(mRemoteFolderChanged ? "changed" : "not changed")); (mRemoteFolderChanged ? "changed" : "not changed"));
} else { } else {
@ -337,15 +335,15 @@ public class RefreshFolderOperation extends RemoteOperation {
mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath()); mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath());
// parse data from remote folder // 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.setParentId(mLocalFolder.getParentId());
remoteFolder.setFileId(mLocalFolder.getFileId()); remoteFolder.setFileId(mLocalFolder.getFileId());
Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+ " changed - starting update of local data "); + " changed - starting update of local data ");
List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1); List<OCFile> updatedFiles = new Vector<OCFile>(folderAndFiles.size() - 1);
List<SynchronizeFileOperation> filesToSyncContents = new Vector<SynchronizeFileOperation>(); mFilesToSyncContents.clear();
// get current data about local contents of the folder to synchronize // get current data about local contents of the folder to synchronize
// TODO Enable when "On Device" is recovered ? // TODO Enable when "On Device" is recovered ?
@ -359,7 +357,7 @@ public class RefreshFolderOperation extends RemoteOperation {
OCFile remoteFile = null, localFile = null; OCFile remoteFile = null, localFile = null;
for (int i=1; i<folderAndFiles.size(); i++) { for (int i=1; i<folderAndFiles.size(); i++) {
/// new OCFile instance with the data from the server /// new OCFile instance with the data from the server
remoteFile = fillOCFile((RemoteFile)folderAndFiles.get(i)); remoteFile = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(i));
remoteFile.setParentId(mLocalFolder.getFileId()); remoteFile.setParentId(mLocalFolder.getFileId());
/// retrieve local data for the read file /// retrieve local data for the read file
@ -377,9 +375,8 @@ public class RefreshFolderOperation extends RemoteOperation {
localFile.getModificationTimestampAtLastSyncForData() localFile.getModificationTimestampAtLastSyncForData()
); );
remoteFile.setStoragePath(localFile.getStoragePath()); remoteFile.setStoragePath(localFile.getStoragePath());
// eTag will not be updated unless contents are synchronized // eTag will not be updated unless file CONTENTS are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter) remoteFile.setEtag(localFile.getEtag());
remoteFile.setEtag(localFile.getEtag());
if (remoteFile.isFolder()) { if (remoteFile.isFolder()) {
remoteFile.setFileLength(localFile.getFileLength()); remoteFile.setFileLength(localFile.getFileLength());
// TODO move operations about size of folders to FileContentProvider // TODO move operations about size of folders to FileContentProvider
@ -392,15 +389,12 @@ public class RefreshFolderOperation extends RemoteOperation {
remoteFile.setPublicLink(localFile.getPublicLink()); remoteFile.setPublicLink(localFile.getPublicLink());
remoteFile.setShareByLink(localFile.isShareByLink()); remoteFile.setShareByLink(localFile.isShareByLink());
} else { } else {
// remote eTag will not be updated unless contents are synchronized // remote eTag will not be updated unless file CONTENTS are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter) remoteFile.setEtag("");
remoteFile.setEtag("");
} }
/// check and fix, if needed, local storage path /// check and fix, if needed, local storage path
checkAndFixForeignStoragePath(remoteFile); // policy - local files are COPIED FileStorageUtils.searchForLocalFileInDefaultPath(remoteFile, mAccount);
// into the ownCloud local folder;
searchForLocalFileInDefaultPath(remoteFile); // legacy
/// prepare content synchronization for kept-in-sync files /// prepare content synchronization for kept-in-sync files
if (remoteFile.isFavorite()) { if (remoteFile.isFavorite()) {
@ -411,18 +405,15 @@ public class RefreshFolderOperation extends RemoteOperation {
mContext mContext
); );
filesToSyncContents.add(operation); mFilesToSyncContents.add(operation);
} }
updatedFiles.add(remoteFile); updatedFiles.add(remoteFile);
} }
// save updated contents in local database // save updated contents in local database
mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values()); mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
// request for the synchronization of file contents AFTER saving current remote properties
startContentSynchronizations(filesToSyncContents, client);
mChildren = updatedFiles; mChildren = updatedFiles;
} }
@ -460,97 +451,6 @@ public class RefreshFolderOperation extends RemoteOperation {
} }
public boolean isMultiStatus(int status) {
return (status == HttpStatus.SC_MULTI_STATUS);
}
/**
* Creates and populates a new {@link 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;
}
/**
* Checks the storage path of the OCFile received as parameter.
* If it's out of the local ownCloud folder, tries to copy the file inside it.
*
* 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) {
String storagePath = file.getStoragePath();
String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file);
if (storagePath != null && !storagePath.equals(expectedPath)) {
/// fix storagePaths out of the local ownCloud folder
File originalFile = new File(storagePath);
if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
file.setStoragePath(null);
} else {
InputStream in = null;
OutputStream out = null;
try {
File expectedFile = new File(expectedPath);
File expectedParent = expectedFile.getParentFile();
expectedParent.mkdirs();
if (!expectedParent.isDirectory()) {
throw new IOException(
"Unexpected error: parent directory could not be created"
);
}
expectedFile.createNewFile();
if (!expectedFile.isFile()) {
throw new IOException("Unexpected error: target file could not be created");
}
in = new FileInputStream(originalFile);
out = new FileOutputStream(expectedFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
file.setStoragePath(expectedPath);
} catch (Exception e) {
Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e);
mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
file.setStoragePath(null);
} finally {
try {
if (in != null) in.close();
} catch (Exception e) {
Log_OC.d(TAG, "Weird exception while closing input stream for "
+ storagePath + " (ignoring)", e);
}
try {
if (out != null) out.close();
} catch (Exception e) {
Log_OC.d(TAG, "Weird exception while closing output stream for "
+ expectedPath + " (ignoring)", e);
}
}
}
}
}
private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) { private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
RemoteOperationResult result = null; RemoteOperationResult result = null;
@ -572,24 +472,6 @@ public class RefreshFolderOperation extends RemoteOperation {
} }
/**
* Scans the default location for saving local copies of files searching for
* a 'lost' file with the same full name as the {@link OCFile} received as
* parameter.
*
* @param file File to associate a possible 'lost' local file.
*/
private void searchForLocalFileInDefaultPath(OCFile file) {
if (file.getStoragePath() == null && !file.isFolder()) {
File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
if (f.exists()) {
file.setStoragePath(f.getAbsolutePath());
file.setLastSyncDateForData(f.lastModified());
}
}
}
/** /**
* Sends a message to any application component interested in the progress * Sends a message to any application component interested in the progress
* of the synchronization. * of the synchronization.
@ -614,8 +496,20 @@ public class RefreshFolderOperation extends RemoteOperation {
} }
public boolean getRemoteFolderChanged() { private void fetchFavoritesToSyncFromLocalData() {
return mRemoteFolderChanged; List<OCFile> children = mStorageManager.getFolderContent(mLocalFolder);
for (OCFile child : children) {
if (!child.isFolder() && child.isFavorite()) {
SynchronizeFileOperation operation = new SynchronizeFileOperation(
child,
child, // cheating with the remote file to get an update to server; to refactor
mAccount,
true,
mContext
);
mFilesToSyncContents.add(operation);
}
}
} }
} }

View file

@ -22,7 +22,6 @@
package com.owncloud.android.operations; package com.owncloud.android.operations;
import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader; import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.files.services.FileUploader;
@ -208,15 +207,13 @@ public class SynchronizeFileOperation extends SyncOperation {
/// check changes in server and local file /// check changes in server and local file
boolean serverChanged = false; boolean serverChanged = false;
/* time for eTag is coming, but not yet if (mLocalFile.getEtag() == null || mLocalFile.getEtag().length() == 0) {
if (mServerFile.getEtag() != null) { // file uploaded (null) or downloaded ("") before upgrade to version 1.8.0; check the old condition
serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); serverChanged = mServerFile.getModificationTimestamp() !=
} else { */ mLocalFile.getModificationTimestampAtLastSyncForData();
serverChanged = ( } else {
mServerFile.getModificationTimestamp() != serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));
mLocalFile.getModificationTimestampAtLastSyncForData() }
);
//}
boolean localChanged = ( boolean localChanged = (
mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData() mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
); );

View file

@ -278,7 +278,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
FileDataStorageManager storageManager = getStorageManager(); FileDataStorageManager storageManager = getStorageManager();
// parse data from remote folder // 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.setParentId(mLocalFolder.getParentId());
remoteFolder.setFileId(mLocalFolder.getFileId()); remoteFolder.setFileId(mLocalFolder.getFileId());
@ -305,7 +305,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
OCFile remoteFile = null, localFile = null; OCFile remoteFile = null, localFile = null;
for (int i=1; i<folderAndFiles.size(); i++) { for (int i=1; i<folderAndFiles.size(); i++) {
/// new OCFile instance with the data from the server /// new OCFile instance with the data from the server
remoteFile = fillOCFile((RemoteFile)folderAndFiles.get(i)); remoteFile = FileStorageUtils.fillOCFile((RemoteFile)folderAndFiles.get(i));
remoteFile.setParentId(mLocalFolder.getFileId()); remoteFile.setParentId(mLocalFolder.getFileId());
/// retrieve local data for the read file /// retrieve local data for the read file
@ -324,7 +324,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
); );
remoteFile.setStoragePath(localFile.getStoragePath()); remoteFile.setStoragePath(localFile.getStoragePath());
// eTag will not be updated unless contents are synchronized // eTag will not be updated unless contents are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter)
remoteFile.setEtag(localFile.getEtag()); remoteFile.setEtag(localFile.getEtag());
if (remoteFile.isFolder()) { if (remoteFile.isFolder()) {
remoteFile.setFileLength(localFile.getFileLength()); remoteFile.setFileLength(localFile.getFileLength());
@ -339,7 +338,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
remoteFile.setShareByLink(localFile.isShareByLink()); remoteFile.setShareByLink(localFile.isShareByLink());
} else { } else {
// remote eTag will not be updated unless contents are synchronized // remote eTag will not be updated unless contents are synchronized
// (Synchronize[File|Folder]Operation with remoteFile as parameter)
remoteFile.setEtag(""); remoteFile.setEtag("");
} }
@ -356,9 +354,8 @@ public class SynchronizeFolderOperation extends SyncOperation {
startSyncFolderOperation(remoteFile.getRemotePath()); startSyncFolderOperation(remoteFile.getRemotePath());
} }
//} else if (remoteFile.isFavorite()) {
} else { } else {
/// prepare content synchronization for kept-in-sync files /// prepare content synchronization for files (any file, not just favorites)
SynchronizeFileOperation operation = new SynchronizeFileOperation( SynchronizeFileOperation operation = new SynchronizeFileOperation(
localFile, localFile,
remoteFile, remoteFile,
@ -368,17 +365,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
); );
mFilesToSyncContents.add(operation); mFilesToSyncContents.add(operation);
/*} else {
/// prepare limited synchronization for regular files
SynchronizeFileOperation operation = new SynchronizeFileOperation(
localFile,
remoteFile,
mAccount,
true,
false,
mContext
);
mFilesToSyncContentsWithoutUpload.add(operation);*/
} }
updatedFiles.add(remoteFile); updatedFiles.add(remoteFile);
@ -405,7 +391,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
} }
} else { } else {
/// prepare limited synchronization for regular files /// synchronization for regular files
if (!child.isDown()) { if (!child.isDown()) {
mFilesForDirectDownload.add(child); mFilesForDirectDownload.add(child);
@ -487,26 +473,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
} }
/**
* 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 * 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} * a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile}

View file

@ -403,7 +403,7 @@ public class UploadFileOperation extends RemoteOperation {
newFile.setModificationTimestamp(mFile.getModificationTimestamp()); newFile.setModificationTimestamp(mFile.getModificationTimestamp());
newFile.setModificationTimestampAtLastSyncForData( newFile.setModificationTimestampAtLastSyncForData(
mFile.getModificationTimestampAtLastSyncForData()); mFile.getModificationTimestampAtLastSyncForData());
// newFile.setEtag(mFile.getEtag()) newFile.setEtag(mFile.getEtag());
newFile.setFavorite(mFile.isFavorite()); newFile.setFavorite(mFile.isFavorite());
newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties()); newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
newFile.setLastSyncDateForData(mFile.getLastSyncDateForData()); newFile.setLastSyncDateForData(mFile.getLastSyncDateForData());

View file

@ -53,7 +53,6 @@ import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation; import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
import com.owncloud.android.operations.CopyFileOperation; import com.owncloud.android.operations.CopyFileOperation;
import com.owncloud.android.operations.DownloadFolderOperation;
import com.owncloud.android.operations.CreateFolderOperation; import com.owncloud.android.operations.CreateFolderOperation;
import com.owncloud.android.operations.CreateShareOperation; import com.owncloud.android.operations.CreateShareOperation;
import com.owncloud.android.operations.GetServerInfoOperation; import com.owncloud.android.operations.GetServerInfoOperation;
@ -102,7 +101,6 @@ public class OperationsService extends Service {
public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER"; public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER";
public static final String ACTION_SYNC_FILE = "SYNC_FILE"; public static final String ACTION_SYNC_FILE = "SYNC_FILE";
public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER"; public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";
public static final String ACTION_DOWNLOAD_FOLDER = "DOWNLOAD_FOLDER" ;
public static final String ACTION_MOVE_FILE = "MOVE_FILE"; public static final String ACTION_MOVE_FILE = "MOVE_FILE";
public static final String ACTION_COPY_FILE = "COPY_FILE"; public static final String ACTION_COPY_FILE = "COPY_FILE";
@ -626,16 +624,6 @@ public class OperationsService extends Service {
System.currentTimeMillis() // TODO remove this dependency from construction time System.currentTimeMillis() // TODO remove this dependency from construction time
); );
} else if (action.equals(ACTION_DOWNLOAD_FOLDER)) { // TODO remove when sync of folders is good enough
// Download folder (all its descendant files are downloaded)
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
operation = new DownloadFolderOperation(
this,
remotePath,
account,
System.currentTimeMillis()
);
} else if (action.equals(ACTION_MOVE_FILE)) { } else if (action.equals(ACTION_MOVE_FILE)) {
// Move file/folder // Move file/folder
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);

View file

@ -30,7 +30,6 @@ import java.util.Map;
import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavException;
import com.owncloud.android.MainApp;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager;
@ -59,7 +58,7 @@ import android.support.v4.app.NotificationCompat;
* Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
* ownCloud files. * ownCloud files.
* *
* Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle, * Performs a full synchronization of the account received in {@link #onPerformSync(Account, Bundle,
* String, ContentProviderClient, SyncResult)}. * String, ContentProviderClient, SyncResult)}.
*/ */
public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
@ -77,9 +76,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
".EVENT_FULL_SYNC_END"; ".EVENT_FULL_SYNC_END";
public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED = public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED =
FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED"; FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
//public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED =
// FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED";
public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() + public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() +
".EXTRA_ACCOUNT_NAME"; ".EXTRA_ACCOUNT_NAME";
public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() + public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() +
@ -268,16 +265,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))
return; return;
/*
OCFile folder,
long currentSyncTime,
boolean updateFolderProperties,
boolean syncFullAccount,
DataStorageManager dataStorageManager,
Account account,
Context context ) {
}
*/
// folder synchronization // folder synchronization
RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder, RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder,
mCurrentSyncTime, mCurrentSyncTime,
@ -308,7 +295,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
// synchronize children folders // synchronize children folders
List<OCFile> children = synchFolderOp.getChildren(); List<OCFile> children = synchFolderOp.getChildren();
// beware of the 'hidden' recursion here! // beware of the 'hidden' recursion here!
fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged()); syncChildren(children);
} }
} else { } else {
@ -351,25 +338,19 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
/** /**
* Triggers the synchronization of any folder contained in the list of received files. * Triggers the synchronization of any folder contained in the list of received files.
*
* No consideration of etag here because it MUST walk down anyway, in case that kept-in-sync files
* have local changes.
* *
* @param files Files to recursively synchronize. * @param files Files to recursively synchronize.
*/ */
private void fetchChildren(OCFile parent, List<OCFile> files, boolean parentEtagChanged) { private void syncChildren(List<OCFile> files) {
int i; int i;
OCFile newFile = null; OCFile newFile;
//String etag = null;
//boolean syncDown = false;
for (i=0; i < files.size() && !mCancellation; i++) { for (i=0; i < files.size() && !mCancellation; i++) {
newFile = files.get(i); newFile = files.get(i);
if (newFile.isFolder()) { if (newFile.isFolder()) {
/* synchronizeFolder(newFile);
etag = newFile.getEtag();
syncDown = (parentEtagChanged || etag == null || etag.length() == 0);
if(syncDown) { */
synchronizeFolder(newFile);
//sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(),
// null);
//}
} }
} }

View file

@ -25,7 +25,6 @@ package com.owncloud.android.ui.dialog;
* *
* Triggers the removal according to the user response. * Triggers the removal according to the user response.
*/ */
import java.util.Vector;
import android.app.Dialog; import android.app.Dialog;
import android.os.Bundle; import android.os.Bundle;
@ -106,34 +105,6 @@ implements ConfirmationDialogFragmentListener {
public void onCancel(String callerTag) { public void onCancel(String callerTag) {
ComponentsGetter cg = (ComponentsGetter)getActivity(); ComponentsGetter cg = (ComponentsGetter)getActivity();
cg.getFileOperationsHelper().removeFile(mTargetFile, true); cg.getFileOperationsHelper().removeFile(mTargetFile, true);
FileDataStorageManager storageManager = cg.getStorageManager();
boolean containsFavorite = false;
if (mTargetFile.isFolder()) {
// TODO Enable when "On Device" is recovered ?
Vector<OCFile> files = storageManager.getFolderContent(mTargetFile/*, false*/);
for(OCFile file: files) {
containsFavorite = file.isFavorite() || containsFavorite;
if (containsFavorite)
break;
}
}
// Remove etag for parent, if file is a favorite
// or is a folder and contains favorite
if (mTargetFile.isFavorite() || containsFavorite) {
OCFile folder = null;
if (mTargetFile.isFolder()) {
folder = mTargetFile;
} else {
folder = storageManager.getFileById(mTargetFile.getParentId());
}
folder.setEtag("");
storageManager.saveFile(folder);
}
} }
@Override @Override

View file

@ -363,10 +363,7 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi
dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION); dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
return true; return true;
} }
case R.id.action_download_file: { case R.id.action_download_file:
mContainerActivity.getFileOperationsHelper().downloadFile(mTargetFile);
return true;
}
case R.id.action_sync_file: { case R.id.action_sync_file: {
mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile); mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
return true; return true;

View file

@ -32,6 +32,7 @@ import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.files.RemoteFile; import com.owncloud.android.lib.resources.files.RemoteFile;
import android.accounts.Account;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -120,7 +121,7 @@ public class FileStorageUtils {
* Creates and populates a new {@link OCFile} object with the data read from the server. * Creates and populates a new {@link OCFile} object with the data read from the server.
* *
* @param remote remote file read from the server (remote file or folder). * @param remote remote file read from the server (remote file or folder).
* @return New OCFile instance representing the remote resource described by we. * @return New OCFile instance representing the remote resource described by remote.
*/ */
public static OCFile fillOCFile(RemoteFile remote) { public static OCFile fillOCFile(RemoteFile remote) {
OCFile file = new OCFile(remote.getRemotePath()); OCFile file = new OCFile(remote.getRemotePath());
@ -302,5 +303,33 @@ public class FileStorageUtils {
String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
return (result != null) ? result : ""; return (result != null) ? result : "";
} }
/**
* Scans the default location for saving local copies of files searching for
* a 'lost' file with the same full name as the {@link OCFile} received as
* parameter.
*
* This method helps to keep linked local copies of the files when the app is uninstalled, and then
* reinstalled in the device. OR after the cache of the app was deleted in system settings.
*
* The method is assuming that all the local changes in the file where synchronized in the past. This is dangerous,
* but assuming the contrary could lead to massive unnecessary synchronizations of downloaded file after deleting
* the app cache.
*
* This should be changed in the near future to avoid any chance of data loss, but we need to add some options
* to limit hard automatic synchronizations to wifi, unless the user wants otherwise.
*
* @param file File to associate a possible 'lost' local file.
* @param account Account holding file.
*/
public static void searchForLocalFileInDefaultPath(OCFile file, Account account) {
if (file.getStoragePath() == null && !file.isFolder()) {
File f = new File(FileStorageUtils.getDefaultSavePathFor(account.name, file));
if (f.exists()) {
file.setStoragePath(f.getAbsolutePath());
file.setLastSyncDateForData(f.lastModified());
}
}
}
} }