浏览代码

Persist conflicts in local database and show with an icon in the list of files

David A. Velasco 9 年之前
父节点
当前提交
e6c1454458

二进制
res/drawable/conflict_file_indicator.png


+ 33 - 2
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -204,7 +204,8 @@ 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_IN_CONFLICT, file.isInConflict());
+
         boolean sameRemotePath = fileExists(file.getRemotePath());
         if (sameRemotePath ||                fileExists(file.getFileId())) {           // for renamed files; no more delete and create
 
@@ -313,6 +314,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_IN_CONFLICT, file.isInConflict());
 
             boolean existsByPath = fileExists(file.getRemotePath());
             if (existsByPath || fileExists(file.getFileId())) {
@@ -942,7 +944,9 @@ 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.setInConflict(c.getInt(
+                    c.getColumnIndex(ProviderTableMeta.FILE_IN_CONFLICT)) == 1 ? true : false);
+
         }
         return file;
     }
@@ -1310,6 +1314,10 @@ public class FileDataStorageManager {
                         ProviderTableMeta.FILE_IS_DOWNLOADING,
                         file.isDownloading() ? 1 : 0
                 );
+                cv.put(
+                        ProviderTableMeta.FILE_IN_CONFLICT,
+                        file.isInConflict() ? 1 : 0
+                );
 
                 boolean existsByPath = fileExists(file.getRemotePath());
                 if (existsByPath || fileExists(file.getFileId())) {
@@ -1578,4 +1586,27 @@ public class FileDataStorageManager {
 
     }
 
+    public void saveConflict(long fileId, boolean inConflict) {
+        ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.FILE_IN_CONFLICT, inConflict);
+        if (getContentResolver() != null) {
+            getContentResolver().update(
+                    ProviderTableMeta.CONTENT_URI_FILE,
+                    cv,
+                    ProviderTableMeta._ID + "=?",
+                    new String[] { String.valueOf(fileId)}
+            );
+        } else {
+            try {
+                getContentProviderClient().update(
+                        ProviderTableMeta.CONTENT_URI_FILE,
+                        cv,
+                        ProviderTableMeta._ID + "=?",
+                        new String[]{String.valueOf(fileId)}
+                );
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage());
+            }
+        }
+    }
 }

+ 12 - 5
src/com/owncloud/android/datamodel/OCFile.java

@@ -74,6 +74,8 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
 
     private boolean mIsDownloading;
 
