diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index e57f135e1d21e537b17ac9ad9eb54073bf1e84f4..b80f40662a5907607c1b52f18a304c1a4ec40734 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -47,11 +47,13 @@ import foundation.e.drive.receivers.DebugCmdReceiver; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.DavClientProvider; +import foundation.e.drive.utils.FileDiffUtils.Action; import foundation.e.drive.utils.ServiceExceptionHandler; import foundation.e.drive.utils.SynchronizationServiceConnection; import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; +import static foundation.e.drive.utils.FileDiffUtils.getActionForFileDiff; import androidx.annotation.Nullable; @@ -380,41 +382,30 @@ public class ObserverService extends Service implements OnRemoteOperationListene continue; } - Log.v(TAG, "syncedFileState.getRemotePath() :"+syncedFileState.getRemotePath() ); - - //If syncedFileState match the remote file if (remoteFilePath.equals(syncedFileState.getRemotePath())) { Log.d(TAG, "correspondant found for "+remoteFilePath ); correspondant_found = true; - if (syncedFileState.isLastEtagStored() //there is an etag stored - && (!remoteFile.getEtag().equals(syncedFileState.getLastETAG()) //If etag has changed - || syncedFileState.getLocalLastModified() == 0L)) { //File hasn't been downloaded - - Log.v(TAG, "etag and localLastModified are valids for "+remoteFilePath ); + final Action action = getActionForFileDiff(remoteFile, syncedFileState); + if (action == Action.Download) { - //compare size with local file - if (remoteFile.getLength() == new File(syncedFileState.getLocalPath()).length()) { //length is 0 is file doesn't exist - Log.v(TAG, "file size are the same for local and remote, just update syncedFileState etag"); + Log.i(TAG, "Add download operation for file " + syncedFileState.getId()); + this.syncRequests.put(syncedFileState.getId(), new DownloadRequest(remoteFile, syncedFileState)); - syncedFileState.setLastETAG(remoteFile.getEtag()); - int affectedRows = DbHelper.manageSyncedFileStateDB(syncedFileState, "UPDATE", this); - Log.v(TAG, affectedRows + " syncedFileState.s row in DB has been updated."); - } else { - Log.i(TAG, "Add download operation for file "+syncedFileState.getId()); + } else if (action == Action.updateDB) { - this.syncRequests.put(syncedFileState.getId(), new DownloadRequest(remoteFile, syncedFileState)); - } + syncedFileState.setLastETAG(remoteFile.getEtag()); + final int affectedRows = DbHelper.manageSyncedFileStateDB(syncedFileState, "UPDATE", this); + if (affectedRows == 0) Log.e(TAG, "Error while updating eTag in DB for: " + remoteFilePath); } - syncedFileListIterator.remove(); //we can delete syncedFile from list because its correspondant has already been found and handled + syncedFileListIterator.remove(); break; } } - if ( correspondant_found )continue; + if (correspondant_found) continue; - //If we get here, RemoteFile is a new file to download - Log.v(TAG, "SyncedFileState corresponding to remoteFile not found."); + Log.v(TAG, remoteFilePath + "is a new file"); //Extract parent folder's path of remote file final String parentOfKnownPath = remoteFilePath.substring(0, remoteFilePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); diff --git a/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java b/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..1edaa713f3434537216ac0028ef454233348f44b --- /dev/null +++ b/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright © ECORP SAS 2022. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ + +package foundation.e.drive.utils; + +import com.owncloud.android.lib.resources.files.model.RemoteFile; + +import java.io.File; + +import foundation.e.drive.models.SyncedFileState; + +/** + * This class encapsulate code to compare syncedFile & Remote file + * but also RemoteFolder and SyncedFolder + * @author vincent Bourgmayer + */ +public class FileDiffUtils { + + public enum Action { + Upload, + Download, + Remove, + skip, + updateDB + } + + + /** + * Define what to do of RemoteFile for which we know the Database equivalent + * @param remoteFile RemoteFile + * @param fileState SyncedFileState instance + * @return Action from Enum + */ + public static Action getActionForFileDiff(RemoteFile remoteFile, SyncedFileState fileState) { + if (hasAlreadyBeenDownloaded(fileState) && !hasEtagChanged(remoteFile, fileState)) { + return Action.skip; + } + + final File localFile = new File(fileState.getLocalPath()); + + if (isRemoteSizeSameAsLocalSize(remoteFile, localFile)) { + return Action.updateDB; + } + + return Action.Download; + } + + /** + * Compare RemoteFile's eTag with the one stored in Database + * @param file RemoteFile + * @param fileState last store file's state + * @return true if ETag + */ + private static boolean hasEtagChanged(RemoteFile file, SyncedFileState fileState) { + //if SyncedFileState has no Etag then it hasn't been uploaded and so must not exist on server + return fileState.isLastEtagStored() && !file.getEtag().equals(fileState.getLastETAG()); + } + + /** + * Indicate if the file has already been downloaded + * or detected on the device + * @param fileState SyncedFileState containing data from Database + * @return true if localLastModified store in Database == 0 + */ + private static boolean hasAlreadyBeenDownloaded(SyncedFileState fileState) { + return fileState.getLocalLastModified() == 0l; + } + + /** + * + * @param remoteFile RemoteFile instance + * @param localFile File instance + * @return true if remote file size is same as local file size + */ + private static boolean isRemoteSizeSameAsLocalSize(RemoteFile remoteFile, File localFile) { + // if local file doesn't exist its size will be 0 + return remoteFile.getLength() == localFile.length(); + } +}