From 9f260ce213f909da0ca7da49812a0ebd1d7c838b Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 11:44:16 +0200 Subject: [PATCH 1/6] update SyncRequest class to allow to pass request for directory --- .../e/drive/models/SyncRequest.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/models/SyncRequest.java b/app/src/main/java/foundation/e/drive/models/SyncRequest.java index e2412cdf..adab0433 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncRequest.java +++ b/app/src/main/java/foundation/e/drive/models/SyncRequest.java @@ -10,14 +10,33 @@ package foundation.e.drive.models; import androidx.annotation.Nullable; public class SyncRequest { - public enum Type { UPLOAD, DOWNLOAD, REMOTE_DELETE}; + public enum Type { UPLOAD, DOWNLOAD, REMOTE_DELETE, MKCOL}; private final SyncedFileState syncedFileState; + private final SyncedFolder syncedFolder; + private final Type operationType; + /** + * Create a syncRequest for a file which isn't a directory + * @param syncedFileState + * @param operationType Shouldn't be MKCol + */ public SyncRequest(SyncedFileState syncedFileState, Type operationType) { this.syncedFileState = syncedFileState; + this.syncedFolder = null; + this.operationType = operationType; + } + + /** + * Create a syncRequest for a directory + * @param syncedFolder + * @param operationType should be MKCol or REMOTE_DELETE + */ + public SyncRequest(SyncedFolder syncedFolder, Type operationType){ + this.syncedFileState = null; + this.syncedFolder = syncedFolder; this.operationType = operationType; } @@ -25,10 +44,19 @@ public class SyncRequest { return operationType; } + /** + * @return null if instance is for a directory + */ public SyncedFileState getSyncedFileState() { return syncedFileState; } + /** + * @return null if instance is for a file which isn't a directory + */ + public SyncedFolder getSyncedFolder() { + return syncedFolder; + } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SyncRequest) { -- GitLab From da884131683ef9f96959fafa62674e89378929d6 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 11:50:38 +0200 Subject: [PATCH 2/6] FileEventListener now handle directory creation correctly --- .../FileObservers/FileEventListener.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java index a4a0b634..5903b9c7 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -9,6 +9,7 @@ package foundation.e.drive.FileObservers; +import static foundation.e.drive.models.SyncRequest.Type.MKCOL; import static foundation.e.drive.models.SyncRequest.Type.UPLOAD; import android.content.Context; @@ -49,15 +50,12 @@ public class FileEventListener { } else { handleFileDelete(file); } - } else if (event == FileObserver.CLOSE_WRITE) { - - if (file.isDirectory()) { - handleDirectoryCloseWrite(file); - } else { - handleFileCloseWrite(file); - } + } else if (event == FileObserver.CLOSE_WRITE && !file.isDirectory()) { + handleFileCloseWrite(file); } else if (event == FileObserver.MOVE_SELF){ Log.d(TAG, file.getAbsolutePath() + " has been moved. Not handled yet"); + } else if( event == FileObserver.CREATE && file.isDirectory()){ + handleDirectoryCreate(file); } } @@ -71,20 +69,25 @@ public class FileEventListener { } } - private void handleDirectoryCloseWrite(File directory) { - final String fileLocalPath = CommonUtils.getLocalPath(directory); - Log.d(TAG, "handleDirectoryCloseWrite(" + fileLocalPath + ")"); - SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); - if (folder == null) { //it's a directory creation - final String parentPath = CommonUtils.getLocalPath(directory.getParentFile()); - SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); - if (parentFolder != null) { //if parent is in the DB - folder = new SyncedFolder(parentFolder, directory.getName() + FileUtils.PATH_SEPARATOR, directory.lastModified(), ""); - DbHelper.insertSyncedFolder(folder, appContext); - } - } else { //It's a directory update - folder.setLastModified(directory.lastModified()); - DbHelper.updateSyncedFolder(folder, appContext); + private void handleDirectoryCreate(File directory) { + final String directoryLocalPath = CommonUtils.getLocalPath(directory); + Log.d(TAG, "handleDirectoryCreate(" + directoryLocalPath + ")"); + + final String parentLocalPath = CommonUtils.getLocalPath(directory.getParentFile()); + final SyncedFolder parentSyncedFolder = DbHelper.getSyncedFolderByLocalPath(parentLocalPath, appContext); + if (parentSyncedFolder == null) { //this directory shouldn't be handled + Log.d(TAG, directory.getName()+" isn't a folder to synchronize"); + return; + } + + final SyncedFolder syncedFolder = new SyncedFolder(parentSyncedFolder, directory.getName() + FileUtils.PATH_SEPARATOR, directory.lastModified(), ""); + final long storedId = DbHelper.insertSyncedFolder(syncedFolder, appContext); + if(storedId > 0) { + syncedFolder.setId((int) storedId); + SyncRequest request = new SyncRequest(syncedFolder, MKCOL); + sendSyncRequestToSynchronizationService(request); + } else{ + Log.w(TAG, "Can't store new SyncedFolder"); } } -- GitLab From 0b0ac3f37c0af74f556474521bc8c0e38536c460 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 11:56:17 +0200 Subject: [PATCH 3/6] update ObserverService to handle new folder creation - rewite two tests with same result into a single one (optimization) - Change HashMap syncRequests into HashMap. Integer which was syncedFileStateId is now File's path which allow to pass SyncedFolder also. But I need to check if using hashMap is still required of if a simple ArrayList could be enough... --- .../e/drive/services/ObserverService.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) 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 567dd17b..eb84fbb3 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -67,7 +67,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene private boolean isWorking = false; private int initialFolderCounter; private Account mAccount; - private HashMap syncRequests; //integer is SyncedFileState id; Parcelable is the operation + private HashMap syncRequests; //String is file path ; Parcelable is the syncRequest private SynchronizationServiceConnection synchronizationServiceConnection = new SynchronizationServiceConnection(); @@ -393,7 +393,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene } else { Log.i(TAG, "Add download operation for file "+syncedFileState.getId()); - this.syncRequests.put(syncedFileState.getId(), new DownloadRequest(remoteFile, syncedFileState)); + this.syncRequests.put(remoteFilePath, new DownloadRequest(remoteFile, syncedFileState)); } } syncedFileListIterator.remove(); //we can delete syncedFile from list because its correspondant has already been found and handled @@ -430,8 +430,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene if (storedId > 0) { newRemoteFile.setId(storedId); Log.i(TAG, "Add download operation for new file "+storedId); - //Create Download operation and add it into Bundle - this.syncRequests.put(storedId, new DownloadRequest(remoteFile, newRemoteFile)); + this.syncRequests.put(remoteFilePath, new DownloadRequest(remoteFile, newRemoteFile)); } else { Log.w(TAG, "Can't save new remote File in DB. Ignore file."); @@ -550,14 +549,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene SyncedFolder syncedFolder = iterator.next(); Log.d(TAG, "SyncedFolder :"+syncedFolder.getLibelle()+", "+syncedFolder.getLocalFolder()+", "+syncedFolder.getLastModified()+", "+syncedFolder.isScanLocal()+", "+syncedFolder.getId() ); - //Check it's not a hidden file - if (syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()).startsWith(".")){ - iterator.remove(); - continue; - } - - //Check it can be scann from local - if (!syncedFolder.isScanLocal()){ + final boolean isHiddenFile = syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()).startsWith("."); + if (isHiddenFile || !syncedFolder.isScanLocal()){ iterator.remove(); continue; } @@ -570,6 +563,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene if (syncedFolder_id > 0) { Log.v(TAG, "Folder has been registered in DB"); syncedFolder.setId(syncedFolder_id); + SyncRequest request = new SyncRequest(syncedFolder, SyncRequest.Type.MKCOL); + this.syncRequests.put(syncedFolder.getLocalFolder(), request); } else { Log.w(TAG, "syncedFolder " + syncedFolder.getLocalFolder() + " remove iterator because it hasn't been registered in DB or already stored"); iterator.remove(); @@ -677,7 +672,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene //If no etag is stored in sfs, the file hasn't been sync up to server. then do upload if ( syncedFileState.getLocalLastModified() < localFile.lastModified() || !syncedFileState.isLastEtagStored()){ Log.i(TAG, "Add upload request for file "+syncedFileState.getId()); - this.syncRequests.put(syncedFileState.getId(), new SyncRequest(syncedFileState, SyncRequest.Type.UPLOAD)); + this.syncRequests.put(filePath, new SyncRequest(syncedFileState, SyncRequest.Type.UPLOAD)); } // No need to reloop on it. syncedFileListIterator.remove(); @@ -710,7 +705,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene newSyncedFileState.setId( storedId ); Log.i(TAG, "Add upload operation for new file "+storedId); - this.syncRequests.put(storedId, new SyncRequest(newSyncedFileState, SyncRequest.Type.UPLOAD)); + this.syncRequests.put(filePath, new SyncRequest(newSyncedFileState, SyncRequest.Type.UPLOAD)); } else { Log.w(TAG, "The new file to synced cannot be store in DB. Ignore it"); } @@ -738,7 +733,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.w(TAG, "The file still exist. There is a problem!"); } else { Log.i(TAG, "Add remote remove request for file "+fileState.getId()); - this.syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.REMOTE_DELETE)); + this.syncRequests.put(fileState.getLocalPath(), new SyncRequest(fileState, SyncRequest.Type.REMOTE_DELETE)); } } } -- GitLab From ba304ca3496d941dfeb236105eb7650dbd5fdbcf Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 14:52:27 +0200 Subject: [PATCH 4/6] SynchonrizationService execute mkcol request --- .../e/drive/services/SynchronizationService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java index 72cee50c..720ae5c1 100644 --- a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java +++ b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java @@ -30,6 +30,7 @@ import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -42,6 +43,7 @@ import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.DownloadRequest; import foundation.e.drive.models.SyncRequest; import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.operations.DownloadFileOperation; import foundation.e.drive.operations.RemoveFileOperation; import foundation.e.drive.operations.UploadFileOperation; @@ -152,6 +154,12 @@ public class SynchronizationService extends Service implements OnRemoteOperation DbHelper.manageSyncedFileStateDB( ( ( RemoveFileOperation ) callerOperation ).getSyncedFileState(), "DELETE", this); } + } else if (callerOperation instanceof CreateFolderRemoteOperation) { + if (result.isSuccess()) { + Log.d(TAG, "CreateRemoteFolderOperation succeed"); + } else { + Log.w(TAG, "CreateRemoteFolderOperation failed: "+result.getCode().name()); + } } else { String operationClassName = callerOperation.getClass().getSimpleName(); final ArrayList callerOperationResultData = result.getData(); @@ -221,6 +229,9 @@ public class SynchronizationService extends Service implements OnRemoteOperation final DownloadRequest downloadRequest = (DownloadRequest) request; operation = new DownloadFileOperation(downloadRequest.getRemoteFile(), downloadRequest.getSyncedFileState(), getApplicationContext()); break; + case MKCOL: + final SyncedFolder syncedFolder = request.getSyncedFolder(); + operation = new CreateFolderRemoteOperation(syncedFolder.getRemoteFolder(), true); case REMOTE_DELETE: default: operation = null; -- GitLab From a9415bfb3da8fca813f335925b1f1174f3d1abc7 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 15:11:46 +0200 Subject: [PATCH 5/6] fix potential NPE - in SyncRequest.equals(...) - in SynchronizationService.startWorker(...) - in SynchronizationService.createRemoteOperation(...) - in FileEventListener.sendSyncRequestToSynchronizationService(...) --- .../foundation/e/drive/FileObservers/FileEventListener.java | 3 ++- .../main/java/foundation/e/drive/models/SyncRequest.java | 6 +++++- .../foundation/e/drive/services/SynchronizationService.java | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java index 5903b9c7..4f3b06cf 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -60,7 +60,8 @@ public class FileEventListener { } private void sendSyncRequestToSynchronizationService(SyncRequest request) { - Log.d(TAG, "Sending a SyncRequest for " + request.getSyncedFileState().getName()); + final String fileName = (request.getSyncedFileState() != null) ? request.getSyncedFileState().getName() : request.getSyncedFolder().getLocalFolder(); + Log.d(TAG, "Sending a SyncRequest for " + fileName); if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); serviceConnection.getSynchronizationService().startSynchronization(); diff --git a/app/src/main/java/foundation/e/drive/models/SyncRequest.java b/app/src/main/java/foundation/e/drive/models/SyncRequest.java index adab0433..5fd7d096 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncRequest.java +++ b/app/src/main/java/foundation/e/drive/models/SyncRequest.java @@ -57,11 +57,15 @@ public class SyncRequest { public SyncedFolder getSyncedFolder() { return syncedFolder; } + @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SyncRequest) { - return (syncedFileState.getId() == ((SyncRequest) obj).syncedFileState.getId() ); + return (syncedFileState.getId() == ((SyncRequest) obj).syncedFileState.getId()) + || (syncedFolder.getId() == ((SyncRequest) obj).getSyncedFolder().getId()); } return super.equals(obj); } + + } diff --git a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java index 720ae5c1..62279cc7 100644 --- a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java +++ b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java @@ -130,7 +130,9 @@ public class SynchronizationService extends Service implements OnRemoteOperation if (operation != null) { Log.v(TAG, " an operation has been poll from queue"); - if (CommonUtils.isThisSyncAllowed(account, request.getSyncedFileState().isMediaType())) { + final SyncedFolder sf = request.getSyncedFolder(); + final boolean isAllowedSync = (sf == null) ? request.getSyncedFileState().isMediaType() : sf.isMediaType(); + if (CommonUtils.isThisSyncAllowed(account, isAllowedSync)) { CommonUtils.createNotificationChannel(this); startedOperations.put(operation, threadIndex); threadPool[threadIndex] = operation.execute(client, this, handler); @@ -232,6 +234,7 @@ public class SynchronizationService extends Service implements OnRemoteOperation case MKCOL: final SyncedFolder syncedFolder = request.getSyncedFolder(); operation = new CreateFolderRemoteOperation(syncedFolder.getRemoteFolder(), true); + break; case REMOTE_DELETE: default: operation = null; -- GitLab From 69275821934bc36a55e941d60cc9b463407b793c Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 4 May 2022 16:07:43 +0200 Subject: [PATCH 6/6] Centralize method of SyncedFileState & SyncedFolder - Create a SyncableContentState interface to declare common methods - Make SyncedFileState to implement SyncableContentState. It required few adaptations: method names (getLastETAG => getEtag), parameter type: id become long to fit with DB stuff - Make SyncedFolder to implement SyncableContentState. It required few adaptations: method names (getLastEtag => getEtag, getLastModified => getLocalLastModified, ...) & parameter type for id become long to fit with DB stuff. Also add a new method: int getScannable() that return value similar to SyncedFileState from boolean. - SyncRequest now use SyncableContentState instead of both SyncedFileState & SyncedFolder. It avoids to have to handle null values and use less memory. - Update SynchronizationService to handle SyncableContentState from SyncRequest. - Update ObserverService to use SyncableContentState's methods when possible - Update CommonUtils.createDataFromSyncedFolder() to fit with long type instead of int for id - Update FileEventListener to use SyncableContentState.getLocalFile from SyncRequest further optimization should be done in later MR --- .../FileObservers/FileEventListener.java | 6 +- .../FileObservers/RecursiveFileObserver.java | 4 +- .../e/drive/database/SyncedFileStateDAO.java | 4 +- .../e/drive/database/SyncedFolderDAO.java | 12 +-- .../e/drive/models/SyncRequest.java | 38 ++-------- .../e/drive/models/SyncableContentState.java | 56 ++++++++++++++ .../e/drive/models/SyncedFileState.java | 23 +++--- .../e/drive/models/SyncedFolder.java | 75 ++++++++++--------- .../operations/DownloadFileOperation.java | 8 +- .../operations/ListFileRemoteOperation.java | 18 ++--- .../drive/operations/UploadFileOperation.java | 4 +- .../e/drive/services/ObserverService.java | 39 +++++----- .../services/SynchronizationService.java | 19 ++--- .../foundation/e/drive/utils/CommonUtils.java | 11 ++- .../drive/work/CreateRemoteFolderWorker.java | 12 +-- .../operations/UploadFileOperationTest.java | 6 +- 16 files changed, 180 insertions(+), 155 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/models/SyncableContentState.java diff --git a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java index 4f3b06cf..86f3b317 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -60,8 +60,8 @@ public class FileEventListener { } private void sendSyncRequestToSynchronizationService(SyncRequest request) { - final String fileName = (request.getSyncedFileState() != null) ? request.getSyncedFileState().getName() : request.getSyncedFolder().getLocalFolder(); - Log.d(TAG, "Sending a SyncRequest for " + fileName); + final String filePath = request.getSyncableContentState().getLocalPath(); + Log.d(TAG, "Sending a SyncRequest for " + filePath); if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); serviceConnection.getSynchronizationService().startSynchronization(); @@ -132,7 +132,7 @@ public class FileEventListener { if (parentFolder.isScanLocal()) scannableValue += 2; } - final String remotePath = parentFolder.getRemoteFolder()+file.getName(); + final String remotePath = parentFolder.getRemotePath()+file.getName(); fileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); int storedId = DbHelper.manageSyncedFileStateDB(fileState, "INSERT", appContext); if (storedId > 0) { diff --git a/app/src/main/java/foundation/e/drive/FileObservers/RecursiveFileObserver.java b/app/src/main/java/foundation/e/drive/FileObservers/RecursiveFileObserver.java index 1e4a9874..c6dcd91f 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/RecursiveFileObserver.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/RecursiveFileObserver.java @@ -77,8 +77,8 @@ public class RecursiveFileObserver extends FileObserver { List mSyncedFolders = DbHelper.getAllSyncedFolders(applicationContext); if (!mSyncedFolders.isEmpty()){ for (SyncedFolder syncedFolder:mSyncedFolders){ - stack.push(syncedFolder.getLocalFolder()); - stack.push(syncedFolder.getRemoteFolder()); + stack.push(syncedFolder.getLocalPath()); + stack.push(syncedFolder.getRemotePath()); } watching = true; } diff --git a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java index 9864b9de..bc5e3c4b 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java @@ -72,7 +72,7 @@ class SyncedFileStateDAO { values.put( FILE_NAME, syncedFileState.getName() ); values.put( LOCAL_PATH, syncedFileState.getLocalPath() ); values.put( REMOTE_PATH, syncedFileState.getRemotePath() ); - values.put( LAST_ETAG, syncedFileState.getLastETAG() ); + values.put( LAST_ETAG, syncedFileState.getEtag() ); values.put( LOCAL_LAST_MODIFIED, syncedFileState.getLocalLastModified() ); values.put( SYNCEDFOLDER_ID, syncedFileState.getSyncedFolderId() ); values.put( IS_MEDIA_TYPE, syncedFileState.isMediaType() ? 1 : 0 ); @@ -212,7 +212,7 @@ class SyncedFileStateDAO { */ private SyncedFileState cursorToSyncedFileState(Cursor cursor) { return new SyncedFileState( - cursor.getInt(0), //id + cursor.getLong(0), //id cursor.getString(1 ),//file name cursor.getString(2 ),//local path cursor.getString(3 ),//remote path diff --git a/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java b/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java index c70be5e5..b6c6bdd9 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java @@ -79,10 +79,10 @@ class SyncedFolderDAO { private ContentValues toContentValues(SyncedFolder syncedFolder){ ContentValues values = new ContentValues(); values.put( CATEGORIE_LABEL, syncedFolder.getLibelle() ); - values.put( LOCAL_PATH, syncedFolder.getLocalFolder() ); - values.put( REMOTE_PATH, syncedFolder.getRemoteFolder() ); - values.put( LAST_ETAG, syncedFolder.getLastEtag() ); - values.put( LOCAL_LAST_MODIFIED, syncedFolder.getLastModified() ); + values.put( LOCAL_PATH, syncedFolder.getLocalPath() ); + values.put( REMOTE_PATH, syncedFolder.getRemotePath() ); + values.put( LAST_ETAG, syncedFolder.getEtag() ); + values.put( LOCAL_LAST_MODIFIED, syncedFolder.getLocalLastModified() ); values.put( SCANLOCAL, syncedFolder.isScanLocal() ? 1 : 0 ); values.put( SCANREMOTE, syncedFolder.isScanRemote() ? 1 : 0 ); values.put( ENABLED, syncedFolder.isEnabled() ? 1 : 0 ); @@ -202,8 +202,8 @@ class SyncedFolderDAO { ( cursor.getInt(9) == 1 ) //is Media Type )//active .setId(cursor.getInt(0) ) - .setLastEtag(cursor.getString( 4 ) ) - .setLastModified(cursor.getLong( 5 ) ); + .setEtag(cursor.getString( 4 ) ) + .setLocalLastModified(cursor.getLong( 5 ) ); } } diff --git a/app/src/main/java/foundation/e/drive/models/SyncRequest.java b/app/src/main/java/foundation/e/drive/models/SyncRequest.java index 5fd7d096..b8ec4f8d 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncRequest.java +++ b/app/src/main/java/foundation/e/drive/models/SyncRequest.java @@ -12,31 +12,17 @@ import androidx.annotation.Nullable; public class SyncRequest { public enum Type { UPLOAD, DOWNLOAD, REMOTE_DELETE, MKCOL}; - private final SyncedFileState syncedFileState; - - private final SyncedFolder syncedFolder; + private final SyncableContentState syncableContentState; private final Type operationType; /** * Create a syncRequest for a file which isn't a directory - * @param syncedFileState + * @param syncableContentState * @param operationType Shouldn't be MKCol */ - public SyncRequest(SyncedFileState syncedFileState, Type operationType) { - this.syncedFileState = syncedFileState; - this.syncedFolder = null; - this.operationType = operationType; - } - - /** - * Create a syncRequest for a directory - * @param syncedFolder - * @param operationType should be MKCol or REMOTE_DELETE - */ - public SyncRequest(SyncedFolder syncedFolder, Type operationType){ - this.syncedFileState = null; - this.syncedFolder = syncedFolder; + public SyncRequest(SyncableContentState syncableContentState, Type operationType) { + this.syncableContentState = syncableContentState; this.operationType = operationType; } @@ -47,25 +33,15 @@ public class SyncRequest { /** * @return null if instance is for a directory */ - public SyncedFileState getSyncedFileState() { - return syncedFileState; - } - - /** - * @return null if instance is for a file which isn't a directory - */ - public SyncedFolder getSyncedFolder() { - return syncedFolder; + public SyncableContentState getSyncableContentState() { + return syncableContentState; } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof SyncRequest) { - return (syncedFileState.getId() == ((SyncRequest) obj).syncedFileState.getId()) - || (syncedFolder.getId() == ((SyncRequest) obj).getSyncedFolder().getId()); + return (syncableContentState.getId() == ((SyncRequest) obj).syncableContentState.getId()); } return super.equals(obj); } - - } diff --git a/app/src/main/java/foundation/e/drive/models/SyncableContentState.java b/app/src/main/java/foundation/e/drive/models/SyncableContentState.java new file mode 100644 index 00000000..70b097fd --- /dev/null +++ b/app/src/main/java/foundation/e/drive/models/SyncableContentState.java @@ -0,0 +1,56 @@ +package foundation.e.drive.models; + +/** + * This interface describe data that can be gotten from a given state of synchronizable content + * A state correspond to a time frame, or time instant. + */ +public interface SyncableContentState { + public static final int NOT_SCANNABLE=0; + public static final int ECLOUD_SCANNABLE=1; + public static final int DEVICE_SCANNABLE=2; + public static final int ALL_SCANNABLE=3; + + /** + * Get Id of content from Database + * @return -1 if not present in DB + */ + public long getId(); + + /** + * get content's path on device + * @return String + */ + public String getLocalPath(); + + /** + * get content's path on cloud + * @return String + */ + public String getRemotePath(); + + /** + * Get last known etag of the file + * @return + */ + public String getEtag(); + + /** + * Get last known 'lastModified' timestamp of the content + * from the device point of view + * @return + */ + public long getLocalLastModified(); + + /** + * Indicate if the SyncableContent (at the currentState) is a media + * (aka photos, videos, documents, etc.) or a settings (aka app & system settings, apk list, etc.) + * @return true if a media type. False if a settings type + */ + public boolean isMediaType(); + + /** + * Indicate if the content (at the given state) can be scanned for update + * @return 0: not scannable. 1: on cloud scannable. 2: on device scannable. 3: fully scannable + */ + public int getScannable(); +} diff --git a/app/src/main/java/foundation/e/drive/models/SyncedFileState.java b/app/src/main/java/foundation/e/drive/models/SyncedFileState.java index f3b842b3..fc2a73ce 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncedFileState.java +++ b/app/src/main/java/foundation/e/drive/models/SyncedFileState.java @@ -15,15 +15,10 @@ import android.os.Parcelable; * @author Vincent Bourgmayer * Describe a file state which will be Synchronized (= Synced) or which has already been synced one times */ - -public class SyncedFileState implements Parcelable { - public static final int NOT_SCANNABLE=0; - public static final int ECLOUD_SCANNABLE=1; - public static final int DEVICE_SCANNABLE=2; - public static final int ALL_SCANNABLE=3; +public class SyncedFileState implements Parcelable, SyncableContentState { protected SyncedFileState(){}; //@ToRemove. Test Only. It's to allow to make a mock SyncedFileState Class in test. - private int id; + private long id; private String name; //name of the file private String localPath; //Path on the device file system private String remotePath; //path on the server @@ -43,7 +38,7 @@ public class SyncedFileState implements Parcelable { * @param lastModified Last modified time where local file has changed * @param isMediaType true if its sync as medias or as device/app' settings. */ - public SyncedFileState(int id, String name, String localPath, String remotePath, String etag, long lastModified, long syncedFolderId, boolean isMediaType, int scannable){ + public SyncedFileState(long id, String name, String localPath, String remotePath, String etag, long lastModified, long syncedFolderId, boolean isMediaType, int scannable){ this.id = id; this.name = name; this.localPath = localPath; @@ -56,7 +51,7 @@ public class SyncedFileState implements Parcelable { } protected SyncedFileState(Parcel in) { - id = in.readInt(); + id = in.readLong(); name = in.readString(); localPath = in.readString(); remotePath = in.readString(); @@ -69,7 +64,7 @@ public class SyncedFileState implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(id); + dest.writeLong(id); dest.writeString(name); dest.writeString(localPath); dest.writeString(remotePath); @@ -92,11 +87,11 @@ public class SyncedFileState implements Parcelable { } }; - public int getId() { + public long getId() { return id; } - public SyncedFileState setId(int id) { + public SyncedFileState setId(long id) { this.id = id; return this; } @@ -113,11 +108,11 @@ public class SyncedFileState implements Parcelable { return remotePath; } - public String getLastETAG() { + public String getEtag() { return lastETAG; } - public SyncedFileState setLastETAG(String lastETAG) { + public SyncedFileState setEtag(String lastETAG) { this.lastETAG = lastETAG; return this; } diff --git a/app/src/main/java/foundation/e/drive/models/SyncedFolder.java b/app/src/main/java/foundation/e/drive/models/SyncedFolder.java index c737032e..9b1710aa 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncedFolder.java +++ b/app/src/main/java/foundation/e/drive/models/SyncedFolder.java @@ -17,11 +17,11 @@ import android.os.Parcelable; * It stores data about remote and local real folder. */ -public class SyncedFolder implements Parcelable { - private int id; +public class SyncedFolder implements Parcelable, SyncableContentState { + private long id; private String libelle; - private String localFolder; - private String remoteFolder; + private String localPath; + private String remotePath; private String lastEtag; private long lastModified =0L; private boolean scanLocal; @@ -33,34 +33,34 @@ public class SyncedFolder implements Parcelable { /** * Constructor for SyncedFolder object. Enabled, scanRemote and scanLocal are true by default. * @param libelle libelle (=categorie) of Synced folder - * @param localFolder path of the folder on device - * @param remoteFolder path of the folder on server + * @param localPath path of the folder on device + * @param remotePath path of the folder on server * @param isMediaType If this folder is a media's folder (true) or a settings's folder (false) */ - public SyncedFolder(String libelle, String localFolder, String remoteFolder, boolean isMediaType){ + public SyncedFolder(String libelle, String localPath, String remotePath, boolean isMediaType){ this.enabled = true; this.scanLocal = true; this.scanRemote = true; this.libelle = libelle; - this.localFolder = localFolder; - this.remoteFolder = remoteFolder; + this.localPath = localPath; + this.remotePath = remotePath; this.isMediaType = isMediaType; } /** * Constructor for SyncedFolder object. Enabled is true by default. * @param libelle libelle (=categorie) of Synced folder - * @param localFolder path of the folder on device - * @param remoteFolder path of the folder on server + * @param localPath path of the folder on device + * @param remotePath path of the folder on server * @param scanLocal Allow to be scanned by LocalObserverService if set to true * @param scanRemote Allow to be scanned by remoteObserverService if set to true * @param enabled If this folder is available for synchronisation * @param isMediaType If this folder is a media's folder (true) or a settings's folder (false) */ - public SyncedFolder(String libelle, String localFolder, String remoteFolder, boolean scanLocal, boolean scanRemote, boolean enabled, boolean isMediaType){ + public SyncedFolder(String libelle, String localPath, String remotePath, boolean scanLocal, boolean scanRemote, boolean enabled, boolean isMediaType){ this.libelle = libelle; - this.localFolder = localFolder; - this.remoteFolder = remoteFolder; + this.localPath = localPath; + this.remotePath = remotePath; this.scanLocal = scanLocal; this.scanRemote = scanRemote; this.enabled = enabled; @@ -72,10 +72,10 @@ public class SyncedFolder implements Parcelable { * @param in The parcel containing data to build the object */ private SyncedFolder(Parcel in){ - this.id = in.readInt(); + this.id = in.readLong(); this.libelle = in.readString(); - this.localFolder = in.readString(); - this.remoteFolder = in.readString(); + this.localPath = in.readString(); + this.remotePath = in.readString(); this.scanLocal = in.readInt() == 1 ; this.scanRemote = in.readInt() == 1 ; this.enabled = in.readInt() == 1 ; @@ -95,8 +95,8 @@ public class SyncedFolder implements Parcelable { public SyncedFolder(SyncedFolder parent, String suffixPath, long lastModified, String lastEtag){ this.id = -1; this.libelle = parent.libelle; - this.localFolder = parent.localFolder+suffixPath; - this.remoteFolder = parent.remoteFolder+suffixPath; + this.localPath = parent.localPath +suffixPath; + this.remotePath = parent.remotePath +suffixPath; this.scanLocal = parent.scanLocal; this.scanRemote = parent.scanRemote; this.lastModified = lastModified; @@ -123,12 +123,12 @@ public class SyncedFolder implements Parcelable { return libelle; } - public String getLocalFolder() { - return localFolder; + public String getLocalPath() { + return localPath; } - public String getRemoteFolder() { - return remoteFolder; + public String getRemotePath() { + return remotePath; } public boolean isEnabled() { @@ -140,29 +140,29 @@ public class SyncedFolder implements Parcelable { return this; } - public int getId() { + public long getId() { return id; } - public SyncedFolder setId(int id) { + public SyncedFolder setId(long id) { this.id = id; return this; } - public String getLastEtag() { + public String getEtag() { return lastEtag; } - public SyncedFolder setLastEtag(String lastEtag) { + public SyncedFolder setEtag(String lastEtag) { this.lastEtag = lastEtag; return this; } - public long getLastModified() { + public long getLocalLastModified() { return lastModified; } - public SyncedFolder setLastModified(long lastModified) { + public SyncedFolder setLocalLastModified(long lastModified) { this.lastModified = lastModified; return this; } @@ -195,6 +195,13 @@ public class SyncedFolder implements Parcelable { return scanRemote; } + public int getScannable(){ + int result = SyncableContentState.ALL_SCANNABLE; + if (!scanLocal) result -= SyncableContentState.DEVICE_SCANNABLE; + if (!scanRemote) result -= SyncableContentState.ECLOUD_SCANNABLE; + return result; + } + @Override public int describeContents() { return 0; @@ -210,10 +217,10 @@ public class SyncedFolder implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(this.id); + dest.writeLong(this.id); dest.writeString(this.libelle); - dest.writeString(this.localFolder); - dest.writeString(this.remoteFolder); + dest.writeString(this.localPath); + dest.writeString(this.remotePath); dest.writeInt(this.scanLocal ? 1 : 0); dest.writeInt(this.scanRemote ? 1 : 0); dest.writeInt(this.enabled ? 1 : 0); @@ -227,8 +234,8 @@ public class SyncedFolder implements Parcelable { public String toString(){ return "SyncedFolder :\nid : "+this.id +"\n libelle : "+this.libelle - +"\n local folder : "+this.localFolder - +"\n remote folder : "+this.remoteFolder + +"\n local folder : "+this.localPath + +"\n remote folder : "+this.remotePath +"\n scan Local : "+this.scanLocal +"\n scan remote : "+this.scanRemote +"\n enabled : "+this.enabled diff --git a/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java index 4445239c..fce30e93 100644 --- a/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java @@ -42,7 +42,7 @@ public class DownloadFileOperation extends RemoteOperation { public DownloadFileOperation(RemoteFile remoteFile, SyncedFileState syncedFileState, Context context) { this.remoteFile = remoteFile; this.syncedFileState = syncedFileState; - this.previousEtag = syncedFileState.getLastETAG(); + this.previousEtag = syncedFileState.getEtag(); this.targetPath = syncedFileState.getLocalPath(); this.context = context; } @@ -59,7 +59,7 @@ public class DownloadFileOperation extends RemoteOperation { this.syncedFileState.setId(DbHelper.manageSyncedFileStateDB(this.syncedFileState, "INSERT", context)); } - if (syncedFileState.getLastETAG().equals(remoteFile.getEtag()) && syncedFileState.getLocalLastModified() > 0L) { + if (syncedFileState.getEtag().equals(remoteFile.getEtag()) && syncedFileState.getLocalLastModified() > 0L) { //Same etag and localLastModified not null mean the file is up to date Log.w(TAG, "File already up-to-date"); return new RemoteOperationResult(RemoteOperationResult.ResultCode.ETAG_UNCHANGED); @@ -105,7 +105,7 @@ public class DownloadFileOperation extends RemoteOperation { if (!renameResult) Log.d(TAG, "File hasn't been successfully moved at its place"); syncedFileState.setLocalLastModified(localFile.lastModified()) - .setLastETAG(remoteFile.getEtag()); + .setEtag(remoteFile.getEtag()); mustRestart = false; resultCode = RemoteOperationResult.ResultCode.OK; //needed to make Gallery show new image @@ -120,7 +120,7 @@ public class DownloadFileOperation extends RemoteOperation { if (mustRestart) { Log.w(TAG, restartCounter+" unsuccessfull trial.s of downloading file " + remoteFile.getRemotePath()); - syncedFileState.setLastETAG(this.previousEtag); + syncedFileState.setEtag(this.previousEtag); if (this.restartCounter < 3) { this.restartCounter += 1; return this.run(ownCloudClient); diff --git a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java b/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java index ffde62e8..4e335816 100644 --- a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java @@ -66,7 +66,7 @@ public class ListFileRemoteOperation extends RemoteOperation { //if folder is media type() && is an hidden folder then ignore it if(syncedFolder.isMediaType() - && CommonUtils.getFileNameFromPath(syncedFolder.getRemoteFolder()).startsWith(".")){ + && CommonUtils.getFileNameFromPath(syncedFolder.getRemotePath()).startsWith(".")){ mSyncedFolderIterator.remove(); continue; } @@ -84,13 +84,13 @@ public class ListFileRemoteOperation extends RemoteOperation { syncedFolder.setId(syncedFolderId); }else{ mSyncedFolderIterator.remove(); - Log.w(TAG, "syncedFolder "+syncedFolder.getRemoteFolder()+" doesn't have a valid ID"); + Log.w(TAG, "syncedFolder "+syncedFolder.getRemotePath()+" doesn't have a valid ID"); continue; } } //Create ReadRemoteOperation - LightReadFolderRemoteOperation operation = new LightReadFolderRemoteOperation(syncedFolder.getRemoteFolder(), DEPTH_1, false); + LightReadFolderRemoteOperation operation = new LightReadFolderRemoteOperation(syncedFolder.getRemotePath(), DEPTH_1, false); RemoteOperationResult result = operation.execute(ownCloudClient); if(result.isSuccess() ){ @@ -98,7 +98,7 @@ public class ListFileRemoteOperation extends RemoteOperation { int dataSize = result.getData().size(); if(dataSize > 1){ //There is at least one subfiles RemoteFile directory = (RemoteFile) result.getData().get(0); - if(!directory.getEtag().equals(syncedFolder.getLastEtag() )){ //if etag differs + if(!directory.getEtag().equals(syncedFolder.getEtag() )){ //if etag differs List remoteFiles = result.getData().subList( 1, dataSize ); //get list of subfiles //loop through subelements @@ -112,7 +112,7 @@ public class ListFileRemoteOperation extends RemoteOperation { continue; } if( remoteFile.getMimeType().equals("DIR") ) { - String suffixPath = remoteFile.getRemotePath().substring( syncedFolder.getRemoteFolder().length() ); + String suffixPath = remoteFile.getRemotePath().substring( syncedFolder.getRemotePath().length() ); //but is it already known as SyncedFolder? SyncedFolder subSyncedFolder = new SyncedFolder(syncedFolder, suffixPath, 0L, "" ); //need to set empty etag to allow it to be scan @@ -124,13 +124,13 @@ public class ListFileRemoteOperation extends RemoteOperation { mRemoteFiles.add(remoteFile); } } - syncedFolder.setLastEtag(directory.getEtag() ).setToSync(true); + syncedFolder.setEtag(directory.getEtag() ).setToSync(true); atLeastOneDirAsChanged = true; } }else if(dataSize == 1){ //Empty folder RemoteFile directory = (RemoteFile) result.getData().get(0); - if(!directory.getEtag().equals(syncedFolder.getLastEtag())) { - syncedFolder.setLastEtag(directory.getEtag()).setToSync(true); + if(!directory.getEtag().equals(syncedFolder.getEtag())) { + syncedFolder.setEtag(directory.getEtag()).setToSync(true); atLeastOneDirAsChanged = true; } }//Last else correspond to error 404 at LightReadFolderRemoteOperation (see below) @@ -139,7 +139,7 @@ public class ListFileRemoteOperation extends RemoteOperation { atLeastOneDirAsChanged = true; syncedFolder.setToSync(true); //If there is no remote file, then try to delete local one if empty. Finally remove Synced Folder from DB. - File localFolder = new File(syncedFolder.getLocalFolder()); + File localFolder = new File(syncedFolder.getLocalPath()); if(localFolder.exists() && localFolder.listFiles().length == 0){ localFolder.delete(); } diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 5d972a0b..88acb7e0 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -106,7 +106,7 @@ public class UploadFileOperation extends RemoteOperation { if (uploadResult.isSuccess()) { Object data = uploadResult.getSingleData(); if (data != null) { - syncedState.setLastETAG((String) data); + syncedState.setEtag((String) data); } syncedState.setLocalLastModified(file.lastModified()); resultCode = uploadResult.getCode(); @@ -175,7 +175,7 @@ public class UploadFileOperation extends RemoteOperation { UploadFileRemoteOperation uploadRemoteFileOperation = new UploadFileRemoteOperation(syncedState.getLocalPath(), (targetPath != null ) ? targetPath : syncedState.getRemotePath(), CommonUtils.getMimeType(file ), - (!this.syncedState.isMediaType() || syncedState.getLastETAG().isEmpty() )? null : syncedState.getLastETAG(), //If not null, This can cause error 412; that means remote file has change + (!this.syncedState.isMediaType() || syncedState.getEtag().isEmpty() )? null : syncedState.getEtag(), //If not null, This can cause error 412; that means remote file has change timeStamp ); uploadRemoteFileOperation.askResultEtag(true); return uploadRemoteFileOperation; 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 eb84fbb3..242b3c2c 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -39,6 +39,7 @@ import foundation.e.drive.fileFilters.FileFilterFactory; import foundation.e.drive.fileFilters.OnlyFileFilter; import foundation.e.drive.models.DownloadRequest; import foundation.e.drive.models.SyncRequest; +import foundation.e.drive.models.SyncableContentState; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.operations.ListFileRemoteOperation; @@ -224,7 +225,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene //Display content of SyncedFolderList StringBuilder logFolderList = new StringBuilder("SyncedFolder: libelle, localFolder, lastmodified, scanLocal, id :"); for(SyncedFolder sf : mSyncedFolders){ - logFolderList.append("\n").append(sf.getLibelle()).append(", ").append(sf.getLocalFolder()).append(", ").append(sf.getLastModified()).append(", ").append(sf.isScanLocal()).append(", ").append(sf.getId()); + logFolderList.append("\n").append(sf.getLibelle()).append(", ").append(sf.getLocalPath()).append(", ").append(sf.getLocalLastModified()).append(", ").append(sf.isScanLocal()).append(", ").append(sf.getId()); } Log.d(TAG, logFolderList.toString()); @@ -378,7 +379,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene correspondant_found = true; if (syncedFileState.isLastEtagStored() //there is an etag stored - && (!remoteFile.getEtag().equals(syncedFileState.getLastETAG()) //If etag has changed + && (!remoteFile.getEtag().equals(syncedFileState.getEtag()) //If etag has changed || syncedFileState.getLocalLastModified() == 0L)) { //File hasn't been downloaded Log.v(TAG, "etag and localLastModified are valids for "+remoteFilePath ); @@ -387,7 +388,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene 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"); - syncedFileState.setLastETAG(remoteFile.getEtag()); + syncedFileState.setEtag(remoteFile.getEtag()); int affectedRows = DbHelper.manageSyncedFileStateDB(syncedFileState, "UPDATE", this); Log.v(TAG, affectedRows + " syncedFileState.s row in DB has been updated."); } else { @@ -411,19 +412,18 @@ public class ObserverService extends Service implements OnRemoteOperationListene //look for parent folder in SyncedFolders for (int j = -1, mSyncedFolderSize = this.mSyncedFolders.size(); ++j < mSyncedFolderSize;) { - if ( mSyncedFolders.get(j).getRemoteFolder().equals( parentOfKnownPath ) ) { //We have found the parent folder + if ( mSyncedFolders.get(j).getRemotePath().equals( parentOfKnownPath ) ) { //We have found the parent folder final SyncedFolder parentFolder = mSyncedFolders.get(j); String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); //get remote file's name if (fileName != null) { - int scannableValue = 0; + int scannableValue = SyncableContentState.NOT_SCANNABLE; if (parentFolder.isEnabled()) { - if (parentFolder.isScanRemote()) scannableValue++; - if (parentFolder.isScanLocal()) scannableValue += 2; + scannableValue = parentFolder.getScannable(); } //create syncedFileState - SyncedFileState newRemoteFile = new SyncedFileState(-1, fileName, parentFolder.getLocalFolder() + fileName, remoteFilePath, remoteFile.getEtag(), 0, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); + SyncedFileState newRemoteFile = new SyncedFileState(-1, fileName, parentFolder.getLocalPath() + fileName, remoteFilePath, remoteFile.getEtag(), 0, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); //Store it in DB int storedId = DbHelper.manageSyncedFileStateDB(newRemoteFile, "INSERT", this); @@ -547,9 +547,9 @@ public class ObserverService extends Service implements OnRemoteOperationListene //Loop through folders while(iterator.hasNext() ){ SyncedFolder syncedFolder = iterator.next(); - Log.d(TAG, "SyncedFolder :"+syncedFolder.getLibelle()+", "+syncedFolder.getLocalFolder()+", "+syncedFolder.getLastModified()+", "+syncedFolder.isScanLocal()+", "+syncedFolder.getId() ); + Log.d(TAG, "SyncedFolder :"+syncedFolder.getLibelle()+", "+syncedFolder.getLocalPath()+", "+syncedFolder.getLocalLastModified()+", "+syncedFolder.isScanLocal()+", "+syncedFolder.getId() ); - final boolean isHiddenFile = syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()).startsWith("."); + final boolean isHiddenFile = syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalPath()).startsWith("."); if (isHiddenFile || !syncedFolder.isScanLocal()){ iterator.remove(); continue; @@ -564,15 +564,15 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.v(TAG, "Folder has been registered in DB"); syncedFolder.setId(syncedFolder_id); SyncRequest request = new SyncRequest(syncedFolder, SyncRequest.Type.MKCOL); - this.syncRequests.put(syncedFolder.getLocalFolder(), request); + this.syncRequests.put(syncedFolder.getLocalPath(), request); } else { - Log.w(TAG, "syncedFolder " + syncedFolder.getLocalFolder() + " remove iterator because it hasn't been registered in DB or already stored"); + Log.w(TAG, "syncedFolder " + syncedFolder.getLocalPath() + " remove iterator because it hasn't been registered in DB or already stored"); iterator.remove(); continue; } } //Get local folder corresponding - File localFolder = new File(syncedFolder.getLocalFolder()); //Obtention du fichier local + File localFolder = new File(syncedFolder.getLocalPath()); //Obtention du fichier local Log.d(TAG, "Local Folder (last modified / exists): "+localFolder.lastModified()+", "+localFolder.exists() ); //Check if local folder exists @@ -586,9 +586,9 @@ public class ObserverService extends Service implements OnRemoteOperationListene boolean folderHasChange = false; //consider by default that file hadn't change //Check if folder had change - if (localFolder.lastModified() > syncedFolder.getLastModified() ) { //compare last modified date + if (localFolder.lastModified() > syncedFolder.getLocalLastModified() ) { //compare last modified date Log.v(TAG, "local folder has changed"); - syncedFolder.setLastModified( localFolder.lastModified() ); //@Todo: it would be better to set it after all it's content has been synced + syncedFolder.setLocalLastModified( localFolder.lastModified() ); //@Todo: it would be better to set it after all it's content has been synced contentToSyncFound = true; //at least one dir has changed folderHasChange = true; //The folder has change folderIdList.add( (long) syncedFolder.getId() ); //add id into list of modified folder @@ -689,15 +689,14 @@ public class ObserverService extends Service implements OnRemoteOperationListene //look into synced folders if folder path exist for(SyncedFolder syncedFolder : mSyncedFolders){ - if (syncedFolder.getLocalFolder().equals(parentPath)){ - int scannableValue = 0; + if (syncedFolder.getLocalPath().equals(parentPath)){ + int scannableValue = SyncableContentState.NOT_SCANNABLE; if (syncedFolder.isEnabled()) { - if (syncedFolder.isScanRemote()) scannableValue++; - if (syncedFolder.isScanLocal()) scannableValue += 2; + scannableValue = syncedFolder.getScannable(); } //create the syncedFile State - SyncedFileState newSyncedFileState = new SyncedFileState(-1, localFile.getName(), filePath, syncedFolder.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType(),scannableValue); + SyncedFileState newSyncedFileState = new SyncedFileState(-1, localFile.getName(), filePath, syncedFolder.getRemotePath() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType(),scannableValue); //Store it in DB int storedId = DbHelper.manageSyncedFileStateDB(newSyncedFileState, "INSERT", this); diff --git a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java index 62279cc7..ee63dbf6 100644 --- a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java +++ b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java @@ -9,9 +9,6 @@ package foundation.e.drive.services; import android.accounts.Account; import android.accounts.AccountManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -24,7 +21,6 @@ import android.os.Message; import android.util.Log; import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; @@ -38,10 +34,10 @@ import java.util.Collection; import java.util.Hashtable; import java.util.concurrent.ConcurrentLinkedDeque; -import foundation.e.drive.R; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.DownloadRequest; import foundation.e.drive.models.SyncRequest; +import foundation.e.drive.models.SyncableContentState; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.operations.DownloadFileOperation; @@ -130,9 +126,7 @@ public class SynchronizationService extends Service implements OnRemoteOperation if (operation != null) { Log.v(TAG, " an operation has been poll from queue"); - final SyncedFolder sf = request.getSyncedFolder(); - final boolean isAllowedSync = (sf == null) ? request.getSyncedFileState().isMediaType() : sf.isMediaType(); - if (CommonUtils.isThisSyncAllowed(account, isAllowedSync)) { + if (CommonUtils.isThisSyncAllowed(account, request.getSyncableContentState().isMediaType())) { CommonUtils.createNotificationChannel(this); startedOperations.put(operation, threadIndex); threadPool[threadIndex] = operation.execute(client, this, handler); @@ -224,16 +218,16 @@ public class SynchronizationService extends Service implements OnRemoteOperation RemoteOperation operation; switch (request.getOperationType()){ case UPLOAD: - final SyncedFileState sfs = request.getSyncedFileState(); + final SyncedFileState sfs = (SyncedFileState) request.getSyncableContentState(); operation = new UploadFileOperation(sfs, getApplicationContext()); break; case DOWNLOAD: final DownloadRequest downloadRequest = (DownloadRequest) request; - operation = new DownloadFileOperation(downloadRequest.getRemoteFile(), downloadRequest.getSyncedFileState(), getApplicationContext()); + operation = new DownloadFileOperation(downloadRequest.getRemoteFile(), (SyncedFileState) downloadRequest.getSyncableContentState(), getApplicationContext()); break; case MKCOL: - final SyncedFolder syncedFolder = request.getSyncedFolder(); - operation = new CreateFolderRemoteOperation(syncedFolder.getRemoteFolder(), true); + final SyncedFolder syncedFolder = (SyncedFolder) request.getSyncableContentState(); + operation = new CreateFolderRemoteOperation(syncedFolder.getRemotePath(), true); break; case REMOTE_DELETE: default: @@ -243,7 +237,6 @@ public class SynchronizationService extends Service implements OnRemoteOperation return operation; } - /** * Handler for the class */ diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index e3461d2d..3ebb51fc 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -70,7 +70,6 @@ import androidx.work.BackoffPolicy; import androidx.work.Constraints; import androidx.work.Data; import androidx.work.ExistingPeriodicWorkPolicy; -import androidx.work.ExistingWorkPolicy; import androidx.work.NetworkType; import androidx.work.OneTimeWorkRequest; import androidx.work.PeriodicWorkRequest; @@ -424,12 +423,12 @@ public abstract class CommonUtils { private static Data createDataFromSyncedFolder(SyncedFolder folder) { return new Data.Builder() - .putInt(DATA_KEY_ID, folder.getId()) + .putLong(DATA_KEY_ID, folder.getId()) .putString(DATA_KEY_LIBELLE, folder.getLibelle()) - .putString(DATA_KEY_LOCAL_PATH, folder.getLocalFolder()) - .putString(DATA_KEY_REMOTE_PATH, folder.getRemoteFolder()) - .putString(DATA_KEY_LAST_ETAG, folder.getLastEtag()) - .putLong(DATA_KEY_LAST_MODIFIED, folder.getLastModified()) + .putString(DATA_KEY_LOCAL_PATH, folder.getLocalPath()) + .putString(DATA_KEY_REMOTE_PATH, folder.getRemotePath()) + .putString(DATA_KEY_LAST_ETAG, folder.getEtag()) + .putLong(DATA_KEY_LAST_MODIFIED, folder.getLocalLastModified()) .putBoolean(DATA_KEY_SCAN_LOCAL, folder.isScanLocal()) .putBoolean(DATA_KEY_SCAN_REMOTE, folder.isScanRemote()) .putBoolean(DATA_KEY_ENABLE, folder.isEnabled()) diff --git a/app/src/main/java/foundation/e/drive/work/CreateRemoteFolderWorker.java b/app/src/main/java/foundation/e/drive/work/CreateRemoteFolderWorker.java index 38ec32f0..c01efe66 100644 --- a/app/src/main/java/foundation/e/drive/work/CreateRemoteFolderWorker.java +++ b/app/src/main/java/foundation/e/drive/work/CreateRemoteFolderWorker.java @@ -68,11 +68,11 @@ public class CreateRemoteFolderWorker extends Worker { } final SyncedFolder syncedFolder = getSyncedFolderFromData(); - Log.d(TAG, "doWork() for :"+syncedFolder.getLocalFolder()); - final File folder = new File(syncedFolder.getLocalFolder() ); + Log.d(TAG, "doWork() for :"+syncedFolder.getLocalPath()); + final File folder = new File(syncedFolder.getLocalPath() ); if (!folder.exists()) { folder.mkdirs(); - syncedFolder.setLastModified(folder.lastModified()); + syncedFolder.setLocalLastModified(folder.lastModified()); } final OwnCloudClient client = CommonUtils.getOwnCloudClient(account, context); @@ -82,7 +82,7 @@ public class CreateRemoteFolderWorker extends Worker { } final CreateFolderRemoteOperation mkcolRequest = - new CreateFolderRemoteOperation(syncedFolder.getRemoteFolder(), true); + new CreateFolderRemoteOperation(syncedFolder.getRemotePath(), true); try { final RemoteOperationResult result = mkcolRequest.execute(client, true); @@ -109,8 +109,8 @@ public class CreateRemoteFolderWorker extends Worker { data.getBoolean(DATA_KEY_ENABLE, true), data.getBoolean(DATA_KEY_MEDIATYPE, true)); - result.setLastModified(data.getLong(DATA_KEY_LAST_MODIFIED, 0L)); - result.setLastEtag(data.getString(DATA_KEY_LAST_ETAG)); + result.setLocalLastModified(data.getLong(DATA_KEY_LAST_MODIFIED, 0L)); + result.setEtag(data.getString(DATA_KEY_LAST_ETAG)); result.setId(data.getInt(DATA_KEY_ID, -1)); return result; diff --git a/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java b/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java index fbf30d4f..179effa6 100644 --- a/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java +++ b/app/src/test/java/foundation/e/drive/operations/UploadFileOperationTest.java @@ -157,7 +157,7 @@ public class UploadFileOperationTest { createSmallFile(); //preparation final SyncedFileState sfs_fromDB = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); - Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getLastETAG().isEmpty()); + Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getEtag().isEmpty()); boolean checkEtag = false; @@ -175,7 +175,7 @@ public class UploadFileOperationTest { Assert.assertTrue( errorMsg, result.isSuccess()); final SyncedFileState sfs_fromDBAfterUpload = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); - Assert.assertFalse("After upload, the database must store the etag of the syncedFileState. But here it is empty", sfs_fromDBAfterUpload.getLastETAG().isEmpty()); + Assert.assertFalse("After upload, the database must store the etag of the syncedFileState. But here it is empty", sfs_fromDBAfterUpload.getEtag().isEmpty()); } @@ -210,7 +210,7 @@ public class UploadFileOperationTest { createSmallFile(); //preparation final SyncedFileState sfs_fromDB = DbHelper.loadSyncedFile(RuntimeEnvironment.application, syncedFileStates.get(0).getLocalPath(), true); - Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getLastETAG().isEmpty()); + Assert.assertTrue("SyncedFileState loaded from DB must have an empty Etag", sfs_fromDB.getEtag().isEmpty()); boolean checkEtag = false; UploadFileOperation testOperation = new UploadFileOperation(syncedFileStates.get(0)); -- GitLab