diff --git a/owncloud-android-library b/owncloud-android-library
index ecc3415e3e..f02dffb1d3 160000
--- a/owncloud-android-library
+++ b/owncloud-android-library
@@ -1 +1 @@
-Subproject commit ecc3415e3e3c13fa8f73fdd51a88c1ab7087b199
+Subproject commit f02dffb1d3c46305c70d246f696cde7b8c3b0971
diff --git a/res/drawable/conflict_file_indicator.png b/res/drawable/conflict_file_indicator.png
new file mode 100644
index 0000000000..fd580caf20
Binary files /dev/null and b/res/drawable/conflict_file_indicator.png differ
diff --git a/res/drawable/synchronizing_file_indicator.png b/res/drawable/synchronizing_file_indicator.png
new file mode 100644
index 0000000000..947cba73bf
Binary files /dev/null and b/res/drawable/synchronizing_file_indicator.png differ
diff --git a/res/menu/file_actions_menu.xml b/res/menu/file_actions_menu.xml
index 3e6f4cd4a2..63fadbbc04 100644
--- a/res/menu/file_actions_menu.xml
+++ b/res/menu/file_actions_menu.xml
@@ -44,13 +44,8 @@
android:icon="@drawable/ic_action_refresh"
android:orderInCategory="1" />
-
- Created:
Modified:
Download
- Refresh file
+ Synchronize
File was renamed to %1$s during upload
List Layout
Share link
@@ -90,8 +90,7 @@
Yes
No
OK
- Cancel download
- Cancel upload
+ Cancel synchronization
Cancel
Save & Exit
Error
@@ -343,7 +342,7 @@
Security
Upload Video Path
- Download of %1$s folder could not be completed
+ Synchronization of %1$s folder could not be completed
shared
with you
diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java
index 29a11c4280..540e83d1d4 100644
--- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java
+++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java
@@ -24,8 +24,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import java.util.Vector;
import android.accounts.Account;
@@ -88,18 +90,10 @@ public class FileDataStorageManager {
return mAccount;
}
- public void setContentResolver(ContentResolver cr) {
- mContentResolver = cr;
- }
-
public ContentResolver getContentResolver() {
return mContentResolver;
}
- public void setContentProviderClient(ContentProviderClient cp) {
- mContentProviderClient = cp;
- }
-
public ContentProviderClient getContentProviderClient() {
return mContentProviderClient;
}
@@ -188,7 +182,6 @@ public class FileDataStorageManager {
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() != DataStorageManager.ROOT_PARENT_ID)
cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
if (!file.isFolder())
@@ -204,11 +197,12 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
-
+ cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
+
boolean sameRemotePath = fileExists(file.getRemotePath());
if (sameRemotePath || fileExists(file.getFileId())) { // for renamed files; no more delete and create
- OCFile oldFile = null;
+ OCFile oldFile;
if (sameRemotePath) {
oldFile = getFileByPath(file.getRemotePath());
file.setFileId(oldFile.getFileId());
@@ -254,12 +248,6 @@ public class FileDataStorageManager {
}
}
-// if (file.isFolder()) {
-// updateFolderSize(file.getFileId());
-// } else {
-// updateFolderSize(file.getParentId());
-// }
-
return overriden;
}
@@ -313,6 +301,7 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail());
cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
+ cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
boolean existsByPath = fileExists(file.getRemotePath());
if (existsByPath || fileExists(file.getFileId())) {
@@ -337,7 +326,6 @@ public class FileDataStorageManager {
for (OCFile file : filesToRemove) {
if (file.getParentId() == folder.getFileId()) {
whereArgs = new String[]{mAccount.name, file.getRemotePath()};
- //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId());
if (file.isFolder()) {
operations.add(ContentProviderOperation.newDelete(
ContentUris.withAppendedId(
@@ -434,43 +422,9 @@ public class FileDataStorageManager {
}
}
- //updateFolderSize(folder.getFileId());
-
}
-// /**
-// *
-// * @param id
-// */
-// private void updateFolderSize(long id) {
-// if (id > FileDataStorageManager.ROOT_PARENT_ID) {
-// Log_OC.d(TAG, "Updating size of " + id);
-// if (getContentResolver() != null) {
-// getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR,
-// new ContentValues(),
- // won't be used, but cannot be null; crashes in KLP
-// ProviderTableMeta._ID + "=?",
-// new String[] { String.valueOf(id) });
-// } else {
-// try {
-// getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR,
-// new ContentValues(),
- // won't be used, but cannot be null; crashes in KLP
-// ProviderTableMeta._ID + "=?",
-// new String[] { String.valueOf(id) });
-//
-// } catch (RemoteException e) {
-// Log_OC.e(
-// TAG, "Exception in update of folder size through compatibility patch " + e.getMessage());
-// }
-// }
-// } else {
-// Log_OC.e(TAG, "not updating size for folder " + id);
-// }
-// }
-
-
public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
boolean success = true;
if (file != null) {
@@ -505,6 +459,7 @@ public class FileDataStorageManager {
// maybe unnecessary, but should be checked TODO remove if unnecessary
file.setStoragePath(null);
saveFile(file);
+ saveConflict(file, null);
}
}
}
@@ -942,44 +897,12 @@ public class FileDataStorageManager {
c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1 ? true : false);
file.setDownloading(c.getInt(
c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1 ? true : false);
-
+ file.setEtagInConflict(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_IN_CONFLICT)));
+
}
return file;
}
- /**
- * Returns if the file/folder is shared by link or not
- *
- * @param path Path of the file/folder
- * @return
- */
- public boolean isShareByLink(String path) {
- Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
- OCFile file = null;
- if (c.moveToFirst()) {
- file = createFileInstance(c);
- }
- c.close();
- return file.isShareByLink();
- }
-
- /**
- * Returns the public link of the file/folder
- *
- * @param path Path of the file/folder
- * @return
- */
- public String getPublicLink(String path) {
- Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
- OCFile file = null;
- if (c.moveToFirst()) {
- file = createFileInstance(c);
- }
- c.close();
- return file.getPublicLink();
- }
-
-
// Methods for Shares
public boolean saveShare(OCShare share) {
boolean overriden = false;
@@ -1310,6 +1233,7 @@ public class FileDataStorageManager {
ProviderTableMeta.FILE_IS_DOWNLOADING,
file.isDownloading() ? 1 : 0
);
+ cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
boolean existsByPath = fileExists(file.getRemotePath());
if (existsByPath || fileExists(file.getFileId())) {
@@ -1490,44 +1414,6 @@ public class FileDataStorageManager {
}
}
return preparedOperations;
-
- /*
- if (operations.size() > 0) {
- try {
- if (getContentResolver() != null) {
- getContentResolver().applyBatch(MainApp.getAuthority(), operations);
-
- } else {
- getContentProviderClient().applyBatch(operations);
- }
-
- } catch (OperationApplicationException e) {
- Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
-
- } catch (RemoteException e) {
- Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
- }
- }
- */
-
- /*
- if (getContentResolver() != null) {
-
- getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE,
- where,
- whereArgs);
- } else {
- try {
- getContentProviderClient().delete( ProviderTableMeta.CONTENT_URI_SHARE,
- where,
- whereArgs);
-
- } catch (RemoteException e) {
- Log_OC.e(TAG, "Exception deleting shares in a folder " + e.getMessage());
- }
- }
- */
- //}
}
public void triggerMediaScan(String path) {
@@ -1578,4 +1464,138 @@ public class FileDataStorageManager {
}
+ public void saveConflict(OCFile file, String etagInConflict) {
+ if (!file.isDown()) {
+ etagInConflict = null;
+ }
+ ContentValues cv = new ContentValues();
+ cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, etagInConflict);
+ int updated = 0;
+ if (getContentResolver() != null) {
+ updated = getContentResolver().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ ProviderTableMeta._ID + "=?",
+ new String[] { String.valueOf(file.getFileId())}
+ );
+ } else {
+ try {
+ updated = getContentProviderClient().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ ProviderTableMeta._ID + "=?",
+ new String[]{String.valueOf(file.getFileId())}
+ );
+ } catch (RemoteException e) {
+ Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
+ }
+ }
+
+ Log_OC.d(TAG, "Number of files updated with CONFLICT: " + updated);
+
+ if (updated > 0) {
+ if (etagInConflict != null) {
+ /// set conflict in all ancestor folders
+
+ long parentId = file.getParentId();
+ Set ancestorIds = new HashSet();
+ while (parentId != FileDataStorageManager.ROOT_PARENT_ID) {
+ ancestorIds.add(Long.toString(parentId));
+ parentId = getFileById(parentId).getParentId();
+ }
+
+ if (ancestorIds.size() > 0) {
+ StringBuffer whereBuffer = new StringBuffer();
+ whereBuffer.append(ProviderTableMeta._ID).append(" IN (");
+ for (int i = 0; i < ancestorIds.size() - 1; i++) {
+ whereBuffer.append("?,");
+ }
+ whereBuffer.append("?");
+ whereBuffer.append(")");
+
+ if (getContentResolver() != null) {
+ updated = getContentResolver().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ whereBuffer.toString(),
+ ancestorIds.toArray(new String[]{})
+ );
+ } else {
+ try {
+ updated = getContentProviderClient().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ whereBuffer.toString(),
+ ancestorIds.toArray(new String[]{})
+ );
+ } catch (RemoteException e) {
+ Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
+ }
+ }
+ } // else file is ROOT folder, no parent to set in conflict
+
+ } else {
+ /// update conflict in ancestor folders
+ // (not directly unset; maybe there are more conflicts below them)
+ String parentPath = file.getRemotePath();
+ if (parentPath.endsWith(OCFile.PATH_SEPARATOR)) {
+ parentPath = parentPath.substring(0, parentPath.length() - 1);
+ }
+ parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
+
+ Log_OC.d(TAG, "checking parents to remove conflict; STARTING with " + parentPath);
+ while (parentPath.length() > 0) {
+
+ String where =
+ ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " IS NOT NULL AND " +
+ ProviderTableMeta.FILE_CONTENT_TYPE + " != 'DIR' AND " +
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + " = ? AND " +
+ ProviderTableMeta.FILE_PATH + " LIKE ?";
+ Cursor descendentsInConflict = getContentResolver().query(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ new String[]{ProviderTableMeta._ID},
+ where,
+ new String[]{mAccount.name, parentPath + "%"},
+ null
+ );
+ if (descendentsInConflict == null || descendentsInConflict.getCount() == 0) {
+ Log_OC.d(TAG, "NO MORE conflicts in " + parentPath);
+ if (getContentResolver() != null) {
+ updated = getContentResolver().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+ ProviderTableMeta.FILE_PATH + "=?",
+ new String[]{mAccount.name, parentPath}
+ );
+ } else {
+ try {
+ updated = getContentProviderClient().update(
+ ProviderTableMeta.CONTENT_URI_FILE,
+ cv,
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " +
+ ProviderTableMeta.FILE_PATH + "=?"
+ , new String[]{mAccount.name, parentPath}
+ );
+ } catch (RemoteException e) {
+ Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
+ }
+ }
+
+ } else {
+ Log_OC.d(TAG, "STILL " + descendentsInConflict.getCount() + " in " + parentPath);
+ }
+
+ if (descendentsInConflict != null) {
+ descendentsInConflict.close();
+ }
+
+ parentPath = parentPath.substring(0, parentPath.length() - 1); // trim last /
+ parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
+ Log_OC.d(TAG, "checking parents to remove conflict; NEXT " + parentPath);
+ }
+ }
+ }
+
+ }
}
diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java
index 4baf1ea52d..fcde054a6d 100644
--- a/src/com/owncloud/android/datamodel/OCFile.java
+++ b/src/com/owncloud/android/datamodel/OCFile.java
@@ -74,6 +74,8 @@ public class OCFile implements Parcelable, Comparable {
private boolean mIsDownloading;
+ private String mEtagInConflict; // Save file etag in the server, when there is a conflict. No conflict = null
+
/**
* Create new {@link OCFile} with given path.
@@ -115,8 +117,9 @@ public class OCFile implements Parcelable, Comparable {
mPublicLink = source.readString();
mPermissions = source.readString();
mRemoteId = source.readString();
- mNeedsUpdateThumbnail = source.readInt() == 0;
- mIsDownloading = source.readInt() == 0;
+ mNeedsUpdateThumbnail = source.readInt() == 1;
+ mIsDownloading = source.readInt() == 1;
+ mEtagInConflict = source.readString();
}
@@ -142,6 +145,7 @@ public class OCFile implements Parcelable, Comparable {
dest.writeString(mRemoteId);
dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
dest.writeInt(mIsDownloading ? 1 : 0);
+ dest.writeString(mEtagInConflict);
}
/**
@@ -315,24 +319,6 @@ public class OCFile implements Parcelable, Comparable {
return mMimeType;
}
- /**
- * Adds a file to this directory. If this file is not a directory, an
- * exception gets thrown.
- *
- * @param file to add
- * @throws IllegalStateException if you try to add a something and this is
- * not a directory
- */
- public void addFile(OCFile file) throws IllegalStateException {
- if (isFolder()) {
- file.mParentId = mId;
- mNeedsUpdating = true;
- return;
- }
- throw new IllegalStateException(
- "This is not a directory where you can add stuff to!");
- }
-
/**
* Used internally. Reset all file properties
*/
@@ -357,6 +343,7 @@ public class OCFile implements Parcelable, Comparable {
mRemoteId = null;
mNeedsUpdateThumbnail = false;
mIsDownloading = false;
+ mEtagInConflict = null;
}
/**
@@ -498,10 +485,9 @@ public class OCFile implements Parcelable, Comparable {
}
public void setEtag(String etag) {
- this.mEtag = etag;
+ this.mEtag = (etag != null ? etag : "");
}
-
public boolean isShareByLink() {
return mShareByLink;
}
@@ -598,8 +584,11 @@ public class OCFile implements Parcelable, Comparable {
this.mIsDownloading = isDownloading;
}
- public boolean isSynchronizing() {
- // TODO real implementation
- return false;
+ public String getEtagInConflict() {
+ return mEtagInConflict;
+ }
+
+ public void setEtagInConflict(String etagInConflict) {
+ mEtagInConflict = etagInConflict;
}
}
diff --git a/src/com/owncloud/android/db/ProviderMeta.java b/src/com/owncloud/android/db/ProviderMeta.java
index 25e8fbd1e5..f15dd9eca2 100644
--- a/src/com/owncloud/android/db/ProviderMeta.java
+++ b/src/com/owncloud/android/db/ProviderMeta.java
@@ -31,7 +31,7 @@ import com.owncloud.android.MainApp;
public class ProviderMeta {
public static final String DB_NAME = "filelist";
- public static final int DB_VERSION = 10;
+ public static final int DB_VERSION = 11;
private ProviderMeta() {
}
@@ -72,6 +72,7 @@ public class ProviderMeta {
public static final String FILE_REMOTE_ID = "remote_id";
public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail";
public static final String FILE_IS_DOWNLOADING= "is_downloading";
+ public static final String FILE_ETAG_IN_CONFLICT = "etag_in_conflict";
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME
+ " collate nocase asc";
@@ -94,7 +95,7 @@ public class ProviderMeta {
public static final String OCSHARES_DEFAULT_SORT_ORDER = OCSHARES_FILE_SOURCE
+ " collate nocase asc";
-
+
}
}
diff --git a/src/com/owncloud/android/files/FileMenuFilter.java b/src/com/owncloud/android/files/FileMenuFilter.java
index f7fee626c5..738ca7ef48 100644
--- a/src/com/owncloud/android/files/FileMenuFilter.java
+++ b/src/com/owncloud/android/files/FileMenuFilter.java
@@ -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.FileUploader;
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.ui.activity.ComponentsGetter;
@@ -106,21 +105,25 @@ public class FileMenuFilter {
* @param toHide List to save the options that must be shown in the menu.
*/
private void filter(List toShow, List toHide) {
- boolean downloading = false;
- boolean uploading = false;
+ boolean synchronizing = false;
if (mComponentsGetter != null && mFile != null && mAccount != null) {
- FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
- downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile));
OperationsServiceBinder opsBinder = mComponentsGetter.getOperationsServiceBinder();
- downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, mFile.getRemotePath()));
FileUploaderBinder uploaderBinder = mComponentsGetter.getFileUploaderBinder();
- uploading = (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile));
+ FileDownloaderBinder downloaderBinder = mComponentsGetter.getFileDownloaderBinder();
+ synchronizing = (
+ // comparing local and remote
+ (opsBinder != null && opsBinder.isSynchronizing(mAccount, mFile.getRemotePath())) ||
+ // downloading
+ (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) ||
+ // uploading
+ (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))
+ );
}
/// decision is taken for each possible action on a file in the menu
// DOWNLOAD
- if (mFile == null || mFile.isDown() || downloading || uploading) {
+ if (mFile == null || mFile.isDown() || mFile.isFolder() || synchronizing) {
toHide.add(R.id.action_download_file);
} else {
@@ -128,7 +131,7 @@ public class FileMenuFilter {
}
// RENAME
- if (mFile == null || downloading || uploading) {
+ if (mFile == null || synchronizing) {
toHide.add(R.id.action_rename_file);
} else {
@@ -136,7 +139,7 @@ public class FileMenuFilter {
}
// MOVE & COPY
- if (mFile == null || downloading || uploading) {
+ if (mFile == null || synchronizing) {
toHide.add(R.id.action_move);
toHide.add(R.id.action_copy);
} else {
@@ -145,7 +148,7 @@ public class FileMenuFilter {
}
// REMOVE
- if (mFile == null || downloading || uploading) {
+ if (mFile == null || synchronizing) {
toHide.add(R.id.action_remove_file);
} else {
@@ -153,31 +156,25 @@ public class FileMenuFilter {
}
// OPEN WITH (different to preview!)
- if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+ if (mFile == null || mFile.isFolder() || !mFile.isDown() || synchronizing) {
toHide.add(R.id.action_open_file_with);
} else {
toShow.add(R.id.action_open_file_with);
}
+ // CANCEL SYNCHRONIZATION
+ if (mFile == null || !synchronizing) {
+ toHide.add(R.id.action_cancel_sync);
- // CANCEL DOWNLOAD
- if (mFile == null || !downloading) {
- toHide.add(R.id.action_cancel_download);
} else {
- toShow.add(R.id.action_cancel_download);
+ toShow.add(R.id.action_cancel_sync);
}
- // CANCEL UPLOAD
- if (mFile == null || !uploading || mFile.isFolder()) {
- toHide.add(R.id.action_cancel_upload);
- } else {
- toShow.add(R.id.action_cancel_upload);
- }
-
- // SYNC FILE CONTENTS
- if (mFile == null || mFile.isFolder() || !mFile.isDown() || downloading || uploading) {
+ // SYNC CONTENTS (BOTH FILE AND FOLDER)
+ if (mFile == null || (!mFile.isFolder() && !mFile.isDown()) || synchronizing) {
toHide.add(R.id.action_sync_file);
+
} else {
toShow.add(R.id.action_sync_file);
}
@@ -210,21 +207,21 @@ public class FileMenuFilter {
// SEND
boolean sendAllowed = (mContext != null &&
mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
- if (mFile == null || !sendAllowed || mFile.isFolder() || uploading || downloading) {
+ if (mFile == null || !sendAllowed || mFile.isFolder() || synchronizing) {
toHide.add(R.id.action_send_file);
} else {
toShow.add(R.id.action_send_file);
}
// FAVORITES
- if (mFile == null || downloading || uploading || mFile.isFolder() || mFile.isFavorite()) {
+ if (mFile == null || synchronizing || mFile.isFolder() || mFile.isFavorite()) {
toHide.add(R.id.action_favorite_file);
} else {
toShow.add(R.id.action_favorite_file);
}
// UNFAVORITES
- if (mFile == null || downloading || uploading || mFile.isFolder() || !mFile.isFavorite()) {
+ if (mFile == null || synchronizing || mFile.isFolder() || !mFile.isFavorite()) {
toHide.add(R.id.action_unfavorite_file);
} else {
toShow.add(R.id.action_unfavorite_file);
diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java
index fba620914b..cf0f50f0db 100644
--- a/src/com/owncloud/android/files/FileOperationsHelper.java
+++ b/src/com/owncloud/android/files/FileOperationsHelper.java
@@ -236,9 +236,12 @@ public class FileOperationsHelper {
}
}
-
+ /**
+ * Request the synchronization of a file or folder with the OC server, including its contents.
+ *
+ * @param file The file or folder to synchronize
+ */
public void syncFile(OCFile file) {
-
if (!file.isFolder()){
Intent intent = new Intent(mFileActivity, OperationsService.class);
intent.setAction(OperationsService.ACTION_SYNC_FILE);
@@ -254,6 +257,7 @@ public class FileOperationsHelper {
intent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
intent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
mFileActivity.startService(intent);
+
}
}
@@ -328,19 +332,11 @@ public class FileOperationsHelper {
// for both files and folders
FileDownloaderBinder downloaderBinder = mFileActivity.getFileDownloaderBinder();
- FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
if (downloaderBinder != null && downloaderBinder.isDownloading(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);
- }
-
- } else if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
+ }
+ FileUploaderBinder uploaderBinder = mFileActivity.getFileUploaderBinder();
+ if (uploaderBinder != null && uploaderBinder.isUploading(account, file)) {
uploaderBinder.cancel(account, file);
}
}
diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java
index f6d3b50f49..b6f21a5cb0 100644
--- a/src/com/owncloud/android/files/services/FileDownloader.java
+++ b/src/com/owncloud/android/files/services/FileDownloader.java
@@ -21,14 +21,12 @@
package com.owncloud.android.files.services;
import java.io.File;
-import java.io.IOException;
import java.util.AbstractList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
-import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -54,7 +52,6 @@ import com.owncloud.android.utils.ErrorMessageAdapter;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AccountsException;
import android.accounts.OnAccountsUpdateListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -153,7 +150,7 @@ public class FileDownloader extends Service
/**
* Entry point to add one or several files to the queue of downloads.
- *
+ *
* New downloads are added calling to startService(), resulting in a call to this method.
* This ensures the service will keep on working although the caller activity goes away.
*/
@@ -169,12 +166,6 @@ public class FileDownloader extends Service
} else {
final Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
final OCFile file = intent.getParcelableExtra(EXTRA_FILE);
-
- /*Log_OC.v(
- "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Received request to download file"
- );*/
-
AbstractList requestedDownloads = new Vector();
try {
DownloadFileOperation newDownload = new DownloadFileOperation(account, file);
@@ -185,20 +176,6 @@ public class FileDownloader extends Service
);
String downloadKey = putResult.first;
requestedDownloads.add(downloadKey);
- /*Log_OC.v(
- "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Download on " + file.getRemotePath() + " added to queue"
- );*/
-
- // Store file on db with state 'downloading'
- /*
- TODO - check if helps with UI responsiveness,
- letting only folders use FileDownloaderBinder to check
- FileDataStorageManager storageManager =
- new FileDataStorageManager(account, getContentResolver());
- file.setDownloading(true);
- storageManager.saveFile(file);
- */
sendBroadcastNewDownload(newDownload, putResult.second);
@@ -275,34 +252,23 @@ public class FileDownloader extends Service
* @param file A file in the queue of pending downloads
*/
public void cancel(Account account, OCFile file) {
- /*Log_OC.v(
- "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Received request to cancel download of " + file.getRemotePath()
- );
- Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Removing download of " + file.getRemotePath());*/
- Pair removeResult =
- mPendingDownloads.remove(account, file.getRemotePath());
+ Pair removeResult = mPendingDownloads.remove(account, file.getRemotePath());
DownloadFileOperation download = removeResult.first;
if (download != null) {
- /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Canceling returned download of " + file.getRemotePath());*/
download.cancel();
} else {
if (mCurrentDownload != null && mCurrentAccount != null &&
mCurrentDownload.getRemotePath().startsWith(file.getRemotePath()) &&
account.name.equals(mCurrentAccount.name)) {
- /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Canceling current sync as descendant: " + mCurrentDownload.getRemotePath());*/
mCurrentDownload.cancel();
}
}
}
/**
- * Cancels a pending or current upload for an account
+ * Cancels all the downloads for an account
*
- * @param account Owncloud accountName where the remote file will be stored.
+ * @param account ownCloud account.
*/
public void cancel(Account account) {
Log_OC.d(TAG, "Account= " + account.name);
@@ -325,7 +291,7 @@ public class FileDownloader extends Service
/**
* Returns True when the file described by 'file' in the ownCloud account 'account'
* is downloading or waiting to download.
- *
+ *
* If 'file' is a directory, returns 'true' if any of its descendant files is downloading or
* waiting to download.
*
@@ -349,7 +315,6 @@ public class FileDownloader extends Service
OnDatatransferProgressListener listener, Account account, OCFile file
) {
if (account == null || file == null || listener == null) return;
- //String targetKey = buildKey(account, file.getRemotePath());
mBoundListeners.put(file.getFileId(), listener);
}
@@ -357,15 +322,14 @@ public class FileDownloader extends Service
/**
* Removes a listener interested in the progress of the download for a concrete file.
*
- * @param listener Object to notify about progress of transfer.
- * @param account ownCloud account holding the file of interest.
- * @param file {@link OCFile} of interest for listener.
+ * @param listener Object to notify about progress of transfer.
+ * @param account ownCloud account holding the file of interest.
+ * @param file {@link OCFile} of interest for listener.
*/
public void removeDatatransferProgressListener(
OnDatatransferProgressListener listener, Account account, OCFile file
) {
if (account == null || file == null || listener == null) return;
- //String targetKey = buildKey(account, file.getRemotePath());
Long fileId = file.getFileId();
if (mBoundListeners.get(fileId) == listener) {
mBoundListeners.remove(fileId);
@@ -375,8 +339,6 @@ public class FileDownloader extends Service
@Override
public void onTransferProgress(long progressRate, long totalTransferredSoFar,
long totalToTransfer, String fileName) {
- //String key = buildKey(mCurrentDownload.getAccount(),
- // mCurrentDownload.getFile().getRemotePath());
OnDatatransferProgressListener boundListener =
mBoundListeners.get(mCurrentDownload.getFile().getFileId());
if (boundListener != null) {
@@ -385,23 +347,12 @@ public class FileDownloader extends Service
}
}
- /**
- * Review downloads and cancel it if its account doesn't exist
- */
- public void checkAccountOfCurrentDownload() {
- if (mCurrentDownload != null &&
- !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
- mCurrentDownload.cancel();
- }
- // The rest of downloads are cancelled when they try to start
- }
-
}
/**
* Download worker. Performs the pending downloads in the order they were requested.
- *
+
* Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}.
*/
private static class ServiceHandler extends Handler {
@@ -440,14 +391,13 @@ public class FileDownloader extends Service
*/
private void downloadFile(String downloadKey) {
- /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Getting download of " + downloadKey);*/
mCurrentDownload = mPendingDownloads.get(downloadKey);
if (mCurrentDownload != null) {
// Detect if the account exists
if (AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().name + " exists");
+
notifyDownloadStart(mCurrentDownload);
RemoteOperationResult downloadResult = null;
@@ -470,26 +420,16 @@ public class FileDownloader extends Service
/// perform the download
- /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Executing download of " + mCurrentDownload.getRemotePath());*/
downloadResult = mCurrentDownload.execute(mDownloadClient);
if (downloadResult.isSuccess()) {
saveDownloadedFile();
}
- } catch (AccountsException e) {
- Log_OC.e(TAG, "Error while trying to get authorization for "
- + mCurrentAccount.name, e);
- downloadResult = new RemoteOperationResult(e);
- } catch (IOException e) {
- Log_OC.e(TAG, "Error while trying to get authorization for "
- + mCurrentAccount.name, e);
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Error downloading", e);
downloadResult = new RemoteOperationResult(e);
} finally {
- /*Log_OC.v( "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
- "Removing payload " + mCurrentDownload.getRemotePath());*/
-
Pair removeResult =
mPendingDownloads.removePayload(mCurrentAccount,
mCurrentDownload.getRemotePath());
@@ -497,9 +437,9 @@ public class FileDownloader extends Service
/// notify result
notifyDownloadResult(mCurrentDownload, downloadResult);
- sendBroadcastDownloadFinished(mCurrentDownload, downloadResult,
- removeResult.second);
+ sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second);
}
+
} else {
// Cancel the transfer
Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().toString() +
@@ -513,6 +453,8 @@ public class FileDownloader extends Service
/**
* Updates the OC File after a successful download.
+ *
+ * TODO move to DownloadFileOperation
*/
private void saveDownloadedFile() {
OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId());
@@ -522,25 +464,16 @@ public class FileDownloader extends Service
file.setNeedsUpdateThumbnail(true);
file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
- // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where available
+ file.setEtag(mCurrentDownload.getEtag());
file.setMimetype(mCurrentDownload.getMimeType());
file.setStoragePath(mCurrentDownload.getSavePath());
file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
file.setRemoteId(mCurrentDownload.getFile().getRemoteId());
mStorageManager.saveFile(file);
mStorageManager.triggerMediaScan(file.getStoragePath());
+ mStorageManager.saveConflict(file, null);
}
- /**
- * Update the OC File after a unsuccessful download
- */
- private void updateUnsuccessfulDownloadedFile() {
- OCFile file = mStorageManager.getFileById(mCurrentDownload.getFile().getFileId());
- file.setDownloading(false);
- mStorageManager.saveFile(file);
- }
-
-
/**
* Creates a status notification to show the download progress
*
@@ -683,6 +616,7 @@ public class FileDownloader extends Service
DownloadFileOperation download,
RemoteOperationResult downloadResult,
String unlinkedFromRemotePath) {
+
Intent end = new Intent(getDownloadFinishMessage());
end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());
end.putExtra(ACCOUNT_NAME, download.getAccount().name);
diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java
index 669ff13563..7c953b8432 100644
--- a/src/com/owncloud/android/files/services/FileUploader.java
+++ b/src/com/owncloud/android/files/services/FileUploader.java
@@ -21,18 +21,14 @@
package com.owncloud.android.files.services;
import java.io.File;
-import java.io.IOException;
import java.util.AbstractList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AccountsException;
import android.accounts.OnAccountsUpdateListener;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -46,6 +42,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.support.v4.app.NotificationCompat;
+import android.util.Pair;
import android.webkit.MimeTypeMap;
import com.owncloud.android.R;
@@ -86,6 +83,7 @@ public class FileUploader extends Service
public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH";
public static final String EXTRA_OLD_FILE_PATH = "OLD_FILE_PATH";
+ public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
public static final String KEY_FILE = "FILE";
@@ -113,11 +111,10 @@ public class FileUploader extends Service
private ServiceHandler mServiceHandler;
private IBinder mBinder;
private OwnCloudClient mUploadClient = null;
- private Account mLastAccount = null;
+ private Account mCurrentAccount = null;
private FileDataStorageManager mStorageManager;
- private ConcurrentMap mPendingUploads =
- new ConcurrentHashMap();
+ private IndexedForest mPendingUploads = new IndexedForest();
private UploadFileOperation mCurrentUpload = null;
private NotificationManager mNotificationManager;
@@ -132,20 +129,6 @@ public class FileUploader extends Service
return FileUploader.class.getName() + UPLOAD_FINISH_MESSAGE;
}
- /**
- * Builds a key for mPendingUploads from the account and file to upload
- *
- * @param account Account where the file to upload is stored
- * @param file File to upload
- */
- private String buildRemoteName(Account account, OCFile file) {
- return account.name + file.getRemotePath();
- }
-
- private String buildRemoteName(Account account, String remotePath) {
- return account.name + remotePath;
- }
-
/**
* Checks if an ownCloud server version should support chunked uploads.
*
@@ -153,6 +136,8 @@ public class FileUploader extends Service
* server.
* @return 'True' if the ownCloud server with version supports chunked
* uploads.
+ *
+ * TODO - move to OCClient
*/
private static boolean chunkedUploadIsSupported(OwnCloudVersion version) {
return (version != null && version.compareTo(OwnCloudVersion.owncloud_v4_5) >= 0);
@@ -282,7 +267,7 @@ public class FileUploader extends Service
files = new OCFile[localPaths.length];
for (int i = 0; i < localPaths.length; i++) {
files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i],
- ((mimeTypes != null) ? mimeTypes[i] : null), storageManager);
+ ((mimeTypes != null) ? mimeTypes[i] : null));
if (files[i] == null) {
// TODO @andomaex add failure Notification
return Service.START_NOT_STICKY;
@@ -298,18 +283,23 @@ public class FileUploader extends Service
UploadFileOperation newUpload = null;
try {
for (int i = 0; i < files.length; i++) {
- uploadKey = buildRemoteName(account, files[i].getRemotePath());
- newUpload = new UploadFileOperation(account, files[i], chunked, isInstant,
+ newUpload = new UploadFileOperation(
+ account,
+ files[i],
+ chunked,
+ isInstant,
forceOverwrite, localAction,
- getApplicationContext());
+ getApplicationContext()
+ );
if (isInstant) {
newUpload.setRemoteFolderToBeCreated();
}
- // Grants that the file only upload once time
- mPendingUploads.putIfAbsent(uploadKey, newUpload);
-
newUpload.addDatatransferProgressListener(this);
- newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder);
+ newUpload.addDatatransferProgressListener((FileUploaderBinder) mBinder);
+ Pair putResult = mPendingUploads.putIfAbsent(
+ account, files[i].getRemotePath(), newUpload
+ );
+ uploadKey = putResult.first;
requestedUploads.add(uploadKey);
}
@@ -333,7 +323,6 @@ public class FileUploader extends Service
msg.obj = requestedUploads;
mServiceHandler.sendMessage(msg);
}
- Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
return Service.START_NOT_STICKY;
}
@@ -386,23 +375,27 @@ public class FileUploader extends Service
/**
* Cancels a pending or current upload of a remote file.
*
- * @param account Owncloud account where the remote file will be stored.
- * @param file A file in the queue of pending uploads
+ * @param account ownCloud account where the remote file will be stored.
+ * @param file A file in the queue of pending uploads
*/
public void cancel(Account account, OCFile file) {
- UploadFileOperation upload;
- synchronized (mPendingUploads) {
- upload = mPendingUploads.remove(buildRemoteName(account, file));
- }
+ Pair removeResult = mPendingUploads.remove(account, file.getRemotePath());
+ UploadFileOperation upload = removeResult.first;
if (upload != null) {
upload.cancel();
+ } else {
+ if (mCurrentUpload != null && mCurrentAccount != null &&
+ mCurrentUpload.getRemotePath().startsWith(file.getRemotePath()) &&
+ account.name.equals(mCurrentAccount.name)) {
+ mCurrentUpload.cancel();
+ }
}
}
/**
- * Cancels a pending or current upload for an account
+ * Cancels all the uploads for an account
*
- * @param account Owncloud accountName where the remote file will be stored.
+ * @param account ownCloud account.
*/
public void cancel(Account account) {
Log_OC.d(TAG, "Account= " + account.name);
@@ -414,13 +407,14 @@ public class FileUploader extends Service
}
}
// Cancel pending uploads
- cancelUploadForAccount(account.name);
+ cancelUploadsForAccount(account);
}
public void clearListeners() {
mBoundListeners.clear();
}
+
/**
* Returns True when the file described by 'file' is being uploaded to
* the ownCloud account 'account' or waiting for it
@@ -432,22 +426,8 @@ public class FileUploader extends Service
* @param file A file that could be in the queue of pending uploads
*/
public boolean isUploading(Account account, OCFile file) {
- if (account == null || file == null)
- return false;
- String targetKey = buildRemoteName(account, file);
- synchronized (mPendingUploads) {
- if (file.isFolder()) {
- // this can be slow if there are many uploads :(
- Iterator it = mPendingUploads.keySet().iterator();
- boolean found = false;
- while (it.hasNext() && !found) {
- found = it.next().startsWith(targetKey);
- }
- return found;
- } else {
- return (mPendingUploads.containsKey(targetKey));
- }
- }
+ if (account == null || file == null) return false;
+ return (mPendingUploads.contains(account, file.getRemotePath()));
}
@@ -496,15 +476,19 @@ public class FileUploader extends Service
}
/**
- * Review uploads and cancel it if its account doesn't exist
+ * Builds a key for the map of listeners.
+ *
+ * TODO remove and replace key with file.getFileId() after changing current policy (upload file, then
+ * add to local database) to better policy (add to local database, then upload)
+ *
+ * @param account ownCloud account where the file to upload belongs.
+ * @param file File to upload
+ * @return Key
*/
- public void checkAccountOfCurrentUpload() {
- if (mCurrentUpload != null &&
- !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
- mCurrentUpload.cancel();
- }
- // The rest of uploads are cancelled when they try to start
+ private String buildRemoteName(Account account, OCFile file) {
+ return account.name + file.getRemotePath();
}
+
}
/**
@@ -544,17 +528,13 @@ public class FileUploader extends Service
/**
* Core upload method: sends the file(s) to upload
*
- * @param uploadKey Key to access the upload to perform, contained in
- * mPendingUploads
+ * @param uploadKey Key to access the upload to perform, contained in mPendingUploads
*/
public void uploadFile(String uploadKey) {
- synchronized (mPendingUploads) {
- mCurrentUpload = mPendingUploads.get(uploadKey);
- }
+ mCurrentUpload = mPendingUploads.get(uploadKey);
if (mCurrentUpload != null) {
-
// Detect if the account exists
if (AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().name + " exists");
@@ -564,16 +544,20 @@ public class FileUploader extends Service
RemoteOperationResult uploadResult = null, grantResult;
try {
- /// prepare client object to send requests to the ownCloud server
- if (mUploadClient == null ||
- !mLastAccount.equals(mCurrentUpload.getAccount())) {
- mLastAccount = mCurrentUpload.getAccount();
- mStorageManager =
- new FileDataStorageManager(mLastAccount, getContentResolver());
- OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
- mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
- getClientFor(ocAccount, this);
- }
+ /// prepare client object to send the request to the ownCloud server
+ if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentUpload.getAccount())) {
+ mCurrentAccount = mCurrentUpload.getAccount();
+ mStorageManager = new FileDataStorageManager(
+ mCurrentAccount,
+ getContentResolver()
+ );
+ } // else, reuse storage manager from previous operation
+
+ // always get client from client manager, to get fresh credentials in case of update
+ OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
+ mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+ getClientFor(ocAccount, this);
+
/// check the existence of the parent folder for the file to upload
String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
@@ -588,43 +572,44 @@ public class FileUploader extends Service
uploadResult = mCurrentUpload.execute(mUploadClient);
if (uploadResult.isSuccess()) {
saveUploadedFile();
+
+ } else if (uploadResult.getCode() == ResultCode.SYNC_CONFLICT) {
+ mStorageManager.saveConflict(mCurrentUpload.getFile(),
+ mCurrentUpload.getFile().getEtagInConflict());
}
} else {
uploadResult = grantResult;
}
- } catch (AccountsException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " +
- mLastAccount.name, e);
- uploadResult = new RemoteOperationResult(e);
-
- } catch (IOException e) {
- Log_OC.e(TAG, "Error while trying to get autorization for " +
- mLastAccount.name, e);
+ } catch (Exception e) {
+ Log_OC.e(TAG, "Error uploading", e);
uploadResult = new RemoteOperationResult(e);
} finally {
- synchronized (mPendingUploads) {
- mPendingUploads.remove(uploadKey);
- Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
+ Pair removeResult;
+ if (mCurrentUpload.wasRenamed()) {
+ removeResult = mPendingUploads.removePayload(
+ mCurrentAccount,
+ mCurrentUpload.getOldFile().getRemotePath()
+ );
+ } else {
+ removeResult = mPendingUploads.removePayload(
+ mCurrentAccount,
+ mCurrentUpload.getRemotePath()
+ );
}
- if (uploadResult != null && uploadResult.isException()) {
- // enforce the creation of a new client object for next uploads;
- // this grant that a new socket will be created in the future if
- // the current exception is due to an abrupt lose of network connection
- mUploadClient = null;
- }
- }
- /// notify result
- notifyUploadResult(uploadResult, mCurrentUpload);
- sendFinalBroadcast(mCurrentUpload, uploadResult);
+ /// notify result
+ notifyUploadResult(mCurrentUpload, uploadResult);
+
+ sendBroadcastUploadFinished(mCurrentUpload, uploadResult, removeResult.second);
+ }
} else {
// Cancel the transfer
Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().toString() +
" doesn't exist");
- cancelUploadForAccount(mCurrentUpload.getAccount().name);
+ cancelUploadsForAccount(mCurrentUpload.getAccount());
}
}
@@ -691,7 +676,7 @@ public class FileUploader extends Service
* synchronized with the server, specially the modification time and Etag
* (where available)
*
- * TODO refactor this ugly thing
+ * TODO move into UploadFileOperation
*/
private void saveUploadedFile() {
OCFile file = mCurrentUpload.getFile();
@@ -709,6 +694,8 @@ public class FileUploader extends Service
if (result.isSuccess()) {
updateOCFile(file, (RemoteFile) result.getData().get(0));
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
@@ -718,6 +705,7 @@ public class FileUploader extends Service
if (oldFile.fileExists()) {
oldFile.setStoragePath(null);
mStorageManager.saveFile(oldFile);
+ mStorageManager.saveConflict(oldFile, null);
} // else: it was just an automatic renaming due to a name
// coincidence; nothing else is needed, the storagePath is right
@@ -725,7 +713,10 @@ public class FileUploader extends Service
}
file.setNeedsUpdateThumbnail(true);
mStorageManager.saveFile(file);
+ mStorageManager.saveConflict(file, null);
+
mStorageManager.triggerMediaScan(file.getStoragePath());
+
}
private void updateOCFile(OCFile file, RemoteFile remoteFile) {
@@ -734,12 +725,11 @@ public class FileUploader extends Service
file.setMimetype(remoteFile.getMimeType());
file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
- // file.setEtag(remoteFile.getEtag()); // TODO Etag, where available
+ file.setEtag(remoteFile.getEtag());
file.setRemoteId(remoteFile.getRemoteId());
}
- private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
- FileDataStorageManager storageManager) {
+ private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) {
// MIME type
if (mimeType == null || mimeType.length() <= 0) {
@@ -830,11 +820,11 @@ public class FileUploader extends Service
/**
* Updates the status notification with the result of an upload operation.
*
- * @param uploadResult Result of the upload operation.
- * @param upload Finished upload operation
+ * @param uploadResult Result of the upload operation.
+ * @param upload Finished upload operation
*/
- private void notifyUploadResult(
- RemoteOperationResult uploadResult, UploadFileOperation upload) {
+ private void notifyUploadResult(UploadFileOperation upload,
+ RemoteOperationResult uploadResult) {
Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
// / cancelled operation or success -> silent removal of progress notification
mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
@@ -941,10 +931,15 @@ public class FileUploader extends Service
* Sends a broadcast in order to the interested activities can update their
* view
*
- * @param upload Finished upload operation
- * @param uploadResult Result of the upload operation
+ * @param upload Finished upload operation
+ * @param uploadResult Result of the upload operation
+ * @param unlinkedFromRemotePath Path in the uploads tree where the upload was unlinked from
*/
- private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
+ private void sendBroadcastUploadFinished(
+ UploadFileOperation upload,
+ RemoteOperationResult uploadResult,
+ String unlinkedFromRemotePath) {
+
Intent end = new Intent(getUploadFinishMessage());
end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote
// path, after
@@ -957,6 +952,10 @@ public class FileUploader extends Service
end.putExtra(EXTRA_OLD_FILE_PATH, upload.getOriginalStoragePath());
end.putExtra(ACCOUNT_NAME, upload.getAccount().name);
end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess());
+ if (unlinkedFromRemotePath != null) {
+ end.putExtra(EXTRA_LINKED_TO_PATH, unlinkedFromRemotePath);
+ }
+
sendStickyBroadcast(end);
}
@@ -966,6 +965,8 @@ public class FileUploader extends Service
* @param localPath Full path to a file in the local file system.
* @param mimeType MIME type of the file.
* @return true if is needed to add the pdf file extension to the file
+ *
+ * TODO - move to OCFile or Utils class
*/
private boolean isPdfFileFromContentProviderWithoutExtension(String localPath,
String mimeType) {
@@ -976,20 +977,11 @@ public class FileUploader extends Service
/**
* Remove uploads of an account
- * @param accountName Name of an OC account
+ *
+ * @param account Downloads account to remove
*/
- private void cancelUploadForAccount(String accountName){
- // this can be slow if there are many uploads :(
- Iterator it = mPendingUploads.keySet().iterator();
- Log_OC.d(TAG, "Number of pending updloads= " + mPendingUploads.size());
- while (it.hasNext()) {
- String key = it.next();
- Log_OC.d(TAG, "mPendingUploads CANCELLED " + key);
- if (key.startsWith(accountName)) {
- synchronized (mPendingUploads) {
- mPendingUploads.remove(key);
- }
- }
- }
+ private void cancelUploadsForAccount(Account account){
+ // Cancel pending uploads
+ mPendingUploads.remove(account);
}
}
diff --git a/src/com/owncloud/android/operations/DownloadFileOperation.java b/src/com/owncloud/android/operations/DownloadFileOperation.java
index 0cb303cee2..dff8aef18f 100644
--- a/src/com/owncloud/android/operations/DownloadFileOperation.java
+++ b/src/com/owncloud/android/operations/DownloadFileOperation.java
@@ -27,7 +27,6 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
-import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.OwnCloudClient;
@@ -52,6 +51,7 @@ public class DownloadFileOperation extends RemoteOperation {
private OCFile mFile;
private Set mDataTransferListeners = new HashSet();
private long mModificationTimestamp = 0;
+ private String mEtag = "";
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private DownloadRemoteFileOperation mDownloadOperation;
@@ -127,11 +127,15 @@ public class DownloadFileOperation extends RemoteOperation {
mFile.getModificationTimestamp();
}
+ public String getEtag() {
+ return mEtag;
+ }
+
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
- RemoteOperationResult result = null;
- File newFile = null;
- boolean moved = true;
+ RemoteOperationResult result;
+ File newFile;
+ boolean moved;
/// download will be performed to a temporal file, then moved to the final location
File tmpFile = new File(getTmpPath());
@@ -154,6 +158,7 @@ public class DownloadFileOperation extends RemoteOperation {
if (result.isSuccess()) {
mModificationTimestamp = mDownloadOperation.getModificationTimestamp();
+ mEtag = mDownloadOperation.getEtag();
newFile = new File(getSavePath());
newFile.getParentFile().mkdirs();
moved = tmpFile.renameTo(newFile);
diff --git a/src/com/owncloud/android/operations/RefreshFolderOperation.java b/src/com/owncloud/android/operations/RefreshFolderOperation.java
index 977f72a8ac..61b13fc87d 100644
--- a/src/com/owncloud/android/operations/RefreshFolderOperation.java
+++ b/src/com/owncloud/android/operations/RefreshFolderOperation.java
@@ -20,26 +20,17 @@
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
-import org.apache.http.HttpStatus;
import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
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.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.utils.Log_OC;
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.ReadRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.RemoteFile;
@@ -120,7 +110,10 @@ public class RefreshFolderOperation extends RemoteOperation {
/** 'True' means that Etag will be ignored */
private boolean mIgnoreETag;
-
+ private List mFilesToSyncContents;
+ // this will be used for every file when 'folder synchronization' replaces 'folder download'
+
+
/**
* Creates a new instance of {@link RefreshFolderOperation}.
*
@@ -154,6 +147,7 @@ public class RefreshFolderOperation extends RemoteOperation {
mForgottenLocalFiles = new HashMap();
mRemoteFolderChanged = false;
mIgnoreETag = ignoreETag;
+ mFilesToSyncContents = new Vector();
}
@@ -191,7 +185,7 @@ public class RefreshFolderOperation extends RemoteOperation {
mConflictsFound = 0;
mForgottenLocalFiles.clear();
- if (FileUtils.PATH_SEPARATOR.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
+ if (OCFile.ROOT_PATH.equals(mLocalFolder.getRemotePath()) && !mSyncFullAccount) {
updateOCVersion(client);
}
@@ -201,9 +195,14 @@ public class RefreshFolderOperation extends RemoteOperation {
if (mRemoteFolderChanged) {
result = fetchAndSyncRemoteFolder(client);
} else {
- // TODO Enable when "On Device" is recovered ?
+ fetchFavoritesToSyncFromLocalData();
mChildren = mStorageManager.getFolderContent(mLocalFolder/*, false*/);
}
+
+ if (result.isSuccess()) {
+ // request for the synchronization of KEPT-IN-SYNC file contents
+ startContentSynchronizations(mFilesToSyncContents, client);
+ }
}
if (!mSyncFullAccount) {
@@ -239,9 +238,8 @@ public class RefreshFolderOperation extends RemoteOperation {
private RemoteOperationResult checkForChanges(OwnCloudClient client) {
mRemoteFolderChanged = true;
RemoteOperationResult result = null;
- String remotePath = null;
+ String remotePath = mLocalFolder.getRemotePath();
- remotePath = mLocalFolder.getRemotePath();
Log_OC.d(TAG, "Checking changes in " + mAccount.name + remotePath);
// remote request
@@ -264,7 +262,7 @@ public class RefreshFolderOperation extends RemoteOperation {
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"));
} else {
@@ -337,15 +335,15 @@ public class RefreshFolderOperation extends RemoteOperation {
mLocalFolder = mStorageManager.getFileByPath(mLocalFolder.getRemotePath());
// parse data from remote folder
- OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0));
+ OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(0));
remoteFolder.setParentId(mLocalFolder.getParentId());
remoteFolder.setFileId(mLocalFolder.getFileId());
- Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+ Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
+ " changed - starting update of local data ");
List updatedFiles = new Vector(folderAndFiles.size() - 1);
- List filesToSyncContents = new Vector();
+ mFilesToSyncContents.clear();
// get current data about local contents of the folder to synchronize
// TODO Enable when "On Device" is recovered ?
@@ -356,54 +354,55 @@ public class RefreshFolderOperation extends RemoteOperation {
}
// loop to update every child
- OCFile remoteFile = null, localFile = null;
+ OCFile remoteFile = null, localFile = null, updatedFile = null;
+ RemoteFile r;
for (int i=1; i 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) {
RemoteOperationResult result = null;
@@ -572,24 +477,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
* of the synchronization.
@@ -614,8 +501,20 @@ public class RefreshFolderOperation extends RemoteOperation {
}
- public boolean getRemoteFolderChanged() {
- return mRemoteFolderChanged;
+ private void fetchFavoritesToSyncFromLocalData() {
+ List 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);
+ }
+ }
}
}
diff --git a/src/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/com/owncloud/android/operations/SynchronizeFileOperation.java
index f94adb15bd..bc0caf19ab 100644
--- a/src/com/owncloud/android/operations/SynchronizeFileOperation.java
+++ b/src/com/owncloud/android/operations/SynchronizeFileOperation.java
@@ -22,7 +22,6 @@
package com.owncloud.android.operations;
-import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.files.services.FileUploader;
@@ -208,15 +207,13 @@ public class SynchronizeFileOperation extends SyncOperation {
/// check changes in server and local file
boolean serverChanged = false;
- /* time for eTag is coming, but not yet
- if (mServerFile.getEtag() != null) {
- serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));
- } else { */
- serverChanged = (
- mServerFile.getModificationTimestamp() !=
- mLocalFile.getModificationTimestampAtLastSyncForData()
- );
- //}
+ if (mLocalFile.getEtag() == null || mLocalFile.getEtag().length() == 0) {
+ // file uploaded (null) or downloaded ("") before upgrade to version 1.8.0; check the old condition
+ serverChanged = mServerFile.getModificationTimestamp() !=
+ mLocalFile.getModificationTimestampAtLastSyncForData();
+ } else {
+ serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag()));
+ }
boolean localChanged = (
mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
);
@@ -225,6 +222,7 @@ public class SynchronizeFileOperation extends SyncOperation {
//if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
if (localChanged && serverChanged) {
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
+ getStorageManager().saveConflict(mLocalFile, mServerFile.getEtag());
} else if (localChanged) {
if (mSyncFileContents && mAllowUploads) {
@@ -254,6 +252,7 @@ public class SynchronizeFileOperation extends SyncOperation {
mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
mServerFile.setStoragePath(mLocalFile.getStoragePath());
mServerFile.setParentId(mLocalFile.getParentId());
+ mServerFile.setEtag(mLocalFile.getEtag());
getStorageManager().saveFile(mServerFile);
}
@@ -264,7 +263,11 @@ public class SynchronizeFileOperation extends SyncOperation {
result = new RemoteOperationResult(ResultCode.OK);
}
- }
+ // safe blanket: sync'ing a not in-conflict file will clean wrong conflict markers in ancestors
+ if (result.getCode() != ResultCode.SYNC_CONFLICT) {
+ getStorageManager().saveConflict(mLocalFile, null);
+ }
+ }
}
diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java
index 78b6a7baac..b8da4a1fb0 100644
--- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java
+++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java
@@ -60,7 +60,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Fetches the list and properties of the files contained in the given folder, including their
* properties, and updates the local database with them.
*
- * Does NOT enter in the child folders to synchronize their contents also.
+ * Does NOT enter in the child folders to synchronize their contents also, BUT requests for a new operation instance
+ * doing so.
*/
public class SynchronizeFolderOperation extends SyncOperation {
@@ -96,10 +97,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
private List mFilesForDirectDownload;
// to avoid extra PROPFINDs when there was no change in the folder
- private List mFilesToSyncContentsWithoutUpload;
- // this will go out when 'folder synchronization' replaces 'folder download'; step by step
-
- private List mFavouriteFilesToSyncContents;
+ private List mFilesToSyncContents;
// this will be used for every file when 'folder synchronization' replaces 'folder download'
private final AtomicBoolean mCancellationRequested;
@@ -120,8 +118,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
mContext = context;
mRemoteFolderChanged = false;
mFilesForDirectDownload = new Vector();
- mFilesToSyncContentsWithoutUpload = new Vector();
- mFavouriteFilesToSyncContents = new Vector();
+ mFilesToSyncContents = new Vector();
mCancellationRequested = new AtomicBoolean(false);
}
@@ -281,7 +278,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
FileDataStorageManager storageManager = getStorageManager();
// parse data from remote folder
- OCFile remoteFolder = fillOCFile((RemoteFile)folderAndFiles.get(0));
+ OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(0));
remoteFolder.setParentId(mLocalFolder.getParentId());
remoteFolder.setFileId(mLocalFolder.getFileId());
@@ -290,8 +287,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
List updatedFiles = new Vector(folderAndFiles.size() - 1);
mFilesForDirectDownload.clear();
- mFilesToSyncContentsWithoutUpload.clear();
- mFavouriteFilesToSyncContents.clear();
+ mFilesToSyncContents.clear();
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
@@ -306,85 +302,77 @@ public class SynchronizeFolderOperation extends SyncOperation {
}
// loop to synchronize every child
- OCFile remoteFile = null, localFile = null;
+ OCFile remoteFile = null, localFile = null, updatedFile = null;
+ RemoteFile r;
for (int i=1; i mDataTransferListeners = new HashSet();
private AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
private Context mContext;
@@ -312,61 +311,61 @@ public class UploadFileOperation extends RemoteOperation {
(new File(mFile.getStoragePath())).length() >
ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(),
- mFile.getRemotePath(), mFile.getMimetype());
+ mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict());
} else {
mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
- mFile.getRemotePath(), mFile.getMimetype());
+ mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict());
}
Iterator listener = mDataTransferListeners.iterator();
while (listener.hasNext()) {
mUploadOperation.addDatatransferProgressListener(listener.next());
}
- if (!mCancellationRequested.get()) {
- result = mUploadOperation.execute(client);
+ if (mCancellationRequested.get()) {
+ throw new OperationCancelledException();
+ }
- /// move local temporal file or original file to its corresponding
- // location in the ownCloud local folder
- if (result.isSuccess()) {
- if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
- mFile.setStoragePath(null);
+ result = mUploadOperation.execute(client);
- } else {
- mFile.setStoragePath(expectedPath);
- File fileToMove = null;
- if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
- // ; see where temporalFile was
- // set
- fileToMove = temporalFile;
- } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
- fileToMove = originalFile;
- }
- if (!expectedFile.equals(fileToMove)) {
- File expectedFolder = expectedFile.getParentFile();
- expectedFolder.mkdirs();
- if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
- mFile.setStoragePath(null); // forget the local file
- // by now, treat this as a success; the file was
- // uploaded; the user won't like that the local file
- // is not linked, but this should be a very rare
- // fail;
- // the best option could be show a warning message
- // (but not a fail)
- // result = new
- // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
- // return result;
- }
+ /// move local temporal file or original file to its corresponding
+ // location in the ownCloud local folder
+ if (result.isSuccess()) {
+ if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
+ mFile.setStoragePath(null);
+
+ } else {
+ mFile.setStoragePath(expectedPath);
+ File fileToMove = null;
+ if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
+ // ; see where temporalFile was
+ // set
+ fileToMove = temporalFile;
+ } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
+ fileToMove = originalFile;
+ }
+ if (!expectedFile.equals(fileToMove)) {
+ File expectedFolder = expectedFile.getParentFile();
+ expectedFolder.mkdirs();
+ if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
+ mFile.setStoragePath(null); // forget the local file
+ // by now, treat this as a success; the file was
+ // uploaded; the user won't like that the local file
+ // is not linked, but this should be a very rare
+ // fail;
+ // the best option could be show a warning message
+ // (but not a fail)
+ // result = new
+ // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
+ // return result;
}
}
}
+
+ } else if (result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED ) {
+ result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
}
} catch (Exception e) {
- // TODO something cleaner with cancellations
- if (mCancellationRequested.get()) {
- result = new RemoteOperationResult(new OperationCancelledException());
- } else {
- result = new RemoteOperationResult(e);
- }
+ result = new RemoteOperationResult(e);
} finally {
if (temporalFile != null && !originalFile.equals(temporalFile)) {
@@ -406,7 +405,7 @@ public class UploadFileOperation extends RemoteOperation {
newFile.setModificationTimestamp(mFile.getModificationTimestamp());
newFile.setModificationTimestampAtLastSyncForData(
mFile.getModificationTimestampAtLastSyncForData());
- // newFile.setEtag(mFile.getEtag())
+ newFile.setEtag(mFile.getEtag());
newFile.setFavorite(mFile.isFavorite());
newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
newFile.setLastSyncDateForData(mFile.getLastSyncDateForData());
diff --git a/src/com/owncloud/android/providers/FileContentProvider.java b/src/com/owncloud/android/providers/FileContentProvider.java
index 70cd8976b2..609c07cab7 100644
--- a/src/com/owncloud/android/providers/FileContentProvider.java
+++ b/src/com/owncloud/android/providers/FileContentProvider.java
@@ -23,7 +23,6 @@
package com.owncloud.android.providers;
import java.io.File;
-import java.security.Provider;
import java.util.ArrayList;
import java.util.HashMap;
@@ -107,6 +106,8 @@ public class FileContentProvider extends ContentProvider {
ProviderTableMeta.FILE_UPDATE_THUMBNAIL);
mFileProjectionMap.put(ProviderTableMeta.FILE_IS_DOWNLOADING,
ProviderTableMeta.FILE_IS_DOWNLOADING);
+ mFileProjectionMap.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT,
+ ProviderTableMeta.FILE_ETAG_IN_CONFLICT);
}
private static final int SINGLE_FILE = 1;
@@ -527,59 +528,6 @@ public class FileContentProvider extends ContentProvider {
}
}
- /*
- private int updateFolderSize(SQLiteDatabase db, String folderId) {
- int count = 0;
- String [] whereArgs = new String[] { folderId };
-
- // read current size saved for the folder
- long folderSize = 0;
- long folderParentId = -1;
- Uri selectFolderUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, folderId);
- String[] folderProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
- String folderWhere = ProviderTableMeta._ID + "=?";
- Cursor folderCursor = query(db, selectFolderUri, folderProjection, folderWhere, whereArgs, null);
- if (folderCursor != null && folderCursor.moveToFirst()) {
- folderSize = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));;
- folderParentId = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_PARENT));;
- }
- folderCursor.close();
-
- // read and sum sizes of children
- long childrenSize = 0;
- Uri selectChildrenUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, folderId);
- String[] childrenProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT};
- String childrenWhere = ProviderTableMeta.FILE_PARENT + "=?";
- Cursor childrenCursor = query(db, selectChildrenUri, childrenProjection, childrenWhere, whereArgs, null);
- if (childrenCursor != null && childrenCursor.moveToFirst()) {
- while (!childrenCursor.isAfterLast()) {
- childrenSize += childrenCursor.getLong(childrenCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));
- childrenCursor.moveToNext();
- }
- }
- childrenCursor.close();
-
- // update if needed
- if (folderSize != childrenSize) {
- Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize);
- ContentValues cv = new ContentValues();
- cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize);
- count = db.update(ProviderTableMeta.FILE_TABLE_NAME, cv, folderWhere, whereArgs);
-
- // propagate update until root
- if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) {
- Log_OC.d("FileContentProvider", "Propagating update to " + folderParentId);
- updateFolderSize(db, String.valueOf(folderParentId));
- } else {
- Log_OC.d("FileContentProvider", "NOT propagating to " + folderParentId);
- }
- } else {
- Log_OC.d("FileContentProvider", "NOT updating, sizes are " + folderSize + " and " + childrenSize);
- }
- return count;
- }
-*/
-
@Override
public ContentProviderResult[] applyBatch (ArrayList operations)
throws OperationApplicationException {
@@ -636,7 +584,8 @@ public class FileContentProvider extends ContentProvider {
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + " INTEGER," //boolean
- + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER);" //boolean
+ + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER," //boolean
+ + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT);"
);
// Create table ocshares
@@ -836,6 +785,24 @@ public class FileContentProvider extends ContentProvider {
if (!upgraded)
Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
", newVersion == " + newVersion);
+
+ if (oldVersion < 11 && newVersion >= 11) {
+ Log_OC.i("SQL", "Entering in the #11 ADD in onUpgrade");
+ db.beginTransaction();
+ try {
+ db .execSQL("ALTER TABLE " + ProviderTableMeta.FILE_TABLE_NAME +
+ " ADD COLUMN " + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " 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/services/OperationsService.java b/src/com/owncloud/android/services/OperationsService.java
index 099bd087ff..c122817083 100644
--- a/src/com/owncloud/android/services/OperationsService.java
+++ b/src/com/owncloud/android/services/OperationsService.java
@@ -100,7 +100,7 @@ public class OperationsService extends Service {
public static final String ACTION_REMOVE = "REMOVE";
public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER";
public static final String ACTION_SYNC_FILE = "SYNC_FILE";
- public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";//for the moment, just to download
+ public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";
public static final String ACTION_MOVE_FILE = "MOVE_FILE";
public static final String ACTION_COPY_FILE = "COPY_FILE";
@@ -234,7 +234,6 @@ public class OperationsService extends Service {
*/
@Override
public IBinder onBind(Intent intent) {
- //Log_OC.wtf(TAG, "onBind" );
return mOperationsBinder;
}
@@ -615,7 +614,7 @@ public class OperationsService extends Service {
);
} else if (action.equals(ACTION_SYNC_FOLDER)) {
- // Sync file
+ // Sync folder (all its descendant files are sync'ed)
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
operation = new SynchronizeFolderOperation(
this, // TODO remove this dependency from construction time
@@ -623,7 +622,7 @@ public class OperationsService extends Service {
account,
System.currentTimeMillis() // TODO remove this dependency from construction time
);
-
+
} else if (action.equals(ACTION_MOVE_FILE)) {
// Move file/folder
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
@@ -726,7 +725,6 @@ public class OperationsService extends Service {
}
}
if (count == 0) {
- //mOperationResults.put(operation.hashCode(), result);
Pair undispatched =
new Pair(operation, result);
mUndispatchedFinishedOperations.put(((Runnable) operation).hashCode(), undispatched);
diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java
index 7f8b0db1c0..7dfe52017b 100644
--- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java
+++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java
@@ -30,7 +30,6 @@ import java.util.Map;
import org.apache.jackrabbit.webdav.DavException;
-import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -59,7 +58,7 @@ import android.support.v4.app.NotificationCompat;
* Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
* 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)}.
*/
public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
@@ -77,9 +76,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
".EVENT_FULL_SYNC_END";
public static final String 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() +
".EXTRA_ACCOUNT_NAME";
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))
return;
- /*
- OCFile folder,
- long currentSyncTime,
- boolean updateFolderProperties,
- boolean syncFullAccount,
- DataStorageManager dataStorageManager,
- Account account,
- Context context ) {
- }
- */
// folder synchronization
RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder,
mCurrentSyncTime,
@@ -308,7 +295,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
// synchronize children folders
List children = synchFolderOp.getChildren();
// beware of the 'hidden' recursion here!
- fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged());
+ syncChildren(children);
}
} else {
@@ -351,25 +338,19 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
/**
* 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.
*/
- private void fetchChildren(OCFile parent, List files, boolean parentEtagChanged) {
+ private void syncChildren(List files) {
int i;
- OCFile newFile = null;
- //String etag = null;
- //boolean syncDown = false;
+ OCFile newFile;
for (i=0; i < files.size() && !mCancellation; i++) {
newFile = files.get(i);
if (newFile.isFolder()) {
- /*
- etag = newFile.getEtag();
- syncDown = (parentEtagChanged || etag == null || etag.length() == 0);
- if(syncDown) { */
- synchronizeFolder(newFile);
- //sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(),
- // null);
- //}
+ synchronizeFolder(newFile);
}
}
diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java
index 240d146fb5..644cf014d8 100644
--- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java
+++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java
@@ -1048,7 +1048,11 @@ public class FileDisplayActivity extends HookActivity
(uploadedRemotePath.startsWith(currentDir.getRemotePath()));
if (sameAccount && isDescendant) {
- refreshListOfFilesFragment();
+ String linkedToRemotePath =
+ intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
+ if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
+ refreshListOfFilesFragment();
+ }
}
boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT,
@@ -1101,6 +1105,16 @@ public class FileDisplayActivity extends HookActivity
}
+ // TODO refactor this receiver, and maybe DownloadFinishReceiver; this method is duplicated :S
+ private boolean isAscendant(String linkedToRemotePath) {
+ OCFile currentDir = getCurrentDir();
+ return (
+ currentDir != null &&
+ currentDir.getRemotePath().startsWith(linkedToRemotePath)
+ );
+ }
+
+
}
@@ -1112,11 +1126,10 @@ public class FileDisplayActivity extends HookActivity
*/
private class DownloadFinishReceiver extends BroadcastReceiver {
- //int refreshCounter = 0;
@Override
public void onReceive(Context context, Intent intent) {
try {
- boolean sameAccount = isSameAccount(context, intent);
+ boolean sameAccount = isSameAccount(intent);
String downloadedRemotePath =
intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
boolean isDescendant = isDescendant(downloadedRemotePath);
@@ -1125,7 +1138,6 @@ public class FileDisplayActivity extends HookActivity
String linkedToRemotePath =
intent.getStringExtra(FileDownloader.EXTRA_LINKED_TO_PATH);
if (linkedToRemotePath == null || isAscendant(linkedToRemotePath)) {
- //Log_OC.v(TAG, "refresh #" + ++refreshCounter);
refreshListOfFilesFragment();
}
refreshSecondFragment(
@@ -1167,7 +1179,7 @@ public class FileDisplayActivity extends HookActivity
);
}
- private boolean isSameAccount(Context context, Intent intent) {
+ private boolean isSameAccount(Intent intent) {
String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
return (accountName != null && getAccount() != null &&
accountName.equals(getAccount().name));
diff --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java
index 5e94e0f27f..d0abff29a0 100644
--- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java
+++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java
@@ -249,24 +249,47 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
mTransferServiceGetter.getFileDownloaderBinder();
FileUploaderBinder uploaderBinder =
mTransferServiceGetter.getFileUploaderBinder();
- boolean downloading = (downloaderBinder != null &&
- downloaderBinder.isDownloading(mAccount, file));
OperationsServiceBinder opsBinder =
mTransferServiceGetter.getOperationsServiceBinder();
- downloading |= (opsBinder != null &&
- opsBinder.isSynchronizing(mAccount, file.getRemotePath()));
- if (downloading) {
- localStateView.setImageResource(R.drawable.downloading_file_indicator);
+
+ localStateView.setVisibility(View.INVISIBLE); // default first
+
+ if ( //synchronizing
+ opsBinder != null &&
+ opsBinder.isSynchronizing(mAccount, file.getRemotePath())
+ ) {
+ localStateView.setImageResource(R.drawable.synchronizing_file_indicator);
localStateView.setVisibility(View.VISIBLE);
- } else if (uploaderBinder != null &&
- uploaderBinder.isUploading(mAccount, file)) {
- localStateView.setImageResource(R.drawable.uploading_file_indicator);
+
+ } else if ( // downloading
+ downloaderBinder != null &&
+ downloaderBinder.isDownloading(mAccount, file)
+ ) {
+ localStateView.setImageResource(
+ file.isFolder() ?
+ R.drawable.synchronizing_file_indicator :
+ R.drawable.downloading_file_indicator
+ );
localStateView.setVisibility(View.VISIBLE);
+
+ } else if ( //uploading
+ uploaderBinder != null &&
+ uploaderBinder.isUploading(mAccount, file)
+ ) {
+ localStateView.setImageResource(
+ file.isFolder() ?
+ R.drawable.synchronizing_file_indicator :
+ R.drawable.uploading_file_indicator
+ );
+ localStateView.setVisibility(View.VISIBLE);
+
+ } else if (file.getEtagInConflict() != null) { // conflict
+ localStateView.setImageResource(R.drawable.conflict_file_indicator);
+ localStateView.setVisibility(View.VISIBLE);
+
} else if (file.isDown()) {
localStateView.setImageResource(R.drawable.local_file_indicator);
localStateView.setVisibility(View.VISIBLE);
- } else {
- localStateView.setVisibility(View.INVISIBLE);
}
// share with me icon
@@ -345,46 +368,6 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
return view;
}
- /**
- * Local Folder size in human readable format
- *
- * @param path
- * String
- * @return Size in human readable format
- */
- private String getFolderSizeHuman(String path) {
-
- File dir = new File(path);
-
- if (dir.exists()) {
- long bytes = FileStorageUtils.getFolderSize(dir);
- return DisplayUtils.bytesToHumanReadable(bytes);
- }
-
- return "0 B";
- }
-
- /**
- * Local Folder size
- * @param dir File
- * @return Size in bytes
- */
- private long getFolderSize(File dir) {
- if (dir.exists()) {
- long result = 0;
- File[] fileList = dir.listFiles();
- for(int i = 0; i < fileList.length; i++) {
- if(fileList[i].isDirectory()) {
- result += getFolderSize(fileList[i]);
- } else {
- result += fileList[i].length();
- }
- }
- return result;
- }
- return 0;
- }
-
@Override
public int getViewTypeCount() {
return 1;
diff --git a/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java b/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
index 28419e62a9..f8310a1de9 100644
--- a/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
+++ b/src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
@@ -25,7 +25,6 @@ package com.owncloud.android.ui.dialog;
*
* Triggers the removal according to the user response.
*/
-import java.util.Vector;
import android.app.Dialog;
import android.os.Bundle;
@@ -106,34 +105,6 @@ implements ConfirmationDialogFragmentListener {
public void onCancel(String callerTag) {
ComponentsGetter cg = (ComponentsGetter)getActivity();
cg.getFileOperationsHelper().removeFile(mTargetFile, true);
-
- FileDataStorageManager storageManager = cg.getStorageManager();
-
- boolean containsFavorite = false;
- if (mTargetFile.isFolder()) {
- // TODO Enable when "On Device" is recovered ?
- Vector 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
diff --git a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java
index b2e6464cd4..6aafbf76c3 100644
--- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java
+++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java
@@ -248,9 +248,8 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
dialog.show(getFragmentManager(), FTAG_RENAME_FILE);
return true;
}
- case R.id.action_cancel_download:
- case R.id.action_cancel_upload: {
- ((FileDisplayActivity) mContainerActivity).cancelTransference(getFile());
+ case R.id.action_cancel_sync: {
+ ((FileDisplayActivity)mContainerActivity).cancelTransference(getFile());
return true;
}
case R.id.action_download_file:
@@ -300,7 +299,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
}
}
-
/**
* Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.
*
diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java
index 02bd845dc5..23590b5e75 100644
--- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java
+++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java
@@ -368,9 +368,8 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi
mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
return true;
}
- case R.id.action_cancel_download:
- case R.id.action_cancel_upload: {
- ((FileDisplayActivity) mContainerActivity).cancelTransference(mTargetFile);
+ case R.id.action_cancel_sync: {
+ ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
return true;
}
case R.id.action_see_details: {
diff --git a/src/com/owncloud/android/utils/ErrorMessageAdapter.java b/src/com/owncloud/android/utils/ErrorMessageAdapter.java
index b80cc573a1..945f70f892 100644
--- a/src/com/owncloud/android/utils/ErrorMessageAdapter.java
+++ b/src/com/owncloud/android/utils/ErrorMessageAdapter.java
@@ -238,7 +238,7 @@ public class ErrorMessageAdapter {
} else { // Generic error
// Show a Message, operation finished without success
- message = String.format(res.getString(R.string.download_folder_failed_content),
+ message = String.format(res.getString(R.string.sync_folder_failed_content),
folderPathName);
}
}
diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java
index 398377178a..1740ca583b 100644
--- a/src/com/owncloud/android/utils/FileStorageUtils.java
+++ b/src/com/owncloud/android/utils/FileStorageUtils.java
@@ -32,6 +32,7 @@ import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.files.RemoteFile;
+import android.accounts.Account;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
@@ -53,8 +54,6 @@ public class FileStorageUtils {
public static Boolean mSortAscending = true;
- //private static final String LOG_TAG = "FileStorageUtils";
-
public static final String getSavePath(String accountName) {
File sdCard = Environment.getExternalStorageDirectory();
return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@");
@@ -120,7 +119,7 @@ public class FileStorageUtils {
* 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.
+ * @return New OCFile instance representing the remote resource described by remote.
*/
public static OCFile fillOCFile(RemoteFile remote) {
OCFile file = new OCFile(remote.getRemotePath());
@@ -302,5 +301,33 @@ public class FileStorageUtils {
String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
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());
+ }
+ }
+ }
+
}