Browse Source

Sync of encrypted folders, in sync with RefreshFolderOperation.synchronizeData

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 4 năm trước cách đây
mục cha
commit
93104917a7

+ 28 - 11
src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -428,11 +428,15 @@ public class RefreshFolderOperation extends RemoteOperation {
         // update richWorkspace
         mLocalFolder.setRichWorkspace(remoteFolder.getRichWorkspace());
 
-        DecryptedFolderMetadata metadata = getDecryptedFolderMetadata(encryptedAncestor);
+        DecryptedFolderMetadata metadata = getDecryptedFolderMetadata(encryptedAncestor,
+                                                                      mLocalFolder,
+                                                                      getClient(),
+                                                                      mAccount,
+                                                                      mContext);
 
         // get current data about local contents of the folder to synchronize
         Map<String, OCFile> localFilesMap = prefillLocalFilesMap(metadata,
-                mStorageManager.getFolderContent(mLocalFolder, false));
+                                                                 mStorageManager.getFolderContent(mLocalFolder, false));
 
         // loop to update every child
         OCFile remoteFile;
@@ -468,7 +472,7 @@ public class RefreshFolderOperation extends RemoteOperation {
 
             // update file name for encrypted files
             if (metadata != null) {
-                updateFileNameForEncryptedFile(metadata, updatedFile);
+                updateFileNameForEncryptedFile(mStorageManager, metadata, updatedFile);
             }
 
             // we parse content, so either the folder itself or its direct parent (which we check) must be encrypted
@@ -481,7 +485,7 @@ public class RefreshFolderOperation extends RemoteOperation {
         // save updated contents in local database
         // update file name for encrypted files
         if (metadata != null) {
-            updateFileNameForEncryptedFile(metadata, mLocalFolder);
+            updateFileNameForEncryptedFile(mStorageManager, metadata, mLocalFolder);
         }
         mStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
 
@@ -489,23 +493,29 @@ public class RefreshFolderOperation extends RemoteOperation {
     }
 
     @Nullable
-    private DecryptedFolderMetadata getDecryptedFolderMetadata(boolean encryptedAncestor) {
+    public static DecryptedFolderMetadata getDecryptedFolderMetadata(boolean encryptedAncestor,
+                                                                     OCFile localFolder,
+                                                                     OwnCloudClient client,
+                                                                     Account account,
+                                                                     Context context) {
         DecryptedFolderMetadata metadata;
         if (encryptedAncestor && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
-            metadata = EncryptionUtils.downloadFolderMetadata(mLocalFolder, getClient(), mContext, mAccount);
+            metadata = EncryptionUtils.downloadFolderMetadata(localFolder, client, context, account);
         } else {
             metadata = null;
         }
         return metadata;
     }
 
-    private void updateFileNameForEncryptedFile(@NonNull DecryptedFolderMetadata metadata, OCFile updatedFile) {
+    public static void updateFileNameForEncryptedFile(FileDataStorageManager storageManager,
+                                                      @NonNull DecryptedFolderMetadata metadata,
+                                                      OCFile updatedFile) {
         try {
             String decryptedFileName = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted()
-                    .getFilename();
+                .getFilename();
             String mimetype = metadata.getFiles().get(updatedFile.getFileName()).getEncrypted().getMimetype();
 
-            OCFile parentFile = mStorageManager.getFileById(updatedFile.getParentId());
+            OCFile parentFile = storageManager.getFileById(updatedFile.getParentId());
             String decryptedRemotePath = parentFile.getDecryptedRemotePath() + decryptedFileName;
 
             if (updatedFile.isFolder()) {
@@ -535,7 +545,14 @@ public class RefreshFolderOperation extends RemoteOperation {
                     localFile.getModificationTimestampAtLastSyncForData()
             );
             if (localFile.isEncrypted()) {
-                updatedFile.setStoragePath(mLocalFolder.getStoragePath() + PATH_SEPARATOR + localFile.getFileName());
+                if (mLocalFolder.getStoragePath() == null) {
+                    updatedFile.setStoragePath(FileStorageUtils.getDefaultSavePathFor(mAccount.name, mLocalFolder) +
+                                                   localFile.getFileName());
+                } else {
+                    updatedFile.setStoragePath(mLocalFolder.getStoragePath() +
+                                                   PATH_SEPARATOR +
+                                                   localFile.getFileName());
+                }
             } else {
                 updatedFile.setStoragePath(localFile.getStoragePath());
             }
@@ -571,7 +588,7 @@ public class RefreshFolderOperation extends RemoteOperation {
     }
 
     @NonNull
-    private Map<String, OCFile> prefillLocalFilesMap(DecryptedFolderMetadata metadata, List<OCFile> localFiles) {
+    public static Map<String, OCFile> prefillLocalFilesMap(DecryptedFolderMetadata metadata, List<OCFile> localFiles) {
         Map<String, OCFile> localFilesMap = new HashMap<>(localFiles.size());
 
         for (OCFile file : localFiles) {

+ 53 - 18
src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -26,6 +26,7 @@ import android.text.TextUtils;
 import android.util.Log;
 
 import com.nextcloud.client.account.User;
+import com.owncloud.android.datamodel.DecryptedFolderMetadata;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
@@ -44,7 +45,6 @@ import com.owncloud.android.utils.MimeTypeUtil;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
@@ -246,13 +246,14 @@ public class SynchronizeFolderOperation extends SyncOperation {
      * @param folderAndFiles Remote folder and children files in Folder
      */
     private void synchronizeData(List<Object> folderAndFiles) throws OperationCancelledException {
+
+
         // parse data from remote folder
         OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) folderAndFiles.get(0));
         remoteFolder.setParentId(mLocalFolder.getParentId());
         remoteFolder.setFileId(mLocalFolder.getFileId());
 
-        Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath()
-                + " changed - starting update of local data ");
+        Log_OC.d(TAG, "Remote folder " + mLocalFolder.getRemotePath() + " changed - starting update of local data ");
 
         mFilesForDirectDownload.clear();
         mFilesToSyncContents.clear();
@@ -262,38 +263,66 @@ public class SynchronizeFolderOperation extends SyncOperation {
         }
 
         FileDataStorageManager storageManager = getStorageManager();
-        List<OCFile> updatedFiles = new ArrayList<>(folderAndFiles.size() - 1);
+
+        // if local folder is encrypted, download fresh metadata
+        boolean encryptedAncestor = FileStorageUtils.checkEncryptionStatus(remoteFolder, storageManager);
+        mLocalFolder.setEncrypted(encryptedAncestor);
+
+        // update permission
+        mLocalFolder.setPermissions(remoteFolder.getPermissions());
+
+        // update richWorkspace
+        mLocalFolder.setRichWorkspace(remoteFolder.getRichWorkspace());
+
+        DecryptedFolderMetadata metadata = RefreshFolderOperation.getDecryptedFolderMetadata(encryptedAncestor,
+                                                                                             mLocalFolder,
+                                                                                             getClient(),
+                                                                                             user.toPlatformAccount(),
+                                                                                             mContext);
 
         // get current data about local contents of the folder to synchronize
-        List<OCFile> localFiles = storageManager.getFolderContent(mLocalFolder, false);
-        Map<String, OCFile> localFilesMap = new HashMap<>(localFiles.size());
-        for (OCFile file : localFiles) {
-            localFilesMap.put(file.getRemotePath(), file);
-        }
+        Map<String, OCFile> localFilesMap =
+            RefreshFolderOperation.prefillLocalFilesMap(metadata,
+                                                        storageManager.getFolderContent(mLocalFolder, false));
 
         // loop to synchronize every child
+        List<OCFile> updatedFiles = new ArrayList<>(folderAndFiles.size() - 1);
         OCFile remoteFile;
         OCFile localFile;
         OCFile updatedFile;
-        RemoteFile r;
-        for (int i=1; i<folderAndFiles.size(); i++) {
+        RemoteFile remote;
+
+        for (int i = 1; i < folderAndFiles.size(); i++) {
             /// new OCFile instance with the data from the server
-            r = (RemoteFile) folderAndFiles.get(i);
-            remoteFile = FileStorageUtils.fillOCFile(r);
+            remote = (RemoteFile) folderAndFiles.get(i);
+            remoteFile = FileStorageUtils.fillOCFile(remote);
+
+            /// new OCFile instance to merge fresh data from server with local state
+            updatedFile = FileStorageUtils.fillOCFile(remote);
+            updatedFile.setParentId(mLocalFolder.getFileId());
 
             /// retrieve local data for the read file
-            //  localFile = mStorageManager.getFileByPath(remoteFile.getRemotePath());
             localFile = localFilesMap.remove(remoteFile.getRemotePath());
 
-            /// new OCFile instance to merge fresh data from server with local state
-            updatedFile = FileStorageUtils.fillOCFile(r);
-            updatedFile.setParentId(mLocalFolder.getFileId());
+            // TODO better implementation is needed
+            if (localFile == null) {
+                localFile = storageManager.getFileByPath(updatedFile.getRemotePath());
+            }
 
             /// add to updatedFile data about LOCAL STATE (not existing in server)
             updateLocalStateData(remoteFile, localFile, updatedFile);
 
             /// check and fix, if needed, local storage path
-            searchForLocalFileInDefaultPath(updatedFile);
+            FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, user.toPlatformAccount());
+
+            // update file name for encrypted files
+            if (metadata != null) {
+                RefreshFolderOperation.updateFileNameForEncryptedFile(storageManager, metadata, updatedFile);
+            }
+
+            // we parse content, so either the folder itself or its direct parent (which we check) must be encrypted
+            boolean encrypted = updatedFile.isEncrypted() || mLocalFolder.isEncrypted();
+            updatedFile.setEncrypted(encrypted);
 
             /// classify file to sync/download contents later
             classifyFileForLaterSyncOrDownload(remoteFile, localFile);
@@ -301,8 +330,14 @@ public class SynchronizeFolderOperation extends SyncOperation {
             updatedFiles.add(updatedFile);
         }
 
+        if (metadata != null) {
+            RefreshFolderOperation.updateFileNameForEncryptedFile(storageManager, metadata, mLocalFolder);
+        }
+
         // save updated contents in local database
         storageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());
+        mLocalFolder.setLastSyncDateForData(System.currentTimeMillis());
+        storageManager.saveFile(mLocalFolder);
     }
 
     private void updateLocalStateData(OCFile remoteFile, OCFile localFile, OCFile updatedFile) {