Browse Source

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

David A. Velasco 10 năm trước cách đây
mục cha
commit
e6c1454458

BIN
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);