From 1cef99695aebb854e009a7bfee3d8c59029575e2 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 15 Mar 2022 15:48:43 +0100 Subject: [PATCH 01/31] Add method to get SyncedFolder from DB from remote Path - Add method getSyncedFolderByLocalPath(String path, Context context) in DbHelper.hava - Add method getSyncedFolderByLocalPath(String path) in SyncedFolderDAO.java --- .../java/foundation/e/drive/database/DbHelper.java | 10 ++++++++++ .../foundation/e/drive/database/SyncedFolderDAO.java | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index d1f94ee7..537c548e 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -243,6 +243,16 @@ public final class DbHelper extends SQLiteOpenHelper { return result; } + public static SyncedFolder getSyncedFolderByLocalPath(String localPath, Context context){ + SyncedFolderDAO dao = openSyncedFolderDAO(context, true); + if(dao == null){ + return null; + } + SyncedFolder syncedFolder = dao.getSyncedFolderByLocalPath(localPath); + dao.close(); + return syncedFolder; + } + /** * Set the lastModified value of SyncedFolder to 1. * The goal is to force to rescan it next time. 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 8af54a1f..69f6e022 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java @@ -174,6 +174,17 @@ class SyncedFolderDAO { return result; } + SyncedFolder getSyncedFolderByLocalPath(String localPath){ + Cursor cursor = mDB.query(TABLE_NAME, allColumns, LOCAL_PATH+" = "+localPath, new String[0], null, null, null); + cursor.moveToFirst(); + SyncedFolder result = null; + if ( !cursor.isAfterLast() ) { + result = cursorToSyncedFolder(cursor); + } + cursor.close(); + return result; + } + /** * Create a syncedFolder object from data in cursor. * @param cursor cursor containing data to build syncedFolder -- GitLab From c771653b6c7a06867581faf75cbd660402d1eb9b Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 15 Mar 2022 18:53:50 +0100 Subject: [PATCH 02/31] make SynchronizationBinder.getService() public --- .../foundation/e/drive/services/SynchronizationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d532786e..7593485c 100644 --- a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java +++ b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java @@ -259,7 +259,7 @@ public class SynchronizationService extends Service implements OnRemoteOperation } public class SynchronizationBinder extends Binder{ - SynchronizationService getService(){ + public SynchronizationService getService(){ return SynchronizationService.this; } } -- GitLab From cd25b948ddce752f833efa722140d7a6a064c2c2 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 15 Mar 2022 18:54:44 +0100 Subject: [PATCH 03/31] Update FileEventListener to handle some event - Add many todo's comment for next part to implement. - Implement 'handleFileDeletion()' method to handle File deletion event (not for directory) - Implement 'handleFileCloseWrite()' method to handle File CLOSE_WRITE event (update/creation) - Implement 'handleFolderDeletion()' method to handle DELETE event for folder. Disable it DB to prevent futur full scan. - Add 'Context' parameter in constructor - Add new fproperty to allow to bind to SynchronizationService - Update 'onEvent()' method to call three new methods depending of event and if file is a directory or not. --- .../foundation/e/drive/EdriveApplication.java | 2 +- .../FileObservers/FileEventListener.java | 162 +++++++++++++++++- 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/EdriveApplication.java b/app/src/main/java/foundation/e/drive/EdriveApplication.java index e8de2b00..65120303 100644 --- a/app/src/main/java/foundation/e/drive/EdriveApplication.java +++ b/app/src/main/java/foundation/e/drive/EdriveApplication.java @@ -41,7 +41,7 @@ public class EdriveApplication extends Application { resetOperationManagerSetting(); final String pathForObserver = Environment.getExternalStorageDirectory().getAbsolutePath(); - mFileObserver = new RecursiveFileObserver(getApplicationContext(), pathForObserver, new FileEventListener()); + mFileObserver = new RecursiveFileObserver(getApplicationContext(), pathForObserver, new FileEventListener(getApplicationContext())); SharedPreferences prefs = getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); 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 bcceca7b..80269a79 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -8,10 +8,25 @@ package foundation.e.drive.FileObservers; +import static foundation.e.drive.models.SyncRequest.Type.UPLOAD; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; import android.os.FileObserver; +import android.os.IBinder; import android.util.Log; import java.io.File; +import java.util.ArrayList; + +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.SyncRequest; +import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.models.SyncedFolder; +import foundation.e.drive.services.SynchronizationService; +import foundation.e.drive.utils.CommonUtils; /** * @author Narinder Rana @@ -19,12 +34,149 @@ import java.io.File; */ public class FileEventListener { private final static String TAG = FileEventListener.class.getSimpleName(); + + private Context appContext; + private SynchronizationService synchronizationService; + private boolean boundToSynchronizationService = false; + private ServiceConnection SynchronizationServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + SynchronizationService.SynchronizationBinder binder = (SynchronizationService.SynchronizationBinder) iBinder; + synchronizationService = binder.getService(); + boundToSynchronizationService = true; + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.e(TAG, "onServiceDisconnected"); + boundToSynchronizationService = false; + } + }; + + public FileEventListener(Context applicationContext){ + this.appContext = applicationContext; + } + + public void onEvent(int event, File file){ + /** + * TEMP comment. Will be removed as soon as fully implemented + * On file event: + * 1. If file is a directory ? is it already handle before in RecursiveFileObserver? + * Not sur.. + * -> If it's a new directory: insert it in Database and start FileObserver on it + * -> If it's a already known directory...update last modified time ? + * -> If it's a deletion: if already in DB, disable it. Else ignore + * -> If it's a rename : ??? + * -> If it's a move : ??? + * + * 2. If It's a file: + * -> If it's a new file: insert it into DB and if insertion successful create uploadRequest + * -> If it's an already know file: update DB but only after Transfer create uploadRequest + * -> If it's a deletion: disable it. If we remove it, it will be downloaded again at next full scan + * -> if it's a rename: handle it later + * -> if it's a move: handle it later + * + **/ + //get syncedFolder + final String fileLocalPath = CommonUtils.getLocalPath(file); + final String parentFolderLocalPath = CommonUtils.getLocalPath(file.getParentFile()); + + + SyncRequest request = null; + + //Check if file isn't a directory + if (file.isDirectory()){ + SyncedFolder syncedFolder = DbHelper.getSyncedFolderByLocalPath(CommonUtils.getLocalPath(file), appContext); + + if (event== FileObserver.CLOSE_WRITE){ //Event triggered after modification/creation + Log.d(TAG, "CLOSE_WRITE event for :"+file.getName()); + } + else if (event== FileObserver.DELETE){ + handleFolderDeletion(file, syncedFolder); + } + } else { + final SyncedFolder parentSyncedFolder = DbHelper.getSyncedFolderByLocalPath(parentFolderLocalPath,appContext); + final SyncedFileState syncedFileState = DbHelper.loadSyncedFile(appContext, fileLocalPath , true); + + if (event == FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation + request = handleFileCloseWrite(file, syncedFileState, parentSyncedFolder); + } else if (event== FileObserver.DELETE) { + handleFileDeletion(file, syncedFileState); + } else { + //@todo handle file rename or file move. But I don't know how to do it yet + Log.w(TAG, "Event: "+event+" for file +"+file.getName()+" not handled"); + } + } + + if (request != null){ + Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); + appContext.bindService(SynchronizationServiceIntent, SynchronizationServiceConnection, Context.BIND_AUTO_CREATE); + + this.synchronizationService.queueOperation(request); + + appContext.unbindService(SynchronizationServiceConnection); + } + } + + + /** + * Handle CLOSE_WRITE fileEvent on the given file. + * This can be creation, edition, attribute changes + * @param file The file which triggered the file event + * @param syncedFileState SyncedFileState instance loaded from DB + * @param syncedFolder SyncedFolder instance representing parent folder of the file. Loaded from DB. + * @return SyncRequest instance if an upload of the file should be done or null if not. + */ + private SyncRequest handleFileCloseWrite(File file, SyncedFileState syncedFileState, SyncedFolder syncedFolder){ + + if (syncedFolder == null || !syncedFolder.isEnabled()){ + Log.w(TAG, "Ignore event because syncedFolder for "+file.getName()+"'s parent is disabled or not in DB."); + return null ; + } + + final String remotePath = syncedFolder.getRemoteFolder()+file.getName(); + + //if file not in DB + if (syncedFileState == null) { + syncedFileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, syncedFolder.getId(), syncedFolder.isMediaType()); + int storedId = DbHelper.manageSyncedFileStateDB(syncedFileState, "INSERT", appContext); + if (storedId > 0) { + syncedFileState.setId(storedId); + } else { + //@todo handle: Database error return same code (-1) as conflict at insertion... + Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); + return null; + } + } + return new SyncRequest(syncedFileState, UPLOAD); + } + + + /** + * Handle DELETE event for given file + * @param file the file which triggered file event + * @param syncedFileState SyncedFileState instance representing the triggering file. if null, just add logcat event + */ + private void handleFileDeletion(File file, SyncedFileState syncedFileState){ + if (syncedFileState == null) { + Log.w(TAG, "File "+file.getName()+" has been removed but wasn't store in DB"); + return; + } + //@todo: disable synchronization for this file... not yet possible + //Require a database change for SyncedFileState + } + + private void handleFolderDeletion(File file, SyncedFolder syncedFolder){ + Log.d(TAG, "DELETE event for :"+file.getName()); + if(syncedFolder != null){ + syncedFolder.setEnabled(false); + ArrayList list = new ArrayList<>(); //@todo add a method to handle singleSyncedFolder update + list.add(syncedFolder); + //@todo add specific method to disable folder and all subfiles & possible subfolder. - public void onEvent(int event, File file) { - if (event == FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation - Log.d(TAG, "CLOSE_WRITE event for :" + file.getName()); - } else if (event == FileObserver.DELETE) { - Log.d(TAG, "DELETE event for :" + file.getName()); + DbHelper.updateSyncedFolders(list, appContext); + }else{ + Log.d(TAG, "Ignore folder deletion as not stored in DB"); } } } -- GitLab From 049eed2784b4adf83af7abe9634b47c5e2ee7364 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Mar 2022 13:52:12 +0100 Subject: [PATCH 04/31] Factorize code about SynchronizationService binding - create SynchronizationServiceConnection.java which implements ServiceConnection. It encapsulates field for connection that would be duplicated over ObserverService and FileEventListener otherwise. - Update FileEventListener to replace classic ServiceConnection by SynchronizationServiceConnection - Update ObserverService to replace classic ServiceConnection by SynchronizationService - Create method "passSyncRequestsToSynchronizationService()" to extract a part of code into a specific method --- .../FileObservers/FileEventListener.java | 30 +++-------- .../e/drive/services/ObserverService.java | 42 +++++++-------- .../SynchronizationServiceConnection.java | 52 +++++++++++++++++++ 3 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.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 80269a79..a60469e7 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -1,5 +1,6 @@ /* * Copyright © Narinder Rana (/e/ foundation). + * Copyright © Vincent Bourgmayer (/e/ foundation). * 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 @@ -10,12 +11,9 @@ package foundation.e.drive.FileObservers; import static foundation.e.drive.models.SyncRequest.Type.UPLOAD; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.os.FileObserver; -import android.os.IBinder; import android.util.Log; import java.io.File; @@ -27,6 +25,7 @@ import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.services.SynchronizationService; import foundation.e.drive.utils.CommonUtils; +import foundation.e.drive.utils.SynchronizationServiceConnection; /** * @author Narinder Rana @@ -36,22 +35,8 @@ public class FileEventListener { private final static String TAG = FileEventListener.class.getSimpleName(); private Context appContext; - private SynchronizationService synchronizationService; - private boolean boundToSynchronizationService = false; - private ServiceConnection SynchronizationServiceConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, IBinder iBinder) { - SynchronizationService.SynchronizationBinder binder = (SynchronizationService.SynchronizationBinder) iBinder; - synchronizationService = binder.getService(); - boundToSynchronizationService = true; - } - @Override - public void onServiceDisconnected(ComponentName componentName) { - Log.e(TAG, "onServiceDisconnected"); - boundToSynchronizationService = false; - } - }; + private SynchronizationServiceConnection serviceConnection = new SynchronizationServiceConnection(); public FileEventListener(Context applicationContext){ this.appContext = applicationContext; @@ -110,11 +95,12 @@ public class FileEventListener { if (request != null){ Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); - appContext.bindService(SynchronizationServiceIntent, SynchronizationServiceConnection, Context.BIND_AUTO_CREATE); + appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); - this.synchronizationService.queueOperation(request); - - appContext.unbindService(SynchronizationServiceConnection); + if(serviceConnection.isBoundToSynchronizationService()){ + serviceConnection.getSynchronizationService().queueOperation(request); + appContext.unbindService(serviceConnection); + } } } 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 632d5b8a..90259ab9 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -50,6 +50,7 @@ import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.DavClientProvider; 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; @@ -70,23 +71,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene private int initialFolderCounter; private Account mAccount; private HashMap syncRequests; //integer is SyncedFileState id; Parcelable is the operation - - private SynchronizationService synchronizationService; - private boolean boundToSynchronizationService = false; - private ServiceConnection SynchronizationServiceConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, IBinder iBinder) { - SynchronizationService.SynchronizationBinder binder = (SynchronizationService.SynchronizationBinder) iBinder; - synchronizationService = binder.getService(); - boundToSynchronizationService = true; - } - - @Override - public void onServiceDisconnected(ComponentName componentName) { - Log.e(TAG, "onServiceDisconnected"); - boundToSynchronizationService = false; - } - }; + private SynchronizationServiceConnection synchronizationServiceConnection = new SynchronizationServiceConnection(); /* Lifecycle Methods */ @@ -162,9 +147,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } this.syncRequests = new HashMap<>(); - Intent SynchronizationServiceIntent = new Intent(this.getApplicationContext(), SynchronizationService.class); - bindService(SynchronizationServiceIntent, SynchronizationServiceConnection, Context.BIND_AUTO_CREATE); - begin(); return super.onStartCommand( intent, flags, startId ); } @@ -317,11 +299,11 @@ public class ObserverService extends Service implements OnRemoteOperationListene } this.startScan(false); - Log.v(TAG, "operationsForIntent contains "+ syncRequests.size() ); + Log.v(TAG, "operationsForIntent contains " + syncRequests.size()); //After everything has been scanned. Send Intent to OperationmanagerService with data in bundle if (syncRequests != null && !syncRequests.isEmpty()) { - this.synchronizationService.queueOperations(syncRequests.values()); + passSyncRequestsToSynchronizationService(); } else { Log.w(TAG, "There is no file to sync."); getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) @@ -330,13 +312,25 @@ public class ObserverService extends Service implements OnRemoteOperationListene .putBoolean(AppConstants.KEY_OMS_IS_WORKING, false) .apply(); } - this.isWorking = false; - unbindService(SynchronizationServiceConnection); this.stopSelf(); + } + } + + private void passSyncRequestsToSynchronizationService() { + final Intent SynchronizationServiceIntent = new Intent(this.getApplicationContext(), SynchronizationService.class); + bindService(SynchronizationServiceIntent, synchronizationServiceConnection, Context.BIND_AUTO_CREATE); + + if (synchronizationServiceConnection.isBoundToSynchronizationService()) { + synchronizationServiceConnection.getSynchronizationService().queueOperations(syncRequests.values()); + unbindService(synchronizationServiceConnection); + } else { + Log.e(TAG, "ERROR: impossible to bind ObserverService to SynchronizationService"); } } + + /** * Method to get Id of SyncedFolder to scan * @return List id of SyncedFolder to scan diff --git a/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java b/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java new file mode 100644 index 00000000..db0fe194 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java @@ -0,0 +1,52 @@ +/** + * Copyright © Vincent Bourgmayer (/e/ foundation). + * 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 android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +import foundation.e.drive.services.SynchronizationService; + +/** + * @author Vincent Bourgmayer + */ +public class SynchronizationServiceConnection implements ServiceConnection { + private final static String TAG = SynchronizationServiceConnection.class.getSimpleName(); + + private SynchronizationService synchronizationService; + private boolean boundToSynchronizationService = false; + + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + Log.i(TAG, "onServiceDisconnected: binding to SynchronizationService"); + SynchronizationService.SynchronizationBinder binder = (SynchronizationService.SynchronizationBinder) iBinder; + synchronizationService = binder.getService(); + boundToSynchronizationService = true; + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.i(TAG, "onServiceDisconnected: unbinding from SynchronizationService"); + boundToSynchronizationService = false; + } + + public boolean isBoundToSynchronizationService() { + return boundToSynchronizationService; + } + + /** + * Get SynchronizationService. Might be null! + * @return + */ + public SynchronizationService getSynchronizationService() { + return synchronizationService; + } +} -- GitLab From d15c55853bc90d10af25ed719a0073cefa7dc2d5 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Mar 2022 15:28:21 +0100 Subject: [PATCH 05/31] fix coding style of FileEventListener.java --- .../FileObservers/FileEventListener.java | 54 ++++++------------- 1 file changed, 15 insertions(+), 39 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 a60469e7..cc12e55e 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -32,51 +32,29 @@ import foundation.e.drive.utils.SynchronizationServiceConnection; * @author vincent Bourgmayer */ public class FileEventListener { - private final static String TAG = FileEventListener.class.getSimpleName(); - + private static final String TAG = FileEventListener.class.getSimpleName(); + private Context appContext; private SynchronizationServiceConnection serviceConnection = new SynchronizationServiceConnection(); - public FileEventListener(Context applicationContext){ + public FileEventListener(Context applicationContext) { this.appContext = applicationContext; } - public void onEvent(int event, File file){ - /** - * TEMP comment. Will be removed as soon as fully implemented - * On file event: - * 1. If file is a directory ? is it already handle before in RecursiveFileObserver? - * Not sur.. - * -> If it's a new directory: insert it in Database and start FileObserver on it - * -> If it's a already known directory...update last modified time ? - * -> If it's a deletion: if already in DB, disable it. Else ignore - * -> If it's a rename : ??? - * -> If it's a move : ??? - * - * 2. If It's a file: - * -> If it's a new file: insert it into DB and if insertion successful create uploadRequest - * -> If it's an already know file: update DB but only after Transfer create uploadRequest - * -> If it's a deletion: disable it. If we remove it, it will be downloaded again at next full scan - * -> if it's a rename: handle it later - * -> if it's a move: handle it later - * - **/ - //get syncedFolder + public void onEvent(int event, File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); final String parentFolderLocalPath = CommonUtils.getLocalPath(file.getParentFile()); - SyncRequest request = null; - //Check if file isn't a directory - if (file.isDirectory()){ + if (file.isDirectory()) { SyncedFolder syncedFolder = DbHelper.getSyncedFolderByLocalPath(CommonUtils.getLocalPath(file), appContext); - if (event== FileObserver.CLOSE_WRITE){ //Event triggered after modification/creation + if (event== FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation Log.d(TAG, "CLOSE_WRITE event for :"+file.getName()); } - else if (event== FileObserver.DELETE){ + else if (event== FileObserver.DELETE) { handleFolderDeletion(file, syncedFolder); } } else { @@ -93,11 +71,11 @@ public class FileEventListener { } } - if (request != null){ + if (request != null) { Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); - if(serviceConnection.isBoundToSynchronizationService()){ + if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); appContext.unbindService(serviceConnection); } @@ -113,16 +91,14 @@ public class FileEventListener { * @param syncedFolder SyncedFolder instance representing parent folder of the file. Loaded from DB. * @return SyncRequest instance if an upload of the file should be done or null if not. */ - private SyncRequest handleFileCloseWrite(File file, SyncedFileState syncedFileState, SyncedFolder syncedFolder){ - - if (syncedFolder == null || !syncedFolder.isEnabled()){ + private SyncRequest handleFileCloseWrite(File file, SyncedFileState syncedFileState, SyncedFolder syncedFolder) { + if (syncedFolder == null || !syncedFolder.isEnabled()) { Log.w(TAG, "Ignore event because syncedFolder for "+file.getName()+"'s parent is disabled or not in DB."); return null ; } final String remotePath = syncedFolder.getRemoteFolder()+file.getName(); - //if file not in DB if (syncedFileState == null) { syncedFileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, syncedFolder.getId(), syncedFolder.isMediaType()); int storedId = DbHelper.manageSyncedFileStateDB(syncedFileState, "INSERT", appContext); @@ -143,7 +119,7 @@ public class FileEventListener { * @param file the file which triggered file event * @param syncedFileState SyncedFileState instance representing the triggering file. if null, just add logcat event */ - private void handleFileDeletion(File file, SyncedFileState syncedFileState){ + private void handleFileDeletion(File file, SyncedFileState syncedFileState) { if (syncedFileState == null) { Log.w(TAG, "File "+file.getName()+" has been removed but wasn't store in DB"); return; @@ -152,16 +128,16 @@ public class FileEventListener { //Require a database change for SyncedFileState } - private void handleFolderDeletion(File file, SyncedFolder syncedFolder){ + private void handleFolderDeletion(File file, SyncedFolder syncedFolder) { Log.d(TAG, "DELETE event for :"+file.getName()); - if(syncedFolder != null){ + if (syncedFolder != null) { syncedFolder.setEnabled(false); ArrayList list = new ArrayList<>(); //@todo add a method to handle singleSyncedFolder update list.add(syncedFolder); //@todo add specific method to disable folder and all subfiles & possible subfolder. DbHelper.updateSyncedFolders(list, appContext); - }else{ + } else { Log.d(TAG, "Ignore folder deletion as not stored in DB"); } } -- GitLab From fe20f44a45c74f6cde5e99ce2f3d206e62e88868 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 11:12:04 +0100 Subject: [PATCH 06/31] Rewrite FileEventListener - Rewrite FileEventListener.onEvent() - Remove previously created private function (handleFolderDeletion, handleFileCloseWrite, etc.) - Add a new method "SendSyncRequestToSynchronizationService(SyncRequest request); --- .../FileObservers/FileEventListener.java | 169 ++++++++---------- 1 file changed, 79 insertions(+), 90 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 cc12e55e..48fd3b5d 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -16,6 +16,8 @@ import android.content.Intent; import android.os.FileObserver; import android.util.Log; +import com.owncloud.android.lib.resources.files.FileUtils; + import java.io.File; import java.util.ArrayList; @@ -34,111 +36,98 @@ import foundation.e.drive.utils.SynchronizationServiceConnection; public class FileEventListener { private static final String TAG = FileEventListener.class.getSimpleName(); - private Context appContext; - - private SynchronizationServiceConnection serviceConnection = new SynchronizationServiceConnection(); + private final Context appContext; + private final SynchronizationServiceConnection serviceConnection = new SynchronizationServiceConnection(); public FileEventListener(Context applicationContext) { this.appContext = applicationContext; } public void onEvent(int event, File file) { + //@todo find a good code split for below massive block final String fileLocalPath = CommonUtils.getLocalPath(file); - final String parentFolderLocalPath = CommonUtils.getLocalPath(file.getParentFile()); - - SyncRequest request = null; - - if (file.isDirectory()) { - SyncedFolder syncedFolder = DbHelper.getSyncedFolderByLocalPath(CommonUtils.getLocalPath(file), appContext); - - if (event== FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation - Log.d(TAG, "CLOSE_WRITE event for :"+file.getName()); - } - else if (event== FileObserver.DELETE) { - handleFolderDeletion(file, syncedFolder); - } - } else { - final SyncedFolder parentSyncedFolder = DbHelper.getSyncedFolderByLocalPath(parentFolderLocalPath,appContext); - final SyncedFileState syncedFileState = DbHelper.loadSyncedFile(appContext, fileLocalPath , true); - - if (event == FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation - request = handleFileCloseWrite(file, syncedFileState, parentSyncedFolder); - } else if (event== FileObserver.DELETE) { - handleFileDeletion(file, syncedFileState); + if (event == FileObserver.DELETE) { + if (file.isDirectory()) { + SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); + if (folder == null) { + //look for parent + final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); + SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); + if (parentFolder != null ) { //if parent is in the DB + folder = new SyncedFolder(parentFolder, file.getName()+ FileUtils.PATH_SEPARATOR, file.lastModified(), ""); + folder.setEnabled(false); + DbHelper.insertSyncedFolder(folder, appContext); + } + } else { //If already in DB + if (folder.isEnabled()) { + folder.setEnabled(false); + //DbHelper.updateSyncedFolder(folder); + //@todo add the missing stuff + } + } } else { - //@todo handle file rename or file move. But I don't know how to do it yet - Log.w(TAG, "Event: "+event+" for file +"+file.getName()+" not handled"); - } - } - - if (request != null) { - Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); - appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); - - if (serviceConnection.isBoundToSynchronizationService()) { - serviceConnection.getSynchronizationService().queueOperation(request); - appContext.unbindService(serviceConnection); + SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); + if (fileState != null) { //If already in DB + //if fileState is enable + //@todo add the missing stuff + //disable sync of SyncedFilestate + //@todo add the missing stuff + DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); + } } - } - } - - - /** - * Handle CLOSE_WRITE fileEvent on the given file. - * This can be creation, edition, attribute changes - * @param file The file which triggered the file event - * @param syncedFileState SyncedFileState instance loaded from DB - * @param syncedFolder SyncedFolder instance representing parent folder of the file. Loaded from DB. - * @return SyncRequest instance if an upload of the file should be done or null if not. - */ - private SyncRequest handleFileCloseWrite(File file, SyncedFileState syncedFileState, SyncedFolder syncedFolder) { - if (syncedFolder == null || !syncedFolder.isEnabled()) { - Log.w(TAG, "Ignore event because syncedFolder for "+file.getName()+"'s parent is disabled or not in DB."); - return null ; - } - - final String remotePath = syncedFolder.getRemoteFolder()+file.getName(); - - if (syncedFileState == null) { - syncedFileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, syncedFolder.getId(), syncedFolder.isMediaType()); - int storedId = DbHelper.manageSyncedFileStateDB(syncedFileState, "INSERT", appContext); - if (storedId > 0) { - syncedFileState.setId(storedId); + } else if (event == FileObserver.CLOSE_WRITE) { + if (file.isDirectory()) { + SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); + if (folder == null) { //it's a directory creation + final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); + SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); + if (parentFolder != null) { //if parent is in the DB + folder = new SyncedFolder(parentFolder, file.getName()+ FileUtils.PATH_SEPARATOR, file.lastModified(), ""); + DbHelper.insertSyncedFolder(folder, appContext); + } + } else { //It's a directory update + folder.setLastModified(file.lastModified()); + //DbHelper.updateSyncedFolder(folder); + //@todo add the missing stuff + } } else { - //@todo handle: Database error return same code (-1) as conflict at insertion... - Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); - return null; + SyncRequest request = null; + SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); + + if (fileState == null) { //New file discovered + final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); + SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); + if (parentFolder != null && parentFolder.isEnabled()) { //if parent is in the DB + final String remotePath = parentFolder.getRemoteFolder()+file.getName(); + fileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, parentFolder.getId(), parentFolder.isMediaType()); + int storedId = DbHelper.manageSyncedFileStateDB(fileState, "INSERT", appContext); + if (storedId > 0) { + fileState.setId(storedId); + request = new SyncRequest(fileState, UPLOAD); + } else { + Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); + } + } + } else { //File update + //If sync is enable + //@todo add the missing stuff + + request = new SyncRequest(fileState, UPLOAD); + } + if (request != null) { + sendSyncRequestToSynchronizationService(request); + } } } - return new SyncRequest(syncedFileState, UPLOAD); - } - - - /** - * Handle DELETE event for given file - * @param file the file which triggered file event - * @param syncedFileState SyncedFileState instance representing the triggering file. if null, just add logcat event - */ - private void handleFileDeletion(File file, SyncedFileState syncedFileState) { - if (syncedFileState == null) { - Log.w(TAG, "File "+file.getName()+" has been removed but wasn't store in DB"); - return; - } - //@todo: disable synchronization for this file... not yet possible - //Require a database change for SyncedFileState } - private void handleFolderDeletion(File file, SyncedFolder syncedFolder) { - Log.d(TAG, "DELETE event for :"+file.getName()); - if (syncedFolder != null) { - syncedFolder.setEnabled(false); - ArrayList list = new ArrayList<>(); //@todo add a method to handle singleSyncedFolder update - list.add(syncedFolder); - //@todo add specific method to disable folder and all subfiles & possible subfolder. + private void sendSyncRequestToSynchronizationService(SyncRequest request) { + final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); + appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); - DbHelper.updateSyncedFolders(list, appContext); - } else { - Log.d(TAG, "Ignore folder deletion as not stored in DB"); + if (serviceConnection.isBoundToSynchronizationService()) { + serviceConnection.getSynchronizationService().queueOperation(request); + appContext.unbindService(serviceConnection); } } } -- GitLab From 144bb50c932b87e237a207221c307d0e8c1570b0 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Wed, 16 Mar 2022 17:21:01 +0100 Subject: [PATCH 07/31] add 'Scannable' field in SyncedFileState and update Database for that - Add 'int scannable' property in SyncedFileState.java. Update Constructor and define getter/setter - Add Update instruction for SyncedFileState DB's Table in SyncedFileStateConstract.java - Update DBHelper to use the Table's update instruction --- .../foundation/e/drive/database/DbHelper.java | 16 +++++---- .../database/SyncedFileStateContract.java | 13 +++++-- .../e/drive/database/SyncedFileStateDAO.java | 13 ++----- .../e/drive/models/SyncedFileState.java | 35 ++++++++++++++++--- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index 537c548e..545dda91 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -24,7 +24,7 @@ import foundation.e.drive.models.SyncedFileState; */ public final class DbHelper extends SQLiteOpenHelper { final private static String TAG = DbHelper.class.getSimpleName(); //Tag for log - private static final int DATABASE_VERSION = 19; //20/09/2018 + private static final int DATABASE_VERSION = 20; //16/03/2022 public static final String DATABASE_NAME = "eelo_drive.db"; /** @@ -53,18 +53,22 @@ public final class DbHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i(TAG, "onUpgrade(db, "+oldVersion+", "+newVersion+")"); - if(oldVersion < 19){ - try { + try { + if (oldVersion < 19) { db.execSQL(SyncedFolderContract.UPDATE_TABLE_TO_VERSION_19); db.execSQL(SyncedFileStateContract.UPDATE_TABLE_TO_VERSION_19); - db.execSQL(SyncedFileStateContract.UPDATE_MEDIA_DATA_TO_VERSION_19); db.execSQL(SyncedFileStateContract.UPDATE_SETTINGS_DATA_TO_VERSION_19); db.execSQL(SyncedFolderContract.UPDATE_MEDIA_DATA_TO_VERSION_19); db.execSQL(SyncedFolderContract.UPDATE_SETTINGS_DATA_TO_VERSION_19); - }catch(Exception e){ - Log.e(TAG, toString()); } + if (oldVersion < 20) { + db.execSQL(SyncedFileStateContract.UPDATE_TABLE_TO_VERSION_20); + db.execSQL(SyncedFileStateContract.UPDATE_MEDIA_DATA_TO_VERSION_20); + db.execSQL(SyncedFileStateContract.UPDATE_SETTINGS_DATA_TO_VERSION_20); + } + } catch(Exception e) { + Log.e(TAG, toString()); } } diff --git a/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java b/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java index 3d0f69cf..3639adab 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java @@ -25,6 +25,7 @@ class SyncedFileStateContract implements BaseColumns{ static final String LOCAL_LAST_MODIFIED = "local_last_modified"; static final String SYNCEDFOLDER_ID = "synced_folder_id"; static final String IS_MEDIA_TYPE = "is_media_type"; + static final String SCANNABLE = "scannable"; static final String SQL_CREATE_TABLE_SYNCEDFILESTATE = "CREATE TABLE "+TABLE_NAME+" ( " @@ -39,14 +40,15 @@ class SyncedFileStateContract implements BaseColumns{ +"CONSTRAINT synced_unicity_constraint UNIQUE (" +FILE_NAME+", " +LOCAL_PATH+", " - +REMOTE_PATH + +REMOTE_PATH+", " + +SCANNABLE +"))"; static final String SQL_DELETE_TABLE_SYNCEDFILESTATE = " DROP TABLE IF EXISTS " + TABLE_NAME; + //Update for version 18 and lower static final String UPDATE_TABLE_TO_VERSION_19 = "ALTER TABLE "+TABLE_NAME+" ADD COLUMN "+IS_MEDIA_TYPE+" BOOLEAN;"; - static final String UPDATE_MEDIA_DATA_TO_VERSION_19 = "UPDATE "+TABLE_NAME+ " SET "+IS_MEDIA_TYPE+" = 1 WHERE "+ REMOTE_PATH+" LIKE \"/Photos/%\" OR "+ @@ -60,4 +62,11 @@ class SyncedFileStateContract implements BaseColumns{ static final String UPDATE_SETTINGS_DATA_TO_VERSION_19 = "UPDATE "+TABLE_NAME+ " SET "+IS_MEDIA_TYPE+" = 0 WHERE "+REMOTE_PATH+" LIKE \"/Devices/%\";"; + //update for version 19 and lower + static final String UPDATE_TABLE_TO_VERSION_20 = "ALTER TABLE "+TABLE_NAME+" ADD COLUMN "+SCANNABLE+" INTEGER;"; + static final String UPDATE_MEDIA_DATA_TO_VERSION_20 = "UPDATE "+TABLE_NAME+" SET "+SCANNABLE+" = 3 WHERE" + + IS_MEDIA_TYPE+" = 1 ;" ; + static final String UPDATE_SETTINGS_DATA_TO_VERSION_20 = "UPDATE "+TABLE_NAME+" SET "+SCANNABLE+" = 2 WHERE" + + IS_MEDIA_TYPE+" = 0 ;" ; + } 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 91865813..031a2726 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java @@ -39,16 +39,6 @@ class SyncedFileStateDAO { private SQLiteDatabase mDB; private final DbHelper mHelper; - /*private final String[] allColumns = { SyncedFileStateContract._ID, - SyncedFileStateContract.FILE_NAME, - SyncedFileStateContract.LOCAL_PATH, - SyncedFileStateContract.REMOTE_PATH, - SyncedFileStateContract.LAST_ETAG, - - SyncedFileStateContract.LOCAL_LAST_MODIFIED, - SyncedFileStateContract.SYNCEDFOLDER_ID, - SyncedFileStateContract.IS_MEDIA_TYPE - };*/ SyncedFileStateDAO(Context context){ this.mHelper = new DbHelper(context); @@ -224,7 +214,8 @@ class SyncedFileStateDAO { cursor.getString(4 ),// last Etag cursor.getLong(5 ),//Local last modified cursor.getLong(6 ), //SyncedFolderID - (cursor.getInt(7) == 1 ) //is Media Type + (cursor.getInt(7) == 1), //is Media Type + cursor.getInt(7) //scannable ); } } 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 42c76a10..f3b842b3 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncedFileState.java +++ b/app/src/main/java/foundation/e/drive/models/SyncedFileState.java @@ -17,7 +17,10 @@ import android.os.Parcelable; */ 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; protected SyncedFileState(){}; //@ToRemove. Test Only. It's to allow to make a mock SyncedFileState Class in test. private int id; @@ -27,7 +30,8 @@ public class SyncedFileState implements Parcelable { private String lastETAG; //Last got Etag for the file private long localLastModified; private long syncedFolderId; - private boolean isMediaType; //if true this is a media synchronisable else it it is a settings synchronisable. + private boolean isMediaType; // true if this is a media synchronisable else it is a settings synchronisable. + private int scannable; /** * Full constructor @@ -39,7 +43,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){ + public SyncedFileState(int 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; @@ -48,6 +52,7 @@ public class SyncedFileState implements Parcelable { this.localLastModified = lastModified; this.syncedFolderId = syncedFolderId; this.isMediaType = isMediaType; + this.scannable = scannable; } protected SyncedFileState(Parcel in) { @@ -59,6 +64,7 @@ public class SyncedFileState implements Parcelable { localLastModified = in.readLong(); syncedFolderId = in.readLong(); isMediaType = in.readByte() != 0; + scannable = in.readInt(); } @Override @@ -71,6 +77,7 @@ public class SyncedFileState implements Parcelable { dest.writeLong(localLastModified); dest.writeLong(syncedFolderId); dest.writeByte((byte) (isMediaType ? 1 : 0)); + dest.writeInt(scannable); } public static final Creator CREATOR = new Creator() { @@ -152,6 +159,24 @@ public class SyncedFileState implements Parcelable { return isMediaType; } + + /** + * Return in which context the file can scan + * @return 0: not scannable. 1: scannable on ecloud. 2: scannable on device. 3: scannable everywhere + */ + public int getScannable() { + return scannable; + } + + /** + * Define in which context the file can be scan + * @param scannable 0: never. 1: on cloud only. 2: on device only. 3: in every context. + */ + public void setScannable(int scannable) { + this.scannable = scannable; + } + + @Override public String toString(){ return "SyncedFileState :" @@ -162,10 +187,10 @@ public class SyncedFileState implements Parcelable { +"\nLast Etag: "+this.lastETAG +"\nLocal last modified: "+this.localLastModified +"\nSyncedFolderId: "+this.syncedFolderId - +"\nisMediaType: "+this.isMediaType; + +"\nisMediaType: "+this.isMediaType + +"\nscannable: "+this.scannable; } - @Override public int describeContents() { return 0; -- GitLab From 5dcbe75965dce093ba36d667e12ec9f33ce4b7c7 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 14:45:31 +0100 Subject: [PATCH 08/31] Update FileEventListener and update use of SyncedFileState constructor - Update SyncedFileState constructor in ObserverService and FileEventListener - Split FileEventListener.onEvent() is 4 method: onFileDelete(File file), onFileCloseWrite(File file), onDirectoryDelete(File directory) & onDirectoryCloseWrite(File directory) --- .../FileObservers/FileEventListener.java | 155 ++++++++++-------- .../e/drive/services/ObserverService.java | 15 +- 2 files changed, 103 insertions(+), 67 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 48fd3b5d..17d6be21 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -44,79 +44,18 @@ public class FileEventListener { } public void onEvent(int event, File file) { - //@todo find a good code split for below massive block final String fileLocalPath = CommonUtils.getLocalPath(file); if (event == FileObserver.DELETE) { if (file.isDirectory()) { - SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); - if (folder == null) { - //look for parent - final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); - SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); - if (parentFolder != null ) { //if parent is in the DB - folder = new SyncedFolder(parentFolder, file.getName()+ FileUtils.PATH_SEPARATOR, file.lastModified(), ""); - folder.setEnabled(false); - DbHelper.insertSyncedFolder(folder, appContext); - } - } else { //If already in DB - if (folder.isEnabled()) { - folder.setEnabled(false); - //DbHelper.updateSyncedFolder(folder); - //@todo add the missing stuff - } - } + onDirectoryDelete(file); } else { - SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); - if (fileState != null) { //If already in DB - //if fileState is enable - //@todo add the missing stuff - //disable sync of SyncedFilestate - //@todo add the missing stuff - DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); - } + onFileDelete(file); } } else if (event == FileObserver.CLOSE_WRITE) { if (file.isDirectory()) { - SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); - if (folder == null) { //it's a directory creation - final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); - SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); - if (parentFolder != null) { //if parent is in the DB - folder = new SyncedFolder(parentFolder, file.getName()+ FileUtils.PATH_SEPARATOR, file.lastModified(), ""); - DbHelper.insertSyncedFolder(folder, appContext); - } - } else { //It's a directory update - folder.setLastModified(file.lastModified()); - //DbHelper.updateSyncedFolder(folder); - //@todo add the missing stuff - } + onDirectoryCloseWrite(file); } else { - SyncRequest request = null; - SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); - - if (fileState == null) { //New file discovered - final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); - SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); - if (parentFolder != null && parentFolder.isEnabled()) { //if parent is in the DB - final String remotePath = parentFolder.getRemoteFolder()+file.getName(); - fileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, parentFolder.getId(), parentFolder.isMediaType()); - int storedId = DbHelper.manageSyncedFileStateDB(fileState, "INSERT", appContext); - if (storedId > 0) { - fileState.setId(storedId); - request = new SyncRequest(fileState, UPLOAD); - } else { - Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); - } - } - } else { //File update - //If sync is enable - //@todo add the missing stuff - - request = new SyncRequest(fileState, UPLOAD); - } - if (request != null) { - sendSyncRequestToSynchronizationService(request); - } + onFileCloseWrite(file); } } } @@ -130,4 +69,90 @@ public class FileEventListener { appContext.unbindService(serviceConnection); } } + + private void onDirectoryCloseWrite(File directory){ + final String fileLocalPath = CommonUtils.getLocalPath(directory); + 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); + //@todo add the missing stuff + } + } + + private void onDirectoryDelete(File directory){ + final String fileLocalPath = CommonUtils.getLocalPath(directory); + SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); + if (folder == null) { + //look for parent + 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(), ""); + folder.setEnabled(false); + DbHelper.insertSyncedFolder(folder, appContext); + } + } else { //If already in DB + if (folder.isEnabled()) { + folder.setEnabled(false); + //DbHelper.updateSyncedFolder(folder); + //@todo add the missing stuff + } + } + } + + private void onFileCloseWrite(File file){ + final String fileLocalPath = CommonUtils.getLocalPath(file); + SyncRequest request = null; + SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); + + if (fileState == null) { //New file discovered + final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); + SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); + if (parentFolder != null && parentFolder.isEnabled()) { //if parent is in the DB + + int scannableValue = 0; + if (parentFolder.isEnabled()) { + if (parentFolder.isScanRemote()) scannableValue++; + if (parentFolder.isScanLocal()) scannableValue += 2; + } + + final String remotePath = parentFolder.getRemoteFolder()+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) { + fileState.setId(storedId); + request = new SyncRequest(fileState, UPLOAD); + } else { + Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); + } + } + } else { //File update + //If sync is enable + if(fileState.getScannable() > 1){ + request = new SyncRequest(fileState, UPLOAD); + } + } + if (request != null) { + sendSyncRequestToSynchronizationService(request); + } + } + + private void onFileDelete(File file){ + final String fileLocalPath = CommonUtils.getLocalPath(file); + SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); + if (fileState != null) { //If already in DB + if(fileState.getScannable() > 0){ + fileState.setScannable(0); + DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); + } + } + } } 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 90259ab9..4293182f 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -425,8 +425,13 @@ public class ObserverService extends Service implements OnRemoteOperationListene String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); //get remote file's name if (fileName != null) { + int scannableValue = 0; + if (parentFolder.isEnabled()) { + if (parentFolder.isScanRemote()) scannableValue++; + if (parentFolder.isScanLocal()) scannableValue += 2; + } //create syncedFileState - SyncedFileState newRemoteFile = new SyncedFileState(-1, fileName, parentFolder.getLocalFolder() + fileName, remoteFilePath, remoteFile.getEtag(), 0, parentFolder.getId(), parentFolder.isMediaType()); + SyncedFileState newRemoteFile = new SyncedFileState(-1, fileName, parentFolder.getLocalFolder() + fileName, remoteFilePath, remoteFile.getEtag(), 0, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); //Store it in DB int storedId = DbHelper.manageSyncedFileStateDB(newRemoteFile, "INSERT", this); @@ -700,8 +705,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.isEnabled()) { + if (syncedFolder.isScanRemote()) scannableValue++; + if (syncedFolder.isScanLocal()) scannableValue += 2; + } + //create the syncedFile State - SyncedFileState newSyncedFileState = new SyncedFileState(-1, localFile.getName(), filePath, syncedFolder.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType()); + SyncedFileState newSyncedFileState = new SyncedFileState(-1, localFile.getName(), filePath, syncedFolder.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType(),scannableValue); //Store it in DB int storedId = DbHelper.manageSyncedFileStateDB(newSyncedFileState, "INSERT", this); -- GitLab From 62029a02c8e3863150653cff8c1174bb7f3011de Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 14:52:40 +0100 Subject: [PATCH 09/31] Add 'UpdateSyncedFolder(SyncedFolder folder)' method in DBHelper. Also use it in FileEventListener. --- .../e/drive/FileObservers/FileEventListener.java | 6 ++---- .../java/foundation/e/drive/database/DbHelper.java | 14 +++++++++++++- 2 files changed, 15 insertions(+), 5 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 17d6be21..5415ca91 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -82,8 +82,7 @@ public class FileEventListener { } } else { //It's a directory update folder.setLastModified(directory.lastModified()); - //DbHelper.updateSyncedFolder(folder); - //@todo add the missing stuff + DbHelper.updateSyncedFolder(folder, appContext); } } @@ -102,8 +101,7 @@ public class FileEventListener { } else { //If already in DB if (folder.isEnabled()) { folder.setEnabled(false); - //DbHelper.updateSyncedFolder(folder); - //@todo add the missing stuff + DbHelper.updateSyncedFolder(folder, appContext); } } } diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index 545dda91..388dfce6 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -120,7 +120,6 @@ public final class DbHelper extends SQLiteOpenHelper { } dao.close(); } - return result; } @@ -182,6 +181,19 @@ public final class DbHelper extends SQLiteOpenHelper { return result; } + + public static int updateSyncedFolder(SyncedFolder syncedFolder, Context context) { + int result = -1; + //Connect to DB + SyncedFolderDAO dao = openSyncedFolderDAO(context, true); + if(dao == null){ + return result; + } + result = dao.update( syncedFolder ); + dao.close(); + return result; + } + /** * Load SyncedFolder's from DB * @param context app or service activity -- GitLab From 6ee9f84dd35fc6507bf332833a06fefe5bf93c06 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 14:59:33 +0100 Subject: [PATCH 10/31] Add logcat input for file moves and fix coding style in FileEventListener --- .../e/drive/FileObservers/FileEventListener.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 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 5415ca91..18b95df8 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -57,6 +57,8 @@ public class FileEventListener { } else { onFileCloseWrite(file); } + } else if (event == FileObserver.MOVE_SELF){ + Log.d(TAG, file.getAbsolutePath()+" has been moved. Not handled yet"); } } @@ -70,7 +72,7 @@ public class FileEventListener { } } - private void onDirectoryCloseWrite(File directory){ + private void onDirectoryCloseWrite(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { //it's a directory creation @@ -86,7 +88,7 @@ public class FileEventListener { } } - private void onDirectoryDelete(File directory){ + private void onDirectoryDelete(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { @@ -106,7 +108,7 @@ public class FileEventListener { } } - private void onFileCloseWrite(File file){ + private void onFileCloseWrite(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); SyncRequest request = null; SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); @@ -134,7 +136,7 @@ public class FileEventListener { } } else { //File update //If sync is enable - if(fileState.getScannable() > 1){ + if (fileState.getScannable() > 1) { request = new SyncRequest(fileState, UPLOAD); } } @@ -143,11 +145,11 @@ public class FileEventListener { } } - private void onFileDelete(File file){ + private void onFileDelete(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); if (fileState != null) { //If already in DB - if(fileState.getScannable() > 0){ + if (fileState.getScannable() > 0) { fileState.setScannable(0); DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); } -- GitLab From e2fe11fd7a2ddf2e170bd61ae57a9761cd5846db Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 15:33:28 +0100 Subject: [PATCH 11/31] Fix SyncedFileState database's Table creation --- .../foundation/e/drive/database/SyncedFileStateContract.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java b/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java index 3639adab..2b91c8c3 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateContract.java @@ -37,11 +37,11 @@ class SyncedFileStateContract implements BaseColumns{ +LOCAL_LAST_MODIFIED+" INTEGER, " + SYNCEDFOLDER_ID +" INTEGER, " +IS_MEDIA_TYPE+" BOOLEAN," + +SCANNABLE+" INTEGER, " +"CONSTRAINT synced_unicity_constraint UNIQUE (" +FILE_NAME+", " +LOCAL_PATH+", " - +REMOTE_PATH+", " - +SCANNABLE + +REMOTE_PATH +"))"; static final String SQL_DELETE_TABLE_SYNCEDFILESTATE = " DROP TABLE IF EXISTS " -- GitLab From b650889b667787b6c7c8881ce9bec14d210abaf2 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 17:42:48 +0100 Subject: [PATCH 12/31] fix SQL query for getting SyncedFolder based on local path --- .../main/java/foundation/e/drive/database/SyncedFolderDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 69f6e022..d2c977b6 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java @@ -175,7 +175,7 @@ class SyncedFolderDAO { } SyncedFolder getSyncedFolderByLocalPath(String localPath){ - Cursor cursor = mDB.query(TABLE_NAME, allColumns, LOCAL_PATH+" = "+localPath, new String[0], null, null, null); + Cursor cursor = mDB.query(TABLE_NAME, allColumns, LOCAL_PATH+" like \""+localPath+"\"", new String[0], null, null, null); cursor.moveToFirst(); SyncedFolder result = null; if ( !cursor.isAfterLast() ) { -- GitLab From 0bae203e5aa0afb35ba73ebed39adfba22039d00 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 18:15:54 +0100 Subject: [PATCH 13/31] Add logcat debug msg for fileEvent --- .../foundation/e/drive/FileObservers/FileEventListener.java | 4 ++++ 1 file changed, 4 insertions(+) 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 18b95df8..cc68168b 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -74,6 +74,7 @@ public class FileEventListener { private void onDirectoryCloseWrite(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); + Log.d(TAG, "onDirectoryCloseWrite("+fileLocalPath+")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { //it's a directory creation final String parentPath = CommonUtils.getLocalPath(directory.getParentFile()); @@ -90,6 +91,7 @@ public class FileEventListener { private void onDirectoryDelete(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); + Log.d(TAG, "onDirectoryDelete("+fileLocalPath+")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { //look for parent @@ -110,6 +112,7 @@ public class FileEventListener { private void onFileCloseWrite(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); + Log.d(TAG, "onFileCloseWrite("+fileLocalPath+")"); SyncRequest request = null; SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); @@ -147,6 +150,7 @@ public class FileEventListener { private void onFileDelete(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); + Log.d(TAG, "onFileDelete("+fileLocalPath+")"); SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); if (fileState != null) { //If already in DB if (fileState.getScannable() > 0) { -- GitLab From d59d83937f9764d21fc4a082c034be984553bb1c Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 17:10:30 +0100 Subject: [PATCH 14/31] Change moment where ObserverService try to bind to SynchronizationService. - Change binding of ObserverService to SynchronizationService. - Fix coding style and remove spaces --- .../java/foundation/e/drive/EdriveApplication.java | 1 - .../foundation/e/drive/services/ObserverService.java | 10 ++++------ .../drive/utils/SynchronizationServiceConnection.java | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/EdriveApplication.java b/app/src/main/java/foundation/e/drive/EdriveApplication.java index 65120303..7944bad6 100644 --- a/app/src/main/java/foundation/e/drive/EdriveApplication.java +++ b/app/src/main/java/foundation/e/drive/EdriveApplication.java @@ -32,7 +32,6 @@ public class EdriveApplication extends Application { private static final String TAG = "EdriveApplication"; private RecursiveFileObserver mFileObserver = null; - @Override public void onCreate() { super.onCreate(); 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 4293182f..7d034b9c 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -78,13 +78,17 @@ public class ObserverService extends Service implements OnRemoteOperationListene @Override public void onDestroy(){ Log.i(TAG, "onDestroy()"); + unbindService(synchronizationServiceConnection); super.onDestroy(); this.mSyncedFolders = null; } + @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); + final Intent SynchronizationServiceIntent = new Intent(this.getApplicationContext(), SynchronizationService.class); + bindService(SynchronizationServiceIntent, synchronizationServiceConnection, Context.BIND_AUTO_CREATE); CommonUtils.setServiceUnCaughtExceptionHandler(this); @@ -318,12 +322,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene } private void passSyncRequestsToSynchronizationService() { - final Intent SynchronizationServiceIntent = new Intent(this.getApplicationContext(), SynchronizationService.class); - bindService(SynchronizationServiceIntent, synchronizationServiceConnection, Context.BIND_AUTO_CREATE); - if (synchronizationServiceConnection.isBoundToSynchronizationService()) { synchronizationServiceConnection.getSynchronizationService().queueOperations(syncRequests.values()); - unbindService(synchronizationServiceConnection); } else { Log.e(TAG, "ERROR: impossible to bind ObserverService to SynchronizationService"); } @@ -630,8 +630,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } } //end of iterator loop - - if (contentToSyncFound) { DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, diff --git a/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java b/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java index db0fe194..7f828ff9 100644 --- a/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java +++ b/app/src/main/java/foundation/e/drive/utils/SynchronizationServiceConnection.java @@ -26,7 +26,7 @@ public class SynchronizationServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { - Log.i(TAG, "onServiceDisconnected: binding to SynchronizationService"); + Log.i(TAG, "onServiceConnected: binding to SynchronizationService"); SynchronizationService.SynchronizationBinder binder = (SynchronizationService.SynchronizationBinder) iBinder; synchronizationService = binder.getService(); boundToSynchronizationService = true; -- GitLab From 3b95b92e6a914b4e21e654113242af5abe3f6956 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 18:41:41 +0100 Subject: [PATCH 15/31] Correctly bound ObserverService to SynchronizationService Also add return START_NOT_STICKY for ObserverService and call synchronizationService.startSynchronization() after adding syncRequest. --- .../java/foundation/e/drive/services/ObserverService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 7d034b9c..a84cb696 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -87,7 +87,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); - final Intent SynchronizationServiceIntent = new Intent(this.getApplicationContext(), SynchronizationService.class); + final Intent SynchronizationServiceIntent = new Intent(this, SynchronizationService.class); bindService(SynchronizationServiceIntent, synchronizationServiceConnection, Context.BIND_AUTO_CREATE); CommonUtils.setServiceUnCaughtExceptionHandler(this); @@ -152,7 +152,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene this.syncRequests = new HashMap<>(); begin(); - return super.onStartCommand( intent, flags, startId ); + return START_NOT_STICKY; } /* Common methods */ @@ -324,6 +324,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene private void passSyncRequestsToSynchronizationService() { if (synchronizationServiceConnection.isBoundToSynchronizationService()) { synchronizationServiceConnection.getSynchronizationService().queueOperations(syncRequests.values()); + synchronizationServiceConnection.getSynchronizationService().startSynchronization(); } else { Log.e(TAG, "ERROR: impossible to bind ObserverService to SynchronizationService"); } -- GitLab From 00afb4ea760b2d378a9b577ea77d8b2ce49e69d2 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 17 Mar 2022 18:47:42 +0100 Subject: [PATCH 16/31] Update FileEventListener to trigger SynchronizationService.startWorker() Also: - remove useless String variable in onEvent() - Move Binding and unbinding to ObserverService in onEvent() --- .../e/drive/FileObservers/FileEventListener.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 cc68168b..e61fca9e 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -44,7 +44,9 @@ public class FileEventListener { } public void onEvent(int event, File file) { - final String fileLocalPath = CommonUtils.getLocalPath(file); + final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); + appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); + if (event == FileObserver.DELETE) { if (file.isDirectory()) { onDirectoryDelete(file); @@ -60,15 +62,13 @@ public class FileEventListener { } else if (event == FileObserver.MOVE_SELF){ Log.d(TAG, file.getAbsolutePath()+" has been moved. Not handled yet"); } + appContext.unbindService(serviceConnection); } private void sendSyncRequestToSynchronizationService(SyncRequest request) { - final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); - appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); - if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); - appContext.unbindService(serviceConnection); + serviceConnection.getSynchronizationService().startSynchronization(); } } -- GitLab From 7abf9d48df723cf41015250414e667b02e068c78 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 18 Mar 2022 12:21:15 +0100 Subject: [PATCH 17/31] Fix: Account was null in SynchronizationService --- .../e/drive/services/SynchronizationService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 7593485c..e03d4a55 100644 --- a/app/src/main/java/foundation/e/drive/services/SynchronizationService.java +++ b/app/src/main/java/foundation/e/drive/services/SynchronizationService.java @@ -66,16 +66,17 @@ public class SynchronizationService extends Service implements OnRemoteOperation public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand()"); - final SharedPreferences prefs = getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); + final String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); + final String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); + account = CommonUtils.getAccount(accountName, accountType, AccountManager.get(this)); - if (prefs.getString(AccountManager.KEY_ACCOUNT_NAME, null) == null) { + if (account == null) { Log.w(TAG, "No account available. Stop SynchronizationService"); stopSelf(); return START_NOT_STICKY; } - - account = (Account) intent.getParcelableExtra("account"); syncedRequestQueue = new ConcurrentLinkedDeque<>(); startedOperations = new Hashtable<>(); threadPool = new Thread[workerAmount]; -- GitLab From ea145df6ac8d184342150daeeea0dd0673803931 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 18 Mar 2022 12:40:52 +0100 Subject: [PATCH 18/31] add more debug output in FileEventListener --- .../e/drive/FileObservers/FileEventListener.java | 13 ++++++++++--- 1 file changed, 10 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 e61fca9e..bf5cc19c 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -44,8 +44,6 @@ public class FileEventListener { } public void onEvent(int event, File file) { - final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); - appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); if (event == FileObserver.DELETE) { if (file.isDirectory()) { @@ -54,21 +52,27 @@ public class FileEventListener { onFileDelete(file); } } else if (event == FileObserver.CLOSE_WRITE) { + final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); + appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); + if (file.isDirectory()) { onDirectoryCloseWrite(file); } else { onFileCloseWrite(file); } + appContext.unbindService(serviceConnection); } else if (event == FileObserver.MOVE_SELF){ Log.d(TAG, file.getAbsolutePath()+" has been moved. Not handled yet"); } - appContext.unbindService(serviceConnection); } private void sendSyncRequestToSynchronizationService(SyncRequest request) { + Log.d(TAG, "Sending a SyncRequest for "+request.getSyncedFileState().getName()); if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); serviceConnection.getSynchronizationService().startSynchronization(); + }else{ + Log.w(TAG, "Impossible to send SyncRequest. FileEventListener not bound to SynchronizationService"); } } @@ -137,6 +141,9 @@ public class FileEventListener { Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); } } + else{ + Log.w(TAG, "Won't send sync request: no parent are known for new file: "+file.getName()); + } } else { //File update //If sync is enable if (fileState.getScannable() > 1) { -- GitLab From 2bedff55c5b5fc25d2f156a167ba6af084e982fa Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 18 Mar 2022 13:38:38 +0100 Subject: [PATCH 19/31] Fix SyncedFileStateDAO.getSyncedFolderByLocalPath() --- .../java/foundation/e/drive/database/SyncedFolderDAO.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 d2c977b6..c70be5e5 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFolderDAO.java @@ -29,6 +29,8 @@ import static foundation.e.drive.database.SyncedFolderContract.SCANREMOTE; import static foundation.e.drive.database.SyncedFolderContract.IS_MEDIA_TYPE; import static foundation.e.drive.database.SyncedFolderContract.TABLE_NAME; +import com.owncloud.android.lib.resources.files.FileUtils; + /** * @author Vincent Bourgmayer * Source: https://vogella.developpez.com/tutoriels/android/utilisation-base-donnees-sqlite/ @@ -175,7 +177,7 @@ class SyncedFolderDAO { } SyncedFolder getSyncedFolderByLocalPath(String localPath){ - Cursor cursor = mDB.query(TABLE_NAME, allColumns, LOCAL_PATH+" like \""+localPath+"\"", new String[0], null, null, null); + Cursor cursor = mDB.query(TABLE_NAME, allColumns, LOCAL_PATH+" like \""+localPath+ FileUtils.PATH_SEPARATOR+"\"", new String[0], null, null, null); cursor.moveToFirst(); SyncedFolder result = null; if ( !cursor.isAfterLast() ) { -- GitLab From 896fb786c761fbd1e65fb22e4f412b99ee3ff608 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 18 Mar 2022 13:41:07 +0100 Subject: [PATCH 20/31] Fix SyncedFileStateDAO method for SCANNABLE column - Add SCANNABLE colum in selection when missing - Fix coding style in method corrected - Update toContentValues(SyncedFileState) to include SCANNABLE's value - Fix Typo in cursorToSyncedFileState(Cursor) --- .../e/drive/database/SyncedFileStateDAO.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) 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 031a2726..9864b9de 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.List; import foundation.e.drive.models.SyncedFileState; + +import static foundation.e.drive.database.SyncedFileStateContract.SCANNABLE; import static foundation.e.drive.database.SyncedFileStateContract.TABLE_NAME; import static foundation.e.drive.database.SyncedFileStateContract.FILE_NAME; import static foundation.e.drive.database.SyncedFileStateContract.IS_MEDIA_TYPE; @@ -65,7 +67,7 @@ class SyncedFileStateDAO { * @param syncedFileState syncedFileState to convert * @return a ContentValues object */ - private ContentValues toContentValues(SyncedFileState syncedFileState){ + private ContentValues toContentValues(SyncedFileState syncedFileState) { ContentValues values = new ContentValues(); values.put( FILE_NAME, syncedFileState.getName() ); values.put( LOCAL_PATH, syncedFileState.getLocalPath() ); @@ -74,6 +76,7 @@ class SyncedFileStateDAO { values.put( LOCAL_LAST_MODIFIED, syncedFileState.getLocalLastModified() ); values.put( SYNCEDFOLDER_ID, syncedFileState.getSyncedFolderId() ); values.put( IS_MEDIA_TYPE, syncedFileState.isMediaType() ? 1 : 0 ); + values.put( SCANNABLE, syncedFileState.getScannable()); return values; } @@ -132,7 +135,7 @@ class SyncedFileStateDAO { * @param syncedFolderids List of path to filter. Need to be directory path * @return List List of SyncedFileState filtered on syncedFolder ID. */ - List getBySyncedFolderID(List syncedFolderids){ + List getBySyncedFolderID(List syncedFolderids) { String query = "Select " +SyncedFileStateContract._ID+", " +FILE_NAME+", " @@ -141,10 +144,11 @@ class SyncedFileStateDAO { +LAST_ETAG+", " +LOCAL_LAST_MODIFIED+", " + SYNCEDFOLDER_ID+", " - + IS_MEDIA_TYPE + + IS_MEDIA_TYPE+", " + + SCANNABLE +" FROM " +TABLE_NAME; - if(syncedFolderids.size() > 0) { + if (syncedFolderids.size() > 0) { query+=" WHERE "; for (int i = -1, idsSize = syncedFolderids.size(); ++i < idsSize; ) { @@ -171,8 +175,8 @@ class SyncedFileStateDAO { * @param path local path or remote path * @return SyncedFileState obtain by the query or null if none has been found */ - SyncedFileState getByPath(String path, boolean isLocalPath){ - String query = "Select " + SyncedFileState getByPath(String path, boolean isLocalPath) { + String query = "Select " +SyncedFileStateContract._ID+", " +FILE_NAME+", " +LOCAL_PATH+", " @@ -180,10 +184,11 @@ class SyncedFileStateDAO { +LAST_ETAG+", " +LOCAL_LAST_MODIFIED+", " + SYNCEDFOLDER_ID+", " - + IS_MEDIA_TYPE+ + + IS_MEDIA_TYPE+", " + + SCANNABLE+ " FROM " +TABLE_NAME+" WHERE "; - if(isLocalPath) + if (isLocalPath) query+=LOCAL_PATH ; else query+=REMOTE_PATH ; @@ -193,7 +198,7 @@ class SyncedFileStateDAO { Cursor cursor = mDB.rawQuery(query, null); cursor.moveToFirst(); SyncedFileState syncedFileState = null; - if( !cursor.isAfterLast()) { + if ( !cursor.isAfterLast()) { syncedFileState = cursorToSyncedFileState(cursor); } cursor.close(); @@ -215,7 +220,7 @@ class SyncedFileStateDAO { cursor.getLong(5 ),//Local last modified cursor.getLong(6 ), //SyncedFolderID (cursor.getInt(7) == 1), //is Media Type - cursor.getInt(7) //scannable + cursor.getInt(8) //scannable ); } } -- GitLab From 003be26c921b3c7c96e971ce7605c504c63353b8 Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 09:26:29 +0000 Subject: [PATCH 21/31] Apply 1 suggestion(s) to 1 file(s) --- .../foundation/e/drive/FileObservers/FileEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bf5cc19c..3c646b93 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -62,7 +62,7 @@ public class FileEventListener { } appContext.unbindService(serviceConnection); } else if (event == FileObserver.MOVE_SELF){ - Log.d(TAG, file.getAbsolutePath()+" has been moved. Not handled yet"); + Log.d(TAG, file.getAbsolutePath() + " has been moved. Not handled yet"); } } -- GitLab From 547c64818e26f0434d1e2647abc31858eb67f2d4 Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 09:26:43 +0000 Subject: [PATCH 22/31] Apply 1 suggestion(s) to 1 file(s) --- .../foundation/e/drive/FileObservers/FileEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3c646b93..fbaba351 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -67,7 +67,7 @@ public class FileEventListener { } private void sendSyncRequestToSynchronizationService(SyncRequest request) { - Log.d(TAG, "Sending a SyncRequest for "+request.getSyncedFileState().getName()); + Log.d(TAG, "Sending a SyncRequest for " + request.getSyncedFileState().getName()); if (serviceConnection.isBoundToSynchronizationService()) { serviceConnection.getSynchronizationService().queueOperation(request); serviceConnection.getSynchronizationService().startSynchronization(); -- GitLab From ead655f9c77a8804282604918f15a7398e8d0eed Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 09:26:51 +0000 Subject: [PATCH 23/31] Apply 1 suggestion(s) to 1 file(s) --- .../foundation/e/drive/FileObservers/FileEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fbaba351..9b0f7f32 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -78,7 +78,7 @@ public class FileEventListener { private void onDirectoryCloseWrite(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); - Log.d(TAG, "onDirectoryCloseWrite("+fileLocalPath+")"); + Log.d(TAG, "onDirectoryCloseWrite(" + fileLocalPath + ")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { //it's a directory creation final String parentPath = CommonUtils.getLocalPath(directory.getParentFile()); -- GitLab From 37c05b56d707b7ea2c7d1451762791e945b528e7 Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 09:27:01 +0000 Subject: [PATCH 24/31] Apply 1 suggestion(s) to 1 file(s) --- .../foundation/e/drive/FileObservers/FileEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9b0f7f32..46ba38b2 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -84,7 +84,7 @@ public class FileEventListener { 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(), ""); + folder = new SyncedFolder(parentFolder, directory.getName() + FileUtils.PATH_SEPARATOR, directory.lastModified(), ""); DbHelper.insertSyncedFolder(folder, appContext); } } else { //It's a directory update -- GitLab From 3afa5908850958d19d6fb6bd8c7856bf14e62d5a Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Mar 2022 10:32:02 +0100 Subject: [PATCH 25/31] rename private functions in FileEventListener --- .../drive/FileObservers/FileEventListener.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 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 46ba38b2..b3ed68c7 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -19,7 +19,6 @@ import android.util.Log; import com.owncloud.android.lib.resources.files.FileUtils; import java.io.File; -import java.util.ArrayList; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncRequest; @@ -47,18 +46,18 @@ public class FileEventListener { if (event == FileObserver.DELETE) { if (file.isDirectory()) { - onDirectoryDelete(file); + handleDirectoryDelete(file); } else { - onFileDelete(file); + handleFileDelete(file); } } else if (event == FileObserver.CLOSE_WRITE) { final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); if (file.isDirectory()) { - onDirectoryCloseWrite(file); + handleDirectoryCloseWrite(file); } else { - onFileCloseWrite(file); + handleFileCloseWrite(file); } appContext.unbindService(serviceConnection); } else if (event == FileObserver.MOVE_SELF){ @@ -76,7 +75,7 @@ public class FileEventListener { } } - private void onDirectoryCloseWrite(File directory) { + private void handleDirectoryCloseWrite(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); Log.d(TAG, "onDirectoryCloseWrite(" + fileLocalPath + ")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); @@ -93,7 +92,7 @@ public class FileEventListener { } } - private void onDirectoryDelete(File directory) { + private void handleDirectoryDelete(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); Log.d(TAG, "onDirectoryDelete("+fileLocalPath+")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); @@ -114,7 +113,7 @@ public class FileEventListener { } } - private void onFileCloseWrite(File file) { + private void handleFileCloseWrite(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); Log.d(TAG, "onFileCloseWrite("+fileLocalPath+")"); SyncRequest request = null; @@ -155,7 +154,7 @@ public class FileEventListener { } } - private void onFileDelete(File file) { + private void handleFileDelete(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); Log.d(TAG, "onFileDelete("+fileLocalPath+")"); SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); -- GitLab From b99102ea69ba577c16866cc70cac8298d9a7c6da Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Mar 2022 11:42:10 +0100 Subject: [PATCH 26/31] Change moment where FileEventListener bind and unbind to SynchronizationService --- .../foundation/e/drive/EdriveApplication.java | 11 +++++++---- .../e/drive/FileObservers/FileEventListener.java | 16 +++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/EdriveApplication.java b/app/src/main/java/foundation/e/drive/EdriveApplication.java index 7944bad6..e36b5752 100644 --- a/app/src/main/java/foundation/e/drive/EdriveApplication.java +++ b/app/src/main/java/foundation/e/drive/EdriveApplication.java @@ -31,16 +31,17 @@ public class EdriveApplication extends Application { private static final String TAG = "EdriveApplication"; private RecursiveFileObserver mFileObserver = null; + private FileEventListener fileEventListener; @Override public void onCreate() { super.onCreate(); - + fileEventListener = new FileEventListener(getApplicationContext()); Log.i(TAG, "Starting"); resetOperationManagerSetting(); final String pathForObserver = Environment.getExternalStorageDirectory().getAbsolutePath(); - mFileObserver = new RecursiveFileObserver(getApplicationContext(), pathForObserver, new FileEventListener(getApplicationContext())); + mFileObserver = new RecursiveFileObserver(getApplicationContext(), pathForObserver, fileEventListener); SharedPreferences prefs = getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); @@ -76,8 +77,9 @@ public class EdriveApplication extends Application { */ public void startRecursiveFileObserver(){ if (!mFileObserver.isWatching()) { + fileEventListener.bindToSynchronizationService(); mFileObserver.startWatching(); - Log.d(TAG, "Starting RecursiveFileObserver on media's root folder"); + Log.d(TAG, "Starting RecursiveFileObserver on root folder"); } else { Log.w(TAG, "RecursiveFileObserver (for media's root folder) was already running"); @@ -86,7 +88,8 @@ public class EdriveApplication extends Application { public void stopRecursiveFileObserver(){ mFileObserver.stopWatching(); - Log.d(TAG, "RecursiveFileObserver on media's root folder stops watching "); + fileEventListener.unbindFromSynchronizationService(); + Log.d(TAG, "RecursiveFileObserver on root folder stops watching "); } @Override 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 b3ed68c7..08a2ce6c 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -43,7 +43,6 @@ public class FileEventListener { } public void onEvent(int event, File file) { - if (event == FileObserver.DELETE) { if (file.isDirectory()) { handleDirectoryDelete(file); @@ -51,15 +50,12 @@ public class FileEventListener { handleFileDelete(file); } } else if (event == FileObserver.CLOSE_WRITE) { - final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); - appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); if (file.isDirectory()) { handleDirectoryCloseWrite(file); } else { handleFileCloseWrite(file); } - appContext.unbindService(serviceConnection); } else if (event == FileObserver.MOVE_SELF){ Log.d(TAG, file.getAbsolutePath() + " has been moved. Not handled yet"); } @@ -71,7 +67,7 @@ public class FileEventListener { serviceConnection.getSynchronizationService().queueOperation(request); serviceConnection.getSynchronizationService().startSynchronization(); }else{ - Log.w(TAG, "Impossible to send SyncRequest. FileEventListener not bound to SynchronizationService"); + Log.w(TAG, "Impossible to send SyncRequest. FileEventListener is not bound to SynchronizationService"); } } @@ -165,4 +161,14 @@ public class FileEventListener { } } } + + public void unbindFromSynchronizationService(){ + appContext.unbindService(serviceConnection); + } + + public void bindToSynchronizationService(){ + Log.d(TAG, "bindToSynchronizationService()"); + final Intent SynchronizationServiceIntent = new Intent(appContext, SynchronizationService.class); + appContext.bindService(SynchronizationServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); + } } -- GitLab From e32d82e0bbec2493b9ae95537598036ebd69cb5f Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Mar 2022 12:53:43 +0100 Subject: [PATCH 27/31] Change method name in FileEventListener logcat.d(TAG, "methodName") --- .../e/drive/FileObservers/FileEventListener.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 08a2ce6c..ca56c14e 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -73,7 +73,7 @@ public class FileEventListener { private void handleDirectoryCloseWrite(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); - Log.d(TAG, "onDirectoryCloseWrite(" + fileLocalPath + ")"); + 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()); @@ -90,7 +90,7 @@ public class FileEventListener { private void handleDirectoryDelete(File directory) { final String fileLocalPath = CommonUtils.getLocalPath(directory); - Log.d(TAG, "onDirectoryDelete("+fileLocalPath+")"); + Log.d(TAG, "handleDirectoryDelete("+fileLocalPath+")"); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { //look for parent @@ -111,7 +111,7 @@ public class FileEventListener { private void handleFileCloseWrite(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); - Log.d(TAG, "onFileCloseWrite("+fileLocalPath+")"); + Log.d(TAG, "handleFileCloseWrite("+fileLocalPath+")"); SyncRequest request = null; SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); @@ -152,7 +152,7 @@ public class FileEventListener { private void handleFileDelete(File file) { final String fileLocalPath = CommonUtils.getLocalPath(file); - Log.d(TAG, "onFileDelete("+fileLocalPath+")"); + Log.d(TAG, "handleFileDelete("+fileLocalPath+")"); SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); if (fileState != null) { //If already in DB if (fileState.getScannable() > 0) { -- GitLab From 9960bf82d9f210c9451497fdda30d689366853a4 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Mar 2022 13:26:21 +0100 Subject: [PATCH 28/31] fix crash due to unbinding FileEvent from SynchronizationService if not bound --- .../foundation/e/drive/FileObservers/FileEventListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 ca56c14e..0903e22b 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -163,7 +163,10 @@ public class FileEventListener { } public void unbindFromSynchronizationService(){ - appContext.unbindService(serviceConnection); + if(serviceConnection.isBoundToSynchronizationService()) + appContext.unbindService(serviceConnection); + else + Log.w(TAG, "Not bound to SynchronizationService: can't unbind."); } public void bindToSynchronizationService(){ -- GitLab From 3e9f9eefb33db785453c8bad07901cc1bc606d2e Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 15:39:30 +0000 Subject: [PATCH 29/31] Apply 1 suggestion(s) to 1 file(s) --- app/src/main/java/foundation/e/drive/database/DbHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index 388dfce6..c096316c 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -261,7 +261,7 @@ public final class DbHelper extends SQLiteOpenHelper { public static SyncedFolder getSyncedFolderByLocalPath(String localPath, Context context){ SyncedFolderDAO dao = openSyncedFolderDAO(context, true); - if(dao == null){ + if (dao == null) { return null; } SyncedFolder syncedFolder = dao.getSyncedFolderByLocalPath(localPath); -- GitLab From 1a0d534b7876f7c98b40090bdfcff4cbbb03dd77 Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Mon, 21 Mar 2022 15:40:26 +0000 Subject: [PATCH 30/31] Apply 1 suggestion(s) to 1 file(s) --- app/src/main/java/foundation/e/drive/database/DbHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index c096316c..383c5fdb 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -186,7 +186,7 @@ public final class DbHelper extends SQLiteOpenHelper { int result = -1; //Connect to DB SyncedFolderDAO dao = openSyncedFolderDAO(context, true); - if(dao == null){ + if (dao == null){ return result; } result = dao.update( syncedFolder ); -- GitLab From 1d01c2a35f7abd5238bdcfed38160c1913a25f71 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 21 Mar 2022 17:00:07 +0100 Subject: [PATCH 31/31] get rid of nested condition --- .../FileObservers/FileEventListener.java | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 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 0903e22b..a4a0b634 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -118,29 +118,26 @@ public class FileEventListener { if (fileState == null) { //New file discovered final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); - if (parentFolder != null && parentFolder.isEnabled()) { //if parent is in the DB - - int scannableValue = 0; - if (parentFolder.isEnabled()) { - if (parentFolder.isScanRemote()) scannableValue++; - if (parentFolder.isScanLocal()) scannableValue += 2; - } - - final String remotePath = parentFolder.getRemoteFolder()+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) { - fileState.setId(storedId); - request = new SyncRequest(fileState, UPLOAD); - } else { - Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); - } - } - else{ + if (parentFolder == null || !parentFolder.isEnabled()) { Log.w(TAG, "Won't send sync request: no parent are known for new file: "+file.getName()); + return; + } + int scannableValue = 0; + if (parentFolder.isEnabled()) { + if (parentFolder.isScanRemote()) scannableValue++; + if (parentFolder.isScanLocal()) scannableValue += 2; + } + + final String remotePath = parentFolder.getRemoteFolder()+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) { + fileState.setId(storedId); + request = new SyncRequest(fileState, UPLOAD); + } else { + Log.w(TAG, "New File " + file.getName() + " observed but impossible to insert it in DB"); } } else { //File update - //If sync is enable if (fileState.getScannable() > 1) { request = new SyncRequest(fileState, UPLOAD); } @@ -154,11 +151,15 @@ public class FileEventListener { final String fileLocalPath = CommonUtils.getLocalPath(file); Log.d(TAG, "handleFileDelete("+fileLocalPath+")"); SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); - if (fileState != null) { //If already in DB - if (fileState.getScannable() > 0) { - fileState.setScannable(0); - DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); - } + if (fileState == null) { + Log.d(TAG, "Ignore event because file is not already in database"); + return; + } + + //If already in DB + if (fileState.getScannable() > 0) { + fileState.setScannable(0); + DbHelper.manageSyncedFileStateDB(fileState, "UPDATE", appContext); } } -- GitLab