+    private boolean mInConflict;
+
 
     /**
      * Create new {@link OCFile} with given path.
@@ -115,8 +117,9 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         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;
+        mInConflict = source.readInt() == 1;
 
     }
 
@@ -142,6 +145,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         dest.writeString(mRemoteId);
         dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
         dest.writeInt(mIsDownloading ? 1 : 0);
+        dest.writeInt(mInConflict ? 1 : 0);
     }
 
     /**
@@ -357,6 +361,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         mRemoteId = null;
         mNeedsUpdateThumbnail = false;
         mIsDownloading = false;
+        mInConflict = false;
     }
 
     /**
@@ -597,9 +602,11 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         this.mIsDownloading = isDownloading;
     }
 
-    public boolean isSynchronizing() {
-        // TODO real implementation
-        return false;
+    public boolean isInConflict() {
+        return mInConflict;
     }
 
+    public void setInConflict(boolean inConflict) {
+        mInConflict = inConflict;
+    }
 }

+ 3 - 2
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_IN_CONFLICT = "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";
-        
+
 
     }
 }

+ 26 - 21
src/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -354,50 +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<folderAndFiles.size(); i++) {
             /// new OCFile instance with the data from the server
-            remoteFile = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(i));
-            remoteFile.setParentId(mLocalFolder.getFileId());
+            r = (RemoteFile) folderAndFiles.get(i);
+            remoteFile = FileStorageUtils.fillOCFile(r);
+
+            /// new OCFile instance to merge fresh data from server with local state
+            updatedFile = FileStorageUtils.fillOCFile(r);
+            updatedFile.setParentId(mLocalFolder.getFileId());
 
             /// retrieve local data for the read file 
             //  localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
             localFile = localFilesMap.remove(remoteFile.getRemotePath());
             
-            /// add to the remoteFile (the new one) data about LOCAL STATE (not existing in server)
-            remoteFile.setLastSyncDateForProperties(mCurrentSyncTime);
+            /// add to updatedFile data about LOCAL STATE (not existing in server)
+            updatedFile.setLastSyncDateForProperties(mCurrentSyncTime);
             if (localFile != null) {
-                // some properties of local state are kept unmodified
-                remoteFile.setFileId(localFile.getFileId());
-                remoteFile.setFavorite(localFile.isFavorite());
-                remoteFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
-                remoteFile.setModificationTimestampAtLastSyncForData(
+                updatedFile.setFileId(localFile.getFileId());
+                updatedFile.setFavorite(localFile.isFavorite());
+                updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
+                updatedFile.setModificationTimestampAtLastSyncForData(
                         localFile.getModificationTimestampAtLastSyncForData()
                 );
-                remoteFile.setStoragePath(localFile.getStoragePath());
+                updatedFile.setStoragePath(localFile.getStoragePath());
                 // eTag will not be updated unless file CONTENTS are synchronized
-                remoteFile.setEtag(localFile.getEtag());
-                if (remoteFile.isFolder()) {
-                    remoteFile.setFileLength(localFile.getFileLength()); 
+                updatedFile.setEtag(localFile.getEtag());
+                if (updatedFile.isFolder()) {
+                    updatedFile.setFileLength(localFile.getFileLength());
                         // TODO move operations about size of folders to FileContentProvider
                 } else if (mRemoteFolderChanged && remoteFile.isImage() &&
                         remoteFile.getModificationTimestamp() !=
                                 localFile.getModificationTimestamp()) {
-                    remoteFile.setNeedsUpdateThumbnail(true);
+                    updatedFile.setNeedsUpdateThumbnail(true);
                     Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
                 }
-                remoteFile.setPublicLink(localFile.getPublicLink());
-                remoteFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setPublicLink(localFile.getPublicLink());
+                updatedFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setInConflict(localFile.isInConflict());
             } else {
                 // remote eTag will not be updated unless file CONTENTS are synchronized
-                remoteFile.setEtag("");
+                updatedFile.setEtag("");
             }
 
             /// check and fix, if needed, local storage path
-            FileStorageUtils.searchForLocalFileInDefaultPath(remoteFile, mAccount);
+            FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, mAccount);
 
             /// prepare content synchronization for kept-in-sync files
-            if (remoteFile.isFavorite()) {
+            if (updatedFile.isFavorite()) {
                 SynchronizeFileOperation operation = new SynchronizeFileOperation(  localFile,        
                                                                                     remoteFile, 
                                                                                     mAccount, 
@@ -408,7 +413,7 @@ public class RefreshFolderOperation extends RemoteOperation {
                 mFilesToSyncContents.add(operation);
             }
 
-            updatedFiles.add(remoteFile);
+            updatedFiles.add(updatedFile);
         }
 
         // save updated contents in local database

+ 2 - 6
src/com/owncloud/android/operations/SynchronizeFileOperation.java

@@ -218,16 +218,11 @@ public class SynchronizeFileOperation extends SyncOperation {
                     mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData()
                 );
 
-                Log_OC.d(TAG, "TOKENs checked to SYNC " + mRemotePath );
-                Log_OC.d(TAG, "  server#modificationTimestamp " + mServerFile.getModificationTimestamp());
-                Log_OC.d(TAG, "  local#modificationTimestampAtLastSyncForData " + mServerFile.getModificationTimestampAtLastSyncForData());
-                Log_OC.d(TAG, "  local#modificationTimestamp " + mLocalFile.getLocalModificationTimestamp());
-                Log_OC.d(TAG, "  local#lastSyncDateForData " + mLocalFile.getLastSyncDateForData());
-
                 /// decide action to perform depending upon changes
                 //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
                 if (localChanged && serverChanged) {
                     result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
+                    getStorageManager().saveConflict(mLocalFile.getFileId(), true);
 
                 } else if (localChanged) {
                     if (mSyncFileContents && mAllowUploads) {
@@ -257,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);
 
                     }

+ 28 - 23
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -302,47 +302,52 @@ 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<folderAndFiles.size(); i++) {
             /// new OCFile instance with the data from the server
-            remoteFile = FileStorageUtils.fillOCFile((RemoteFile)folderAndFiles.get(i));
-            remoteFile.setParentId(mLocalFolder.getFileId());
+            r = (RemoteFile) folderAndFiles.get(i);
+            remoteFile = FileStorageUtils.fillOCFile(r);
+
+            /// new OCFile instance to merge fresh data from server with local state
+            updatedFile = FileStorageUtils.fillOCFile(r);
+            updatedFile.setParentId(mLocalFolder.getFileId());
 
             /// retrieve local data for the read file
             //  localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
             localFile = localFilesMap.remove(remoteFile.getRemotePath());
 
-            /// add to the remoteFile (the new one) data about LOCAL STATE (not existing in server)
-            remoteFile.setLastSyncDateForProperties(mCurrentSyncTime);
+            /// add to updatedFile data about LOCAL STATE (not existing in server)
+            updatedFile.setLastSyncDateForProperties(mCurrentSyncTime);
             if (localFile != null) {
-                // some properties of local state are kept unmodified
-                remoteFile.setFileId(localFile.getFileId());
-                remoteFile.setFavorite(localFile.isFavorite());
-                remoteFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
-                remoteFile.setModificationTimestampAtLastSyncForData(
+                updatedFile.setFileId(localFile.getFileId());
+                updatedFile.setFavorite(localFile.isFavorite());
+                updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
+                updatedFile.setModificationTimestampAtLastSyncForData(
                         localFile.getModificationTimestampAtLastSyncForData()
                 );
-                remoteFile.setStoragePath(localFile.getStoragePath());
-                // eTag will not be updated unless contents are synchronized
-                remoteFile.setEtag(localFile.getEtag());
-                if (remoteFile.isFolder()) {
-                    remoteFile.setFileLength(localFile.getFileLength());
+                updatedFile.setStoragePath(localFile.getStoragePath());
+                // eTag will not be updated unless file CONTENTS are synchronized
+                updatedFile.setEtag(localFile.getEtag());
+                if (updatedFile.isFolder()) {
+                    updatedFile.setFileLength(localFile.getFileLength());
                         // TODO move operations about size of folders to FileContentProvider
                 } else if (mRemoteFolderChanged && remoteFile.isImage() &&
                         remoteFile.getModificationTimestamp() !=
                                 localFile.getModificationTimestamp()) {
-                    remoteFile.setNeedsUpdateThumbnail(true);
+                    updatedFile.setNeedsUpdateThumbnail(true);
                     Log.d(TAG, "Image " + remoteFile.getFileName() + " updated on the server");
                 }
-                remoteFile.setPublicLink(localFile.getPublicLink());
-                remoteFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setPublicLink(localFile.getPublicLink());
+                updatedFile.setShareByLink(localFile.isShareByLink());
+                updatedFile.setInConflict(localFile.isInConflict());
             } else {
-                // remote eTag will not be updated unless contents are synchronized
-                remoteFile.setEtag("");
+                // remote eTag will not be updated unless file CONTENTS are synchronized
+                updatedFile.setEtag("");
             }
 
             /// check and fix, if needed, local storage path
-            searchForLocalFileInDefaultPath(remoteFile);
+            searchForLocalFileInDefaultPath(updatedFile);
             
             /// classify file to sync/download contents later
             if (remoteFile.isFolder()) {
@@ -367,7 +372,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
                 
             }
 
-            updatedFiles.add(remoteFile);
+            updatedFiles.add(updatedFile);
         }
 
         // save updated contents in local database
@@ -399,7 +404,7 @@ public class SynchronizeFolderOperation extends SyncOperation {
                     /// this should result in direct upload of files that were locally modified
                     SynchronizeFileOperation operation = new SynchronizeFileOperation(
                             child,
-                            child,  // cheating with the remote file to get an upadte to server; to refactor
+                            (child.isInConflict() ? null : child),
                             mAccount,
                             true,
                             mContext

+ 22 - 1
src/com/owncloud/android/providers/FileContentProvider.java

@@ -107,6 +107,8 @@ public class FileContentProvider extends ContentProvider {
                 ProviderTableMeta.FILE_UPDATE_THUMBNAIL);
         mFileProjectionMap.put(ProviderTableMeta.FILE_IS_DOWNLOADING,
                 ProviderTableMeta.FILE_IS_DOWNLOADING);
+        mFileProjectionMap.put(ProviderTableMeta.FILE_IN_CONFLICT,
+                ProviderTableMeta.FILE_IN_CONFLICT);
     }
 
     private static final int SINGLE_FILE = 1;
@@ -634,7 +636,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_IN_CONFLICT + " INTEGER);"    //boolean
                     );
 
             // Create table ocshares
@@ -834,6 +837,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_IN_CONFLICT + " INTEGER " +
+                            " DEFAULT 0");
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion +
+                        ", newVersion == " + newVersion);
+
         }
     }
 

+ 4 - 0
src/com/owncloud/android/ui/adapter/FileListListAdapter.java

@@ -291,6 +291,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                         localStateView.setImageResource(R.drawable.uploading_file_indicator);
                         localStateView.setVisibility(View.VISIBLE);
 
+                    } else if (file.isInConflict()) {   // 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);