From 9c43a9d8b83810ef33403c66c0291a0fcb883cf2 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 5 Aug 2021 08:46:07 +0530 Subject: [PATCH 01/38] continue whit old code for schedule scanner job --- .../foundation/e/drive/utils/JobUtils.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/utils/JobUtils.java b/app/src/main/java/foundation/e/drive/utils/JobUtils.java index 213b1e9f..2958bea7 100644 --- a/app/src/main/java/foundation/e/drive/utils/JobUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/JobUtils.java @@ -32,23 +32,23 @@ public abstract class JobUtils { */ public static void scheduleScannerJob(Context context){ Log.i(TAG, "scheduleJob"); - Log.i(TAG, "scheduleJob task off"); + /* I. Start periodic checkup */ -// ComponentName jobService = new ComponentName( context, ScannerJob.class ); -// -// JobInfo job = new JobInfo.Builder(ScannerJobId, jobService ) -// .setPeriodic(1860000, 30000) //31git minutes and 30 secondes -// .setPersisted(true) -// .setRequiredNetworkType( JobInfo.NETWORK_TYPE_ANY ) -// .build(); -// -// JobScheduler jobScheduler = context.getSystemService( JobScheduler.class ); -// -// if ( jobScheduler.schedule( job ) == JobScheduler.RESULT_SUCCESS ) { -// Log.d(TAG, "Scheduled job created"); -// } else { -// Log.e(TAG, "Scheduled job not created"); -// } + ComponentName jobService = new ComponentName( context, ScannerJob.class ); + + JobInfo job = new JobInfo.Builder(ScannerJobId, jobService ) + .setPeriodic(7200000 , 30000) //31git minutes and 30 secondes + .setPersisted(true) + .setRequiredNetworkType( JobInfo.NETWORK_TYPE_ANY ) + .build(); + + JobScheduler jobScheduler = context.getSystemService( JobScheduler.class ); + + if ( jobScheduler.schedule( job ) == JobScheduler.RESULT_SUCCESS ) { + Log.d(TAG, "Scheduled job created"); + } else { + Log.e(TAG, "Scheduled job not created"); + } } /** -- GitLab From 07fc6c5a536af242d85143c7a7f239ff4af92ebb Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 5 Aug 2021 11:05:17 +0530 Subject: [PATCH 02/38] continue whit old code for schedule scanner job --- app/src/main/java/foundation/e/drive/utils/JobUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/utils/JobUtils.java b/app/src/main/java/foundation/e/drive/utils/JobUtils.java index 2958bea7..a33855fa 100644 --- a/app/src/main/java/foundation/e/drive/utils/JobUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/JobUtils.java @@ -37,7 +37,7 @@ public abstract class JobUtils { ComponentName jobService = new ComponentName( context, ScannerJob.class ); JobInfo job = new JobInfo.Builder(ScannerJobId, jobService ) - .setPeriodic(7200000 , 30000) //31git minutes and 30 secondes + .setPeriodic(7200000 , 30000) //2 hr .setPersisted(true) .setRequiredNetworkType( JobInfo.NETWORK_TYPE_ANY ) .build(); -- GitLab From ef43998626715e07a1265a8cc5f90699fbbf75d8 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 9 Aug 2021 09:52:08 +0530 Subject: [PATCH 03/38] initialization --- .../e/drive/services/FileObserverService.java | 27 ++++++++++++------- .../e/drive/services/ObserverService.java | 4 +++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 964fe206..58f059e5 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -55,16 +55,23 @@ public class FileObserverService extends Service { if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ Log.d("OnEvent", "...Event ..." + event+"...file ..." + file); - try - { - if(observerFlag == -1){ - new AsyncTaskRunner().execute(""); - } - } - catch (Exception e) - { - e.printStackTrace(); - } + + //Check internet + // Add event in List + //call to ObserverService >> getSyncedFileState >> HandleLocal File + + + +// try +// { +// if(observerFlag == -1){ +// new AsyncTaskRunner().execute(""); +// } +// } +// catch (Exception e) +// { +// e.printStackTrace(); +// } } } 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 dfd2873e..16598f22 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -628,6 +628,10 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } + + //Create function about getSyncedFileState input List from Database + //call handleLocalFiles + /** * This function determine the action to do depending for each file or syncedFileState * If file has already be synced and modified since last synced then update (= upload) -- GitLab From e23d7aa64ea5b483f326dac82323814e6b556dfa Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Sat, 28 Aug 2021 09:40:58 +0530 Subject: [PATCH 04/38] call handleLocalFiles and skip scanLocalFiles --- .../e/drive/models/FileObserver.java | 33 ++++++++++++++++ .../e/drive/services/FileObserverService.java | 39 +++++++++++++------ .../e/drive/services/InitializerService.java | 3 ++ .../e/drive/services/ObserverService.java | 23 ++++++++--- .../foundation/e/drive/utils/CommonUtils.java | 27 +++++++++++++ 5 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/models/FileObserver.java diff --git a/app/src/main/java/foundation/e/drive/models/FileObserver.java b/app/src/main/java/foundation/e/drive/models/FileObserver.java new file mode 100644 index 00000000..dde77187 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/models/FileObserver.java @@ -0,0 +1,33 @@ +package foundation.e.drive.models; + +import java.io.File; +import java.io.Serializable; +import java.util.List; + +public class FileObserver implements Serializable { + + private List files; + + private List syncedFileStatesList; + + public FileObserver(List files, List syncedFileStatesList) { + this.files = files; + this.syncedFileStatesList = syncedFileStatesList; + } + + public List getFiles() { + return files; + } + + public void setFiles(List files) { + this.files = files; + } + + public List getSyncedFileStatesList() { + return syncedFileStatesList; + } + + public void setSyncedFileStatesList(List syncedFileStatesList) { + this.syncedFileStatesList = syncedFileStatesList; + } +} diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 58f059e5..a0a887b1 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -16,7 +16,12 @@ import android.support.annotation.Nullable; import android.util.Log; import java.io.File; +import java.util.ArrayList; +import java.util.List; +import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.RecursiveFileObserver; public class FileObserverService extends Service { @@ -24,7 +29,8 @@ public class FileObserverService extends Service { RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; - + List syncedFileStatesList=new ArrayList<>(); + List files=new ArrayList<>(); @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -56,22 +62,29 @@ public class FileObserverService extends Service { Log.d("OnEvent", "...Event ..." + event+"...file ..." + file); + SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getAbsolutePath(), true); + + syncedFileStatesList.add(syncedFileStates); + files.add(file); //Check internet + // Add event in List + //InitializerService.fileObserver.add(file); //call to ObserverService >> getSyncedFileState >> HandleLocal File -// try -// { -// if(observerFlag == -1){ -// new AsyncTaskRunner().execute(""); -// } -// } -// catch (Exception e) -// { -// e.printStackTrace(); -// } + try + { + if(observerFlag == -1){ + + new AsyncTaskRunner().execute(""); + } + } + catch (Exception e) + { + e.printStackTrace(); + } } } @@ -123,7 +136,10 @@ public class FileObserverService extends Service { public void run() { // Log.e("onPostExecute", "...ObserverService Intent..." ); // Do something after 20s = 20000ms + Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); + observersServiceIntent.putExtra("isFileObserverService", true); + observersServiceIntent.putExtra("fileObserverObject", new foundation.e.drive.models.FileObserver(files, syncedFileStatesList)); startService(observersServiceIntent); observerFlag=-1; @@ -132,6 +148,7 @@ public class FileObserverService extends Service { } + } diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index ad556cea..4e172cbb 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -28,6 +28,7 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -61,6 +62,8 @@ public class InitializerService extends Service private int restartFolderCreationCounter =0; private ConnectivityReceiver connectivityReceiver; + // public static List fileObserver=new ArrayList<>(); + @Override public void onCreate() { Log.i(TAG, "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 16598f22..18c4670f 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -69,6 +69,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene private int initialFolderCounter; private Account mAccount; private HashMap operationsForIntent; + private Boolean isFileObserverService; + private foundation.e.drive.models.FileObserver fileObserverObject; /* Lifecycle Methods */ @Override @@ -82,6 +84,14 @@ public class ObserverService extends Service implements OnRemoteOperationListene public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); + try { + isFileObserverService = (Boolean)intent.getExtras().get("isFileObserverService"); + fileObserverObject = (foundation.e.drive.models.FileObserver)intent.getExtras().get("fileObserverObject"); + + }catch (Exception ex){ + ex.printStackTrace(); + } + CommonUtils.setServiceUnCaughtExceptionHandler(this); SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); @@ -239,7 +249,14 @@ public class ObserverService extends Service implements OnRemoteOperationListene return; } } else { - scanLocalFiles(); + if(isFileObserverService){ + + handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); + + }else { + scanLocalFiles(); + } + } } @@ -628,10 +645,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } - - //Create function about getSyncedFileState input List from Database - //call handleLocalFiles - /** * This function determine the action to do depending for each file or syncedFileState * If file has already be synced and modified since last synced then update (= upload) diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 2d1c16e2..6c5e1d86 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -30,7 +30,12 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.resources.files.FileUtils; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import foundation.e.drive.receivers.ScreenOffReceiver; @@ -291,4 +296,26 @@ public abstract class CommonUtils { + "\n File can be read?: " + f.canRead() + "\n File can be written?: " + f.canWrite(); } + + /* + this function convert object to bytes + */ + private byte[] convertToBytes(Object object) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos)) { + out.writeObject(object); + return bos.toByteArray(); + } + } + + /* + this function convert bytes to Object + */ + private Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bis)) { + return in.readObject(); + } + } + } \ No newline at end of file -- GitLab From fe90bc08e3c4fd3caef620e792fef1b50aa8c541 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 30 Aug 2021 11:18:29 +0530 Subject: [PATCH 05/38] improve bundle value --- .../e/drive/services/FileObserverService.java | 15 +++++++++++---- .../e/drive/services/ObserverService.java | 17 ++++++++++++----- .../foundation/e/drive/utils/CommonUtils.java | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index a0a887b1..44c4a046 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -137,10 +137,17 @@ public class FileObserverService extends Service { // Log.e("onPostExecute", "...ObserverService Intent..." ); // Do something after 20s = 20000ms - Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); - observersServiceIntent.putExtra("isFileObserverService", true); - observersServiceIntent.putExtra("fileObserverObject", new foundation.e.drive.models.FileObserver(files, syncedFileStatesList)); - startService(observersServiceIntent); + try { + Log.e("TAG", "========================================="); + Log.e("TAG", "File Observer to Observer services....."); + Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); + observersServiceIntent.putExtra("isFileObserverService", true); + observersServiceIntent.putExtra("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files, syncedFileStatesList))); + startService(observersServiceIntent); + }catch (Exception exception){ + exception.printStackTrace(); + } + observerFlag=-1; } 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 18c4670f..ba48062a 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -15,6 +15,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; @@ -69,7 +70,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene private int initialFolderCounter; private Account mAccount; private HashMap operationsForIntent; - private Boolean isFileObserverService; + private Boolean isFileObserverService=false; private foundation.e.drive.models.FileObserver fileObserverObject; /* Lifecycle Methods */ @@ -85,8 +86,12 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.i(TAG, "onStartCommand("+startId+")"); try { - isFileObserverService = (Boolean)intent.getExtras().get("isFileObserverService"); - fileObserverObject = (foundation.e.drive.models.FileObserver)intent.getExtras().get("fileObserverObject"); + Bundle bundle = intent.getExtras(); + if(null!=bundle){ + isFileObserverService = bundle.getBoolean("isFileObserverService"); + fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); + } + }catch (Exception ex){ ex.printStackTrace(); @@ -546,7 +551,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene * Prepare the list of files and SyncedFileState for synchronisation */ private void scanLocalFiles(){ - Log.i( TAG, "scanLocalFiles()" ); + Log.e( TAG, "========================================================" ); + Log.e( TAG, "scanLocalFiles()" ); List fileList = new ArrayList<>(); List folderIdList= new ArrayList<>(); boolean contentToSyncFound = false; @@ -654,7 +660,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene * @param syncedFileStates List of SyncedFileState to scan */ private void handleLocalFiles(List localFileList, List syncedFileStates ){ - Log.i(TAG, "handleLocalFiles()"); + Log.e( TAG, "========================================================" ); + Log.e(TAG, "handleLocalFiles()"); Log.d(TAG, "Loop through local file list"); Log.v(TAG, "format: filePath, exist, lastModified) :"); diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 6c5e1d86..98a9841b 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -300,7 +300,7 @@ public abstract class CommonUtils { /* this function convert object to bytes */ - private byte[] convertToBytes(Object object) throws IOException { + public static byte[] convertToBytes(Object object) throws IOException { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos)) { out.writeObject(object); @@ -311,7 +311,7 @@ public abstract class CommonUtils { /* this function convert bytes to Object */ - private Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException { + public static Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException { try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(bis)) { return in.readObject(); -- GitLab From a8941f28f3c41a5197cc09ec08aa8d138aa73aae Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 1 Sep 2021 07:40:16 +0530 Subject: [PATCH 06/38] intent put extra bundle value File ObserverService to ObserverService --- .../e/drive/models/SyncedFileState.java | 4 +- .../e/drive/services/FileObserverService.java | 51 +++++++++++-------- .../e/drive/services/ObserverService.java | 4 +- 3 files changed, 33 insertions(+), 26 deletions(-) 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..3b9255be 100644 --- a/app/src/main/java/foundation/e/drive/models/SyncedFileState.java +++ b/app/src/main/java/foundation/e/drive/models/SyncedFileState.java @@ -11,12 +11,14 @@ package foundation.e.drive.models; import android.os.Parcel; import android.os.Parcelable; +import java.io.Serializable; + /** * @author Vincent Bourgmayer * Describe a file state which will be Synchronized (= Synced) or which has already been synced one times */ -public class SyncedFileState implements Parcelable { +public class SyncedFileState implements Parcelable, Serializable { protected SyncedFileState(){}; //@ToRemove. Test Only. It's to allow to make a mock SyncedFileState Class in test. diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 44c4a046..1efb0b7d 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -5,6 +5,7 @@ import android.app.Service; import android.content.Intent; import android.os.AsyncTask; import android.os.Build; +import android.os.Bundle; import android.os.Environment; import android.os.FileObserver; @@ -130,28 +131,34 @@ public class FileObserverService extends Service { super.onPostExecute(s); // Log.d("onPostExecute", "...ObserverService Intent...post Execute " ); - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - // Log.e("onPostExecute", "...ObserverService Intent..." ); - // Do something after 20s = 20000ms - - try { - Log.e("TAG", "========================================="); - Log.e("TAG", "File Observer to Observer services....."); - Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); - observersServiceIntent.putExtra("isFileObserverService", true); - observersServiceIntent.putExtra("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files, syncedFileStatesList))); - startService(observersServiceIntent); - }catch (Exception exception){ - exception.printStackTrace(); - } - - - observerFlag=-1; - } - }, 20000); + try { + Log.e("TAG", "========================================="); + Log.e("TAG", "File Observer to Observer services....."); + Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); + + Bundle mBundle = new Bundle(); + mBundle.putBoolean("isFileObserverService", true); + mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files, syncedFileStatesList))); + observersServiceIntent.putExtras(mBundle); + startService(observersServiceIntent); + }catch (Exception exception){ + exception.printStackTrace(); + } + observerFlag=-1; + +// final Handler handler = new Handler(); +// handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// // Log.e("onPostExecute", "...ObserverService Intent..." ); +// // Do something after 20s = 20000ms +// +// +// +// +// +// } +// }, 20000); } 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 ba48062a..ec1f0588 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -91,8 +91,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene isFileObserverService = bundle.getBoolean("isFileObserverService"); fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); } - - }catch (Exception ex){ ex.printStackTrace(); } @@ -255,7 +253,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } else { if(isFileObserverService){ - + Log.e("TAG", "isFileObserverService................"+isFileObserverService); handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); }else { -- GitLab From f2f56c046aee112a79f3d7128e32e64885c1680e Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 1 Sep 2021 13:19:46 +0530 Subject: [PATCH 07/38] null check --- .../e/drive/services/FileObserverService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 1efb0b7d..f43a84cb 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -63,18 +63,20 @@ public class FileObserverService extends Service { Log.d("OnEvent", "...Event ..." + event+"...file ..." + file); - SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getAbsolutePath(), true); + SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getPath(), true); - syncedFileStatesList.add(syncedFileStates); + if(null!=syncedFileStates){ + syncedFileStatesList.add(syncedFileStates); + + } files.add(file); + //Check internet // Add event in List //InitializerService.fileObserver.add(file); //call to ObserverService >> getSyncedFileState >> HandleLocal File - - try { if(observerFlag == -1){ -- GitLab From 7ae2731fc2fc29a2746e9d7d9e85ff7e2e50c356 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 2 Sep 2021 17:03:40 +0530 Subject: [PATCH 08/38] SyncedFileState is null --- .../java/foundation/e/drive/services/FileObserverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index f43a84cb..88bfe329 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -62,7 +62,7 @@ public class FileObserverService extends Service { if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ Log.d("OnEvent", "...Event ..." + event+"...file ..." + file); - + //getting null SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getPath(), true); if(null!=syncedFileStates){ -- GitLab From 764a385cca5e001f6fe380eac38c5c9bd13f3996 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 6 Sep 2021 11:35:49 +0530 Subject: [PATCH 09/38] manage HandleLocalFiles function values --- .../e/drive/models/FileObserver.java | 20 +++++------ .../e/drive/services/FileObserverService.java | 34 +++++++++++++------ .../e/drive/services/ObserverService.java | 18 +++++++++- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/models/FileObserver.java b/app/src/main/java/foundation/e/drive/models/FileObserver.java index dde77187..9b5e76fc 100644 --- a/app/src/main/java/foundation/e/drive/models/FileObserver.java +++ b/app/src/main/java/foundation/e/drive/models/FileObserver.java @@ -8,11 +8,11 @@ public class FileObserver implements Serializable { private List files; - private List syncedFileStatesList; + //private List syncedFileStatesList; - public FileObserver(List files, List syncedFileStatesList) { + public FileObserver(List files) { this.files = files; - this.syncedFileStatesList = syncedFileStatesList; + } public List getFiles() { @@ -23,11 +23,11 @@ public class FileObserver implements Serializable { this.files = files; } - public List getSyncedFileStatesList() { - return syncedFileStatesList; - } - - public void setSyncedFileStatesList(List syncedFileStatesList) { - this.syncedFileStatesList = syncedFileStatesList; - } +// public List getSyncedFileStatesList() { +// return syncedFileStatesList; +// } +// +// public void setSyncedFileStatesList(List syncedFileStatesList) { +// this.syncedFileStatesList = syncedFileStatesList; +// } } diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 88bfe329..e945fb01 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -20,17 +20,15 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import foundation.e.drive.database.DbHelper; -import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.RecursiveFileObserver; public class FileObserverService extends Service { - + private final static String TAG = FileObserverService.class.getSimpleName(); RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; - List syncedFileStatesList=new ArrayList<>(); + //List syncedFileStatesList=new ArrayList<>(); List files=new ArrayList<>(); @Override @@ -60,15 +58,29 @@ public class FileObserverService extends Service { //Modify =2, create =256, delete =512, movedTo =128 if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ - Log.d("OnEvent", "...Event ..." + event+"...file ..." + file); + Log.e("OnEvent", "...Event ..." + event+"...file ..." + file); //getting null - SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getPath(), true); - - if(null!=syncedFileStates){ - syncedFileStatesList.add(syncedFileStates); - } +// +// SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getPath(), true); +// +// if(null==syncedFileStates){ +// syncedFileStates = new SyncedFileState(-1, file.getName(), file.getPath(), file.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType()); +// +// //Store it in DB +// int storedId = DbHelper.manageSyncedFileStateDB(newSyncedFileState, "INSERT", this); +// if(storedId > 0){ +// newSyncedFileState.setId( storedId ); +// Log.i(TAG, "Add upload operation for new file "+storedId); +// //create UploadOperation and add it into bundle +// UploadFileOperation uploadOperation = new UploadFileOperation(newSyncedFileState, syncedFolder.isScanRemote()); +// this.operationsForIntent.put(storedId, uploadOperation); +// }else{ +// Log.w(TAG, "The new file to synced cannot be store in DB. Ignore it"); +// } +// } +// syncedFileStatesList.add(syncedFileStates); files.add(file); //Check internet @@ -140,7 +152,7 @@ public class FileObserverService extends Service { Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); - mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files, syncedFileStatesList))); + mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); observersServiceIntent.putExtras(mBundle); startService(observersServiceIntent); }catch (Exception exception){ 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 ec1f0588..27de0072 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -254,7 +254,22 @@ public class ObserverService extends Service implements OnRemoteOperationListene } else { if(isFileObserverService){ Log.e("TAG", "isFileObserverService................"+isFileObserverService); - handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); + + //mSyncedFolders we have here + + //we can get getIdsFromFolderToScan + + List files = fileObserverObject.getFiles(); + DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. + + List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, + getIdsFromFolderToScan()); + + if(!syncedFileStates.isEmpty() || !files.isEmpty() ) { + handleLocalFiles(files, syncedFileStates); + } + + // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); }else { scanLocalFiles(); @@ -640,6 +655,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene if(contentToSyncFound) { DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. + List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, folderIdList); -- GitLab From 0cb8b6260420b5caf46c843ca51ef3d3fb042f54 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Tue, 7 Sep 2021 20:00:42 +0530 Subject: [PATCH 10/38] manage Files List before and after upload --- .../e/drive/operations/UploadFileOperation.java | 12 ++++++++++++ .../e/drive/services/FileObserverService.java | 14 ++++++++++---- .../e/drive/services/InitializerService.java | 1 + .../e/drive/services/ObserverService.java | 15 +++++---------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 88276a6b..0ded25fa 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -25,6 +25,7 @@ import java.io.File; import java.util.ArrayList; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.services.InitializerService; import foundation.e.drive.utils.CommonUtils; /** @@ -136,6 +137,17 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp //if upload is a success if( uploadResult.isSuccess() ){ + Log.e(TAG, "upload is success ........................."+file.getName() + +" "+file.getAbsolutePath()); + + + Log.e(TAG, "files size before remove ........................."+InitializerService.files.size()); + + InitializerService.files.remove(file); + + Log.e(TAG, "files size after remove ........................."+InitializerService.files.size()); + + Object data = uploadResult.getSingleData(); if(data != null){ mSyncedState.setLastETAG((String) data); diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index e945fb01..ac48298f 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -23,13 +23,15 @@ import java.util.List; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.RecursiveFileObserver; + + public class FileObserverService extends Service { private final static String TAG = FileObserverService.class.getSimpleName(); RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; //List syncedFileStatesList=new ArrayList<>(); - List files=new ArrayList<>(); + @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -81,7 +83,12 @@ public class FileObserverService extends Service { // } // } // syncedFileStatesList.add(syncedFileStates); - files.add(file); + + if(!InitializerService.files.contains(file)){ + Log.e(TAG, "adding new file into files list "+file.getName() +" .... "+file.getAbsolutePath()); + InitializerService.files.add(file); + } + //Check internet @@ -92,7 +99,6 @@ public class FileObserverService extends Service { try { if(observerFlag == -1){ - new AsyncTaskRunner().execute(""); } } @@ -152,7 +158,7 @@ public class FileObserverService extends Service { Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); - mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); + // mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); observersServiceIntent.putExtras(mBundle); startService(observersServiceIntent); }catch (Exception exception){ diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 4e172cbb..445467fb 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -62,6 +62,7 @@ public class InitializerService extends Service private int restartFolderCreationCounter =0; private ConnectivityReceiver connectivityReceiver; + public static List files=new ArrayList<>(); // public static List fileObserver=new ArrayList<>(); @Override 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 27de0072..ab2dff78 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -71,7 +71,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene private Account mAccount; private HashMap operationsForIntent; private Boolean isFileObserverService=false; - private foundation.e.drive.models.FileObserver fileObserverObject; + // private foundation.e.drive.models.FileObserver fileObserverObject; /* Lifecycle Methods */ @Override @@ -89,7 +89,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene Bundle bundle = intent.getExtras(); if(null!=bundle){ isFileObserverService = bundle.getBoolean("isFileObserverService"); - fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); + // fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); } }catch (Exception ex){ ex.printStackTrace(); @@ -253,20 +253,15 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } else { if(isFileObserverService){ - Log.e("TAG", "isFileObserverService................"+isFileObserverService); - //mSyncedFolders we have here - - //we can get getIdsFromFolderToScan - - List files = fileObserverObject.getFiles(); + // List files = fileObserverObject.getFiles(); DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, getIdsFromFolderToScan()); - if(!syncedFileStates.isEmpty() || !files.isEmpty() ) { - handleLocalFiles(files, syncedFileStates); + if(!syncedFileStates.isEmpty() || !InitializerService.files.isEmpty() ) { + handleLocalFiles(InitializerService.files, syncedFileStates); } // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); -- GitLab From 116808872e1cd88ae4bc658513e6898f5549cea6 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 8 Sep 2021 10:36:28 +0530 Subject: [PATCH 11/38] initialization and identity place --- .../e/drive/receivers/ConnectivityReceiver.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index 066582a4..bf9adcd4 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -36,15 +36,23 @@ public class ConnectivityReceiver public void onReceive(Context context, Intent arg1) { ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + // NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +// boolean isConnected = activeNetwork != null +// && activeNetwork.isConnectedOrConnecting(); - boolean isConnected = activeNetwork != null - && activeNetwork.isConnectedOrConnecting(); + boolean isConnected =isConnected(context); //if (connectivityReceiverListener != null) { Log.e("TAG", "ConnectivityReceiver onNetworkConnectionChanged...." + isConnected); //connectivityReceiverListener.onNetworkConnectionChanged(isConnected); //} + if(isConnected){ + + //if Scheduler flag + + //else fileObserver Flag + } + } public interface ConnectivityReceiverListener { -- GitLab From b08bf215883d1fcf0039b23c0d3040c0fc8ba866 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 8 Sep 2021 11:02:11 +0530 Subject: [PATCH 12/38] manage flag scheduler and fileObserver into ConnectivityReceiver --- .../e/drive/receivers/ConnectivityReceiver.java | 16 ++++++++++++++-- .../e/drive/services/InitializerService.java | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index bf9adcd4..407eff18 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -5,10 +5,14 @@ import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Bundle; import android.util.Log; import java.io.IOException; +import foundation.e.drive.services.FileObserverService; +import foundation.e.drive.services.InitializerService; + public class ConnectivityReceiver extends BroadcastReceiver { @@ -47,10 +51,18 @@ public class ConnectivityReceiver //connectivityReceiverListener.onNetworkConnectionChanged(isConnected); //} if(isConnected){ + Intent observersServiceIntent = new Intent(context, foundation.e.drive.services.ObserverService.class); + if(InitializerService.schedulerFlag){ - //if Scheduler flag + context.startService(observersServiceIntent); + }else if(InitializerService.fileObserverFlag) { + // + Bundle mBundle = new Bundle(); + mBundle.putBoolean("isFileObserverService", true); + observersServiceIntent.putExtras(mBundle); + context.startService(observersServiceIntent); + } - //else fileObserver Flag } } diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 445467fb..b894bc2a 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -63,7 +63,8 @@ public class InitializerService extends Service private ConnectivityReceiver connectivityReceiver; public static List files=new ArrayList<>(); - // public static List fileObserver=new ArrayList<>(); + public static boolean schedulerFlag=false; + public static boolean fileObserverFlag=false; @Override public void onCreate() { -- GitLab From 372201e6de09a65d177ad887cf6a04ec6836840a Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 8 Sep 2021 11:12:48 +0530 Subject: [PATCH 13/38] assign and Manage value to flags --- .../foundation/e/drive/jobs/ScannerJob.java | 19 ++++++-- .../drive/receivers/ConnectivityReceiver.java | 5 ++- .../e/drive/services/FileObserverService.java | 43 ++++++------------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java b/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java index 878f554b..7c014600 100644 --- a/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java +++ b/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java @@ -13,7 +13,10 @@ import android.app.job.JobService; import android.content.Intent; import android.content.IntentFilter; import android.util.Log; + +import foundation.e.drive.receivers.ConnectivityReceiver; import foundation.e.drive.receivers.ScreenOffReceiver; +import foundation.e.drive.services.InitializerService; import foundation.e.drive.services.ObserverService; import foundation.e.drive.utils.CommonUtils; @@ -32,10 +35,18 @@ public class ScannerJob extends JobService { filter.addAction(Intent.ACTION_SCREEN_OFF); getApplicationContext().registerReceiver(ScreenOffReceiver.getInstance(), filter); - Intent observerServiceIntent = new Intent(this, ObserverService.class); - this.startService(observerServiceIntent); - jobFinished(params, false); - return true; + if(ConnectivityReceiver.isConnected(getApplicationContext())){ + Intent observerServiceIntent = new Intent(this, ObserverService.class); + this.startService(observerServiceIntent); + jobFinished(params, false); + return true; + } + else { + InitializerService.fileObserverFlag=true; + return false; + } + + } /** diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index 407eff18..ae63f3dc 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -22,7 +22,7 @@ public class ConnectivityReceiver super(); } - public boolean isConnected(Context context) { + public static boolean isConnected(Context context) { // String command = "ping -c 1 e.foundation"; // return (Runtime.getRuntime().exec(command).waitFor() == 0); try { @@ -55,6 +55,7 @@ public class ConnectivityReceiver if(InitializerService.schedulerFlag){ context.startService(observersServiceIntent); + }else if(InitializerService.fileObserverFlag) { // Bundle mBundle = new Bundle(); @@ -63,6 +64,8 @@ public class ConnectivityReceiver context.startService(observersServiceIntent); } + InitializerService.schedulerFlag=false; + InitializerService.fileObserverFlag=false; } } diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index ac48298f..83c66fc9 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import foundation.e.drive.receivers.ConnectivityReceiver; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.RecursiveFileObserver; @@ -62,28 +63,6 @@ public class FileObserverService extends Service { if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ Log.e("OnEvent", "...Event ..." + event+"...file ..." + file); - //getting null - -// -// SyncedFileState syncedFileStates = DbHelper.loadSyncedFile(getApplicationContext(), file.getPath(), true); -// -// if(null==syncedFileStates){ -// syncedFileStates = new SyncedFileState(-1, file.getName(), file.getPath(), file.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType()); -// -// //Store it in DB -// int storedId = DbHelper.manageSyncedFileStateDB(newSyncedFileState, "INSERT", this); -// if(storedId > 0){ -// newSyncedFileState.setId( storedId ); -// Log.i(TAG, "Add upload operation for new file "+storedId); -// //create UploadOperation and add it into bundle -// UploadFileOperation uploadOperation = new UploadFileOperation(newSyncedFileState, syncedFolder.isScanRemote()); -// this.operationsForIntent.put(storedId, uploadOperation); -// }else{ -// Log.w(TAG, "The new file to synced cannot be store in DB. Ignore it"); -// } -// } -// syncedFileStatesList.add(syncedFileStates); - if(!InitializerService.files.contains(file)){ Log.e(TAG, "adding new file into files list "+file.getName() +" .... "+file.getAbsolutePath()); InitializerService.files.add(file); @@ -96,16 +75,22 @@ public class FileObserverService extends Service { //InitializerService.fileObserver.add(file); //call to ObserverService >> getSyncedFileState >> HandleLocal File - try - { - if(observerFlag == -1){ - new AsyncTaskRunner().execute(""); + if(ConnectivityReceiver.isConnected(getApplicationContext())){ + try + { + if(observerFlag == -1){ + new AsyncTaskRunner().execute(""); + } + } + catch (Exception e) + { + e.printStackTrace(); } } - catch (Exception e) - { - e.printStackTrace(); + else { + InitializerService.fileObserverFlag=true; } + } } -- GitLab From 697ec137f759fcf4c4793285954022188bc9de83 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 15 Sep 2021 12:13:06 +0530 Subject: [PATCH 14/38] implement handler for maintain connection --- app/src/main/AndroidManifest.xml | 1 + .../foundation/e/drive/jobs/ScannerJob.java | 2 +- .../drive/receivers/ConnectivityReceiver.java | 83 ++++++++++--------- .../e/drive/services/FileObserverService.java | 2 +- .../e/drive/services/MyApplication.java | 25 ++++++ 5 files changed, 73 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/services/MyApplication.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fafd9d3f..6a4e9cd0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ http://www.gnu.org/licenses/gpl.html android:protectionLevel="signature" /> > getSyncedFileState >> HandleLocal File - if(ConnectivityReceiver.isConnected(getApplicationContext())){ + if(ConnectivityReceiver.isConnected()){ try { if(observerFlag == -1){ diff --git a/app/src/main/java/foundation/e/drive/services/MyApplication.java b/app/src/main/java/foundation/e/drive/services/MyApplication.java new file mode 100644 index 00000000..79ae6d83 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/services/MyApplication.java @@ -0,0 +1,25 @@ +package foundation.e.drive.services; + +import android.app.Application; + +import foundation.e.drive.receivers.ConnectivityReceiver; + +public class MyApplication extends Application { + + private static MyApplication mInstance; + + @Override + public void onCreate() { + super.onCreate(); + + mInstance = this; + } + + public static synchronized MyApplication getInstance() { + return mInstance; + } + + public void setConnectivityListener(ConnectivityReceiver.ConnectivityReceiverListener listener) { + ConnectivityReceiver.connectivityReceiverListener = listener; + } +} \ No newline at end of file -- GitLab From 91470b830f5bccae1b37a540a7c570c8da5d63da Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 15 Sep 2021 13:02:15 +0530 Subject: [PATCH 15/38] remove unused tags --- .../e/drive/services/FileObserverService.java | 30 ++----------------- .../e/drive/services/ObserverService.java | 5 +--- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index b55603b9..f77708f3 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -61,20 +61,14 @@ public class FileObserverService extends Service { //Modify =2, create =256, delete =512, movedTo =128 if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ - Log.e("OnEvent", "...Event ..." + event+"...file ..." + file); + Log.i(TAG, "...Event ..." + event+"...file ..." + file); if(!InitializerService.files.contains(file)){ - Log.e(TAG, "adding new file into files list "+file.getName() +" .... "+file.getAbsolutePath()); + InitializerService.files.add(file); } - //Check internet - - // Add event in List - //InitializerService.fileObserver.add(file); - //call to ObserverService >> getSyncedFileState >> HandleLocal File - if(ConnectivityReceiver.isConnected()){ try { @@ -116,7 +110,7 @@ public class FileObserverService extends Service { @Override public void onTaskRemoved(Intent rootIntent) { - Log.d("TAG", "............onTaskRemoved"); + Log.d(TAG, "............onTaskRemoved"); super.onTaskRemoved(rootIntent); Intent intent = new Intent(this, InitializerService.class); this.startActivity(intent); @@ -134,11 +128,7 @@ public class FileObserverService extends Service { @Override protected void onPostExecute(String s) { super.onPostExecute(s); - // Log.d("onPostExecute", "...ObserverService Intent...post Execute " ); - try { - Log.e("TAG", "========================================="); - Log.e("TAG", "File Observer to Observer services....."); Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); @@ -151,20 +141,6 @@ public class FileObserverService extends Service { } observerFlag=-1; -// final Handler handler = new Handler(); -// handler.postDelayed(new Runnable() { -// @Override -// public void run() { -// // Log.e("onPostExecute", "...ObserverService Intent..." ); -// // Do something after 20s = 20000ms -// -// -// -// -// -// } -// }, 20000); - } 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 ab2dff78..c9c37220 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -559,8 +559,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene * Prepare the list of files and SyncedFileState for synchronisation */ private void scanLocalFiles(){ - Log.e( TAG, "========================================================" ); - Log.e( TAG, "scanLocalFiles()" ); + List fileList = new ArrayList<>(); List folderIdList= new ArrayList<>(); boolean contentToSyncFound = false; @@ -669,8 +668,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene * @param syncedFileStates List of SyncedFileState to scan */ private void handleLocalFiles(List localFileList, List syncedFileStates ){ - Log.e( TAG, "========================================================" ); - Log.e(TAG, "handleLocalFiles()"); Log.d(TAG, "Loop through local file list"); Log.v(TAG, "format: filePath, exist, lastModified) :"); -- GitLab From 3cc6bebb7cf61f28f378f0239dbd8c610ed1b6b7 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 15 Sep 2021 13:08:27 +0530 Subject: [PATCH 16/38] check file list onScreenReceiver and call to observerService --- .../e/drive/receivers/ScreenOffReceiver.java | 17 ++++++++++++++++- .../e/drive/services/FileObserverService.java | 1 - 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java index 519cd481..7f176017 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java @@ -11,7 +11,10 @@ package foundation.e.drive.receivers; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.util.Log; + +import foundation.e.drive.services.InitializerService; import foundation.e.drive.services.ObserverService; import foundation.e.drive.utils.CommonUtils; @@ -38,7 +41,19 @@ public class ScreenOffReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "onReceive"); - // i will use this code for check file sync list + + if(InitializerService.files.size()!=0){ + try { + Intent observersServiceIntent = new Intent(context, foundation.e.drive.services.ObserverService.class); + Bundle mBundle = new Bundle(); + mBundle.putBoolean("isFileObserverService", true); + observersServiceIntent.putExtras(mBundle); + context.startService(observersServiceIntent); + }catch (Exception exception){ + exception.printStackTrace(); + } + } + /*String intentAction = intent.getAction(); if(intentAction == null){ diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index f77708f3..514ea99c 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -130,7 +130,6 @@ public class FileObserverService extends Service { super.onPostExecute(s); try { Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); - Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); // mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); -- GitLab From 880b63056808813b61efd8a5d85845c8d5630da3 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 16 Sep 2021 12:22:01 +0530 Subject: [PATCH 17/38] remove tag for testing --- .../e/drive/operations/UploadFileOperation.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 0ded25fa..1cc78bcb 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -137,17 +137,9 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp //if upload is a success if( uploadResult.isSuccess() ){ - Log.e(TAG, "upload is success ........................."+file.getName() - +" "+file.getAbsolutePath()); - - - Log.e(TAG, "files size before remove ........................."+InitializerService.files.size()); InitializerService.files.remove(file); - Log.e(TAG, "files size after remove ........................."+InitializerService.files.size()); - - Object data = uploadResult.getSingleData(); if(data != null){ mSyncedState.setLastETAG((String) data); -- GitLab From 2a75778b2fdeb76fe04622d1b2b72faae6c07f0a Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 22 Sep 2021 11:25:08 +0530 Subject: [PATCH 18/38] update connection check for testing --- .../foundation/e/drive/jobs/ScannerJob.java | 16 +++++------- .../e/drive/services/FileObserverService.java | 26 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java b/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java index d8f8e719..762c7cd7 100644 --- a/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java +++ b/app/src/main/java/foundation/e/drive/jobs/ScannerJob.java @@ -35,16 +35,14 @@ public class ScannerJob extends JobService { filter.addAction(Intent.ACTION_SCREEN_OFF); getApplicationContext().registerReceiver(ScreenOffReceiver.getInstance(), filter); - if(ConnectivityReceiver.isConnected()){ - Intent observerServiceIntent = new Intent(this, ObserverService.class); - this.startService(observerServiceIntent); - jobFinished(params, false); - return true; - } - else { - InitializerService.fileObserverFlag=true; - return false; + Intent observerServiceIntent = new Intent(this, ObserverService.class); + this.startService(observerServiceIntent); + jobFinished(params, false); + + if(!ConnectivityReceiver.isConnected()){ + InitializerService.fileObserverFlag=false; } + return true; } diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 514ea99c..e029a43c 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -67,24 +67,22 @@ public class FileObserverService extends Service { InitializerService.files.add(file); } - - - if(ConnectivityReceiver.isConnected()){ - try - { - if(observerFlag == -1){ - new AsyncTaskRunner().execute(""); - } - } - catch (Exception e) - { - e.printStackTrace(); + if(!ConnectivityReceiver.isConnected()){ + InitializerService.fileObserverFlag=true; + } + try + { + if(observerFlag == -1){ + new AsyncTaskRunner().execute(""); } } - else { - InitializerService.fileObserverFlag=true; + catch (Exception e) + { + e.printStackTrace(); } + + } } -- GitLab From 0f69bbb2a7b230a03f04e89f7195346cf0522739 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 23 Sep 2021 12:47:24 +0530 Subject: [PATCH 19/38] update for testing --- .../e/drive/services/FileObserverService.java | 39 ++++++++++++------- .../e/drive/services/InitializerService.java | 8 ++-- .../e/drive/services/ObserverService.java | 3 ++ .../foundation/e/drive/utils/JobUtils.java | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index e029a43c..fae9f99f 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -63,23 +63,28 @@ public class FileObserverService extends Service { if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ Log.i(TAG, "...Event ..." + event+"...file ..." + file); - if(!InitializerService.files.contains(file)){ + Log.e("TAG", "file.isDirectory() ...."+file+"......"+file.isDirectory()); - InitializerService.files.add(file); - } - if(!ConnectivityReceiver.isConnected()){ - InitializerService.fileObserverFlag=true; - } - try - { - if(observerFlag == -1){ - new AsyncTaskRunner().execute(""); + if(!file.isDirectory()){ + // if(!InitializerService.files.contains(file)){ + + InitializerService.files.add(file); + // } + if(!ConnectivityReceiver.isConnected()){ + InitializerService.fileObserverFlag=true; + } + try + { + if(observerFlag == -1){ + new AsyncTaskRunner().execute(""); + } + } + catch (Exception e) + { + e.printStackTrace(); } } - catch (Exception e) - { - e.printStackTrace(); - } + @@ -127,6 +132,12 @@ public class FileObserverService extends Service { protected void onPostExecute(String s) { super.onPostExecute(s); try { + Log.e("Tag", "onPostExecute.........."); + + for(File f:InitializerService.files){ + Log.e("TAG", "...........file name in post execute.."+f.getAbsolutePath()); + } + Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index b894bc2a..06629bef 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -301,8 +301,8 @@ public class InitializerService extends Service .apply(); //all folder have been created - //JobUtils.stopScheduledJob(appContext, JobUtils.InitializerJobId); - // JobUtils.scheduleScannerJob(appContext); + JobUtils.stopScheduledJob(appContext, JobUtils.InitializerJobId); + JobUtils.scheduleScannerJob(appContext); Log.d(TAG, "RegisterReceiver: screenOffReceiver"); IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); @@ -310,8 +310,8 @@ public class InitializerService extends Service getApplicationContext().registerReceiver(ScreenOffReceiver.getInstance(), filter); //Immediatly start ObserverService to not have to wait 30 minutes. -// Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); -// startService(observersServiceIntent); + Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); + startService(observersServiceIntent); //start FileObserverService startService(new Intent(this, FileObserverService.class)); 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 c9c37220..0f62b8ad 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -254,6 +254,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene } else { if(isFileObserverService){ + Log.e("TAG", "ObserverService..isFileObserverService...."+isFileObserverService); + // List files = fileObserverObject.getFiles(); DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. @@ -671,6 +673,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.d(TAG, "Loop through local file list"); Log.v(TAG, "format: filePath, exist, lastModified) :"); + Log.e("TAG", "ObserverService..handleLocalFiles...."); //Loop through local files for(int i =-1, localFilesSize = localFileList.size(); ++i < localFilesSize;){ diff --git a/app/src/main/java/foundation/e/drive/utils/JobUtils.java b/app/src/main/java/foundation/e/drive/utils/JobUtils.java index a33855fa..a83aedb8 100644 --- a/app/src/main/java/foundation/e/drive/utils/JobUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/JobUtils.java @@ -24,7 +24,7 @@ import foundation.e.drive.jobs.ScannerJob; public abstract class JobUtils { final private static String TAG = JobUtils.class.getSimpleName(); //Tag for log public final static int ScannerJobId = 3310; - //public final static int InitializerJobId = 3311; + public final static int InitializerJobId = 3311; /** * Start the scheduledJob for observing remote's folder -- GitLab From 2cf38162f2b1cb82fb5d3331b14fe5871b581d66 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 23 Sep 2021 21:06:50 +0530 Subject: [PATCH 20/38] now it's working --- app/src/main/AndroidManifest.xml | 1 + .../drive/operations/UploadFileOperation.java | 2 +- .../e/drive/receivers/ScreenOffReceiver.java | 22 +++++++++---------- .../e/drive/services/FileObserverService.java | 12 +++++----- .../e/drive/services/InitializerService.java | 2 +- .../e/drive/services/ObserverService.java | 10 +++++---- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a4e9cd0..52b93ca7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,6 +28,7 @@ http://www.gnu.org/licenses/gpl.html android:allowBackup="true" android:icon="@mipmap/ic_eelo" android:label="@string/app_name" + android:roundIcon="@mipmap/ic_eelo_round"> syncedFileStatesList=new ArrayList<>(); + List files=new ArrayList<>(); @Override @@ -66,10 +66,10 @@ public class FileObserverService extends Service { Log.e("TAG", "file.isDirectory() ...."+file+"......"+file.isDirectory()); if(!file.isDirectory()){ - // if(!InitializerService.files.contains(file)){ + if(!files.contains(file)){ - InitializerService.files.add(file); - // } + files.add(file); + } if(!ConnectivityReceiver.isConnected()){ InitializerService.fileObserverFlag=true; } @@ -134,14 +134,14 @@ public class FileObserverService extends Service { try { Log.e("Tag", "onPostExecute.........."); - for(File f:InitializerService.files){ + for(File f:files){ Log.e("TAG", "...........file name in post execute.."+f.getAbsolutePath()); } Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); - // mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); + mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); observersServiceIntent.putExtras(mBundle); startService(observersServiceIntent); }catch (Exception exception){ diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 06629bef..05fe20e9 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -62,7 +62,7 @@ public class InitializerService extends Service private int restartFolderCreationCounter =0; private ConnectivityReceiver connectivityReceiver; - public static List files=new ArrayList<>(); + // public static List files=new ArrayList<>(); public static boolean schedulerFlag=false; public static boolean fileObserverFlag=false; 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 0f62b8ad..672342c9 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -41,6 +41,7 @@ import foundation.e.drive.database.DbHelper; import foundation.e.drive.fileFilters.CrashlogsFileFilter; import foundation.e.drive.fileFilters.FileFilterFactory; import foundation.e.drive.fileFilters.OnlyFileFilter; +import foundation.e.drive.models.FileObserver; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.operations.DownloadFileOperation; @@ -71,7 +72,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene private Account mAccount; private HashMap operationsForIntent; private Boolean isFileObserverService=false; - // private foundation.e.drive.models.FileObserver fileObserverObject; + private FileObserver fileObserverObject; + // private foundation.e.drive.models.FileObserver fileObserverObject; /* Lifecycle Methods */ @Override @@ -89,7 +91,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene Bundle bundle = intent.getExtras(); if(null!=bundle){ isFileObserverService = bundle.getBoolean("isFileObserverService"); - // fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); + fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); } }catch (Exception ex){ ex.printStackTrace(); @@ -262,8 +264,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, getIdsFromFolderToScan()); - if(!syncedFileStates.isEmpty() || !InitializerService.files.isEmpty() ) { - handleLocalFiles(InitializerService.files, syncedFileStates); + if(!syncedFileStates.isEmpty() || !fileObserverObject.getFiles().isEmpty() ) { + handleLocalFiles(fileObserverObject.getFiles(), syncedFileStates); } // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); -- GitLab From d2be27135eb7a4fcd9f8db32136b370d1202a1cc Mon Sep 17 00:00:00 2001 From: Romain Hunault Date: Fri, 24 Sep 2021 16:13:36 +0200 Subject: [PATCH 21/38] Fix CI --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ba265a2..23340a40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: "registry.gitlab.e.foundation:5000/e/apps/docker-android-apps-cicd:latest" +image: "registry.gitlab.e.foundation:5000/e/apps/docker-android-apps-cicd:legacy" stages: - build @@ -22,4 +22,3 @@ build: paths: - app/build/outputs/apk/ expire_in: 4 weeks - -- GitLab From cf3c3b4ebe121b5642341a44269a5b3905b25a0d Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 27 Sep 2021 13:00:16 +0530 Subject: [PATCH 22/38] onScreen off on sync to file list --- .../e/drive/receivers/ScreenOffReceiver.java | 23 ++++++++++--------- .../e/drive/services/FileObserverService.java | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java index 2ffb081b..e8d29f5e 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ScreenOffReceiver.java @@ -14,6 +14,7 @@ import android.content.Intent; import android.os.Bundle; import android.util.Log; +import foundation.e.drive.services.FileObserverService; import foundation.e.drive.services.InitializerService; import foundation.e.drive.services.ObserverService; import foundation.e.drive.utils.CommonUtils; @@ -42,17 +43,17 @@ public class ScreenOffReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.i(TAG, "onReceive"); -// if(InitializerService.files.size()!=0){ -// try { -// Intent observersServiceIntent = new Intent(context, foundation.e.drive.services.ObserverService.class); -// Bundle mBundle = new Bundle(); -// mBundle.putBoolean("isFileObserverService", true); -// observersServiceIntent.putExtras(mBundle); -// context.startService(observersServiceIntent); -// }catch (Exception exception){ -// exception.printStackTrace(); -// } -// } + if(FileObserverService.files.size()!=0){ + try { + Intent observersServiceIntent = new Intent(context, foundation.e.drive.services.ObserverService.class); + Bundle mBundle = new Bundle(); + mBundle.putBoolean("isFileObserverService", true); + observersServiceIntent.putExtras(mBundle); + context.startService(observersServiceIntent); + }catch (Exception exception){ + exception.printStackTrace(); + } + } /*String intentAction = intent.getAction(); diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 050254ab..ea3cc29b 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -31,7 +31,7 @@ public class FileObserverService extends Service { private final static String TAG = FileObserverService.class.getSimpleName(); RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; - List files=new ArrayList<>(); + public static List files=new ArrayList<>(); @Override -- GitLab From dda9730b09e061ac9a62b7666bba9b950d44e608 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 27 Sep 2021 14:29:17 +0530 Subject: [PATCH 23/38] remove file list item when upload done --- .../drive/operations/UploadFileOperation.java | 4 +- .../e/drive/services/ObserverService.java | 315 +++++++++--------- 2 files changed, 164 insertions(+), 155 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 24ef0fab..258cf978 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -24,7 +24,9 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo import java.io.File; import java.util.ArrayList; import foundation.e.drive.database.DbHelper; +import foundation.e.drive.models.FileObserver; import foundation.e.drive.models.SyncedFileState; +import foundation.e.drive.services.FileObserverService; import foundation.e.drive.services.InitializerService; import foundation.e.drive.utils.CommonUtils; @@ -138,7 +140,7 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp //if upload is a success if( uploadResult.isSuccess() ){ - // InitializerService.files.remove(file); + FileObserverService.files.remove(file); Object data = uploadResult.getSingleData(); if(data != null){ 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 672342c9..59ac3582 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -22,12 +22,14 @@ import android.os.Parcelable; import android.provider.MediaStore; import android.support.annotation.Nullable; import android.util.Log; + import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.lib.resources.files.model.RemoteFile; + import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; @@ -62,7 +64,7 @@ import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE * @author Vincent Bourgmayer * This service look for remote or looale file to synchronize */ -public class ObserverService extends Service implements OnRemoteOperationListener{ +public class ObserverService extends Service implements OnRemoteOperationListener { private final static String TAG = ObserverService.class.getSimpleName(); private final static int INTERSYNC_MINIMUM_DELAY = 900000; // min delay between two sync in ms. @@ -71,29 +73,29 @@ public class ObserverService extends Service implements OnRemoteOperationListene private int initialFolderCounter; private Account mAccount; private HashMap operationsForIntent; - private Boolean isFileObserverService=false; + private Boolean isFileObserverService = false; private FileObserver fileObserverObject; // private foundation.e.drive.models.FileObserver fileObserverObject; /* Lifecycle Methods */ @Override - public void onDestroy(){ + public void onDestroy() { Log.i(TAG, "onDestroy()"); super.onDestroy(); this.mSyncedFolders = null; } - + @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.i(TAG, "onStartCommand("+startId+")"); + Log.i(TAG, "onStartCommand(" + startId + ")"); try { Bundle bundle = intent.getExtras(); - if(null!=bundle){ + if (null != bundle) { isFileObserverService = bundle.getBoolean("isFileObserverService"); - fileObserverObject = (foundation.e.drive.models.FileObserver)CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); + fileObserverObject = (foundation.e.drive.models.FileObserver) CommonUtils.convertFromBytes(bundle.getByteArray("fileObserverObject")); } - }catch (Exception ex){ + } catch (Exception ex) { ex.printStackTrace(); } @@ -106,14 +108,14 @@ public class ObserverService extends Service implements OnRemoteOperationListene initialFolderCounter = prefs.getInt(AppConstants.INITIALFOLDERS_NUMBER, 0); // Check if account is invalid - if(this.mAccount == null){ + if (this.mAccount == null) { Log.w(TAG, "No account registered"); JobUtils.stopScheduledJob(this, JobUtils.ScannerJobId); //If no account return super.onStartCommand(intent, flags, startId); } //check if user have disable eDrive's sync in account's settings - if(!CommonUtils.isMediaSyncEnabled(mAccount) && !CommonUtils.isSettingsSyncEnabled(mAccount) ){ + if (!CommonUtils.isMediaSyncEnabled(mAccount) && !CommonUtils.isSettingsSyncEnabled(mAccount)) { Log.w(TAG, "eDrive syncing has been disabled in /e/ account's settings"); return super.onStartCommand(intent, flags, startId); } @@ -123,19 +125,19 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.w(TAG, "Initialization hasn't been done"); Intent initializerIntent = new Intent(this, InitializerService.class); startService(initializerIntent); - return super.onStartCommand( intent, flags, startId ); + return super.onStartCommand(intent, flags, startId); } //Check this service isn't already working - if(isWorking){ + if (isWorking) { Log.w(TAG, "ObserverService is already working"); - return super.onStartCommand(intent,flags,startId); + return super.onStartCommand(intent, flags, startId); } //check OperationManagerService isn't working - if(prefs.getBoolean(AppConstants.KEY_OMS_IS_WORKING, false)){ + if (prefs.getBoolean(AppConstants.KEY_OMS_IS_WORKING, false)) { Log.w(TAG, "OperationManagerService is still performing some operation"); - return super.onStartCommand(intent,flags, startId); + return super.onStartCommand(intent, flags, startId); } //Check a minimum delay has been respected between two start. @@ -151,19 +153,20 @@ public class ObserverService extends Service implements OnRemoteOperationListene //check for the case where intent has been launched by initializerService if (!CommonUtils.haveNetworkConnexion(this)) { Log.w(TAG, "There is no Internet connexion."); - return super.onStartCommand( intent, flags, startId ); + return super.onStartCommand(intent, flags, startId); } this.operationsForIntent = new HashMap<>(); begin(); - return super.onStartCommand( intent, flags, startId ); + return super.onStartCommand(intent, flags, startId); } /* Common methods */ + /** * Start to bind this service to OperationManagerService or start scan if binding is already set. * Method to factorise code that is called from different place */ - private void begin(){ + private void begin() { Log.i(TAG, "begin()"); this.isWorking = true; clearCachedFile(); @@ -175,7 +178,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene * This method remove all the crash-logs file * in external dir that are 10 days or more old. */ - private void deleteOldestCrashlogs(){ + private void deleteOldestCrashlogs() { Log.i(TAG, "deleteOldestCrashLogs()"); File[] fileToRemove = getExternalFilesDir(ServiceExceptionHandler.CRASH_LOG_FOLDER) .listFiles(new CrashlogsFileFilter()); @@ -185,48 +188,50 @@ public class ObserverService extends Service implements OnRemoteOperationListene try { file.delete(); ++counter; - }catch (SecurityException e){ + } catch (SecurityException e) { e.printStackTrace(); } } - Log.d(TAG, counter+" old crashlogs file.s deleted"); + Log.d(TAG, counter + " old crashlogs file.s deleted"); } /** * Clear cached file unused: * remove each cached file which isn't in OperationManagerService.lockedSyncedFileState(); + * * @TODO rewrite this method! */ - private void clearCachedFile(){ + private void clearCachedFile() { Log.i(TAG, "clearCachedFile()"); //Load subfiles into external cache file - File[] fileArray = this.getApplicationContext().getExternalCacheDir().listFiles(new OnlyFileFilter() ); - if(fileArray != null) { + File[] fileArray = this.getApplicationContext().getExternalCacheDir().listFiles(new OnlyFileFilter()); + if (fileArray != null) { boolean toRemove; for (int i = -1, size = fileArray.length; ++i < size; ) { toRemove = true; if (toRemove) { boolean deleteResult = fileArray[i].delete(); - Log.v(TAG+"_handleCachedFile()", "Deletion of cached file: " + deleteResult); + Log.v(TAG + "_handleCachedFile()", "Deletion of cached file: " + deleteResult); } } - }else{ - Log.e(TAG+"_handleCachedFile()", "Array of cached file is null"); + } else { + Log.e(TAG + "_handleCachedFile()", "Array of cached file is null"); } } /** * Start scanning job * Load operation from DB + * * @param remote if true looks for remote change. If false, look for local change. **/ private void startScan(boolean remote) { - Log.i(TAG, "startScan("+remote+")"); + Log.i(TAG, "startScan(" + remote + ")"); this.mSyncedFolders = loadSyncedFolders(); - if(mSyncedFolders.isEmpty() ){ + if (mSyncedFolders.isEmpty()) { Log.w(TAG, "List of synced folders is empty"); this.stopSelf(); return; @@ -234,7 +239,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene //Display content of SyncedFolderList StringBuilder logFolderList = new StringBuilder("SyncedFolder: libelle, localFolder, lastmodified, scanLocal, id :"); - for(SyncedFolder sf : mSyncedFolders){ + for (SyncedFolder sf : mSyncedFolders) { logFolderList.append("\n").append(sf.getLibelle()).append(", ").append(sf.getLocalFolder()).append(", ").append(sf.getLastModified()).append(", ").append(sf.isScanLocal()).append(", ").append(sf.getId()); } Log.d(TAG, logFolderList.toString()); @@ -246,31 +251,30 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.d(TAG, "Going to scan remote files"); ListFileRemoteOperation loadOperation = new ListFileRemoteOperation(this.mSyncedFolders, this, this.initialFolderCounter); loadOperation.execute(client, this, new Handler()); - } catch (IllegalArgumentException e){ - Log.e(TAG, e.toString() ); + } catch (IllegalArgumentException e) { + Log.e(TAG, e.toString()); } - }else{ + } else { Log.w(TAG, "OwnCloudClient is null"); return; } } else { - if(isFileObserverService){ + if (isFileObserverService && null != fileObserverObject) { - Log.e("TAG", "ObserverService..isFileObserverService...."+isFileObserverService); + Log.e("TAG", "ObserverService..isFileObserverService...." + isFileObserverService); - // List files = fileObserverObject.getFiles(); + // List files = fileObserverObject.getFiles(); DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, getIdsFromFolderToScan()); - if(!syncedFileStates.isEmpty() || !fileObserverObject.getFiles().isEmpty() ) { + if (!syncedFileStates.isEmpty() || !fileObserverObject.getFiles().isEmpty()) { handleLocalFiles(fileObserverObject.getFiles(), syncedFileStates); } + // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); - // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); - - }else { + } else { scanLocalFiles(); } @@ -280,37 +284,35 @@ public class ObserverService extends Service implements OnRemoteOperationListene /** * Get list of synced folder depending of if media and setting sync are enabled. + * * @return */ - private List loadSyncedFolders(){ + private List loadSyncedFolders() { boolean mediaSyncEnabled = CommonUtils.isMediaSyncEnabled(mAccount); boolean settingsSyncedEnabled = CommonUtils.isSettingsSyncEnabled(mAccount); - if(mediaSyncEnabled && settingsSyncedEnabled){ + if (mediaSyncEnabled && settingsSyncedEnabled) { return DbHelper.getAllSyncedFolders(this); - }else if(mediaSyncEnabled){ + } else if (mediaSyncEnabled) { return DbHelper.getSyncedFolderList(this, true); - }else if(settingsSyncedEnabled){ + } else if (settingsSyncedEnabled) { return DbHelper.getSyncedFolderList(this, false); - }else{ + } else { return new ArrayList(); } - } - - - - + } /** * Handle end of remote Operation + * * @param operation The RemoteOperation which ends and call this methods - * @param result The result of the remote Operation + * @param result The result of the remote Operation */ @Override - public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result ) { - Log.i( TAG, "onRemoteOperationFinish()" ); - if( operation instanceof ListFileRemoteOperation) { + public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + Log.i(TAG, "onRemoteOperationFinish()"); + if (operation instanceof ListFileRemoteOperation) { if (result.isSuccess()) { List resultDatas = result.getData(); if (resultDatas != null) { @@ -330,18 +332,18 @@ public class ObserverService extends Service implements OnRemoteOperationListene } this.startScan(false); - Log.v(TAG, "operationsForIntent contains "+ operationsForIntent.size() ); + Log.v(TAG, "operationsForIntent contains " + operationsForIntent.size()); //After everything has been scanned. Send Intent to OperationmanagerService with data in bundle - if(operationsForIntent != null && !operationsForIntent.isEmpty()) { + if (operationsForIntent != null && !operationsForIntent.isEmpty()) { Intent OMSIntent = new Intent(this, OperationManagerService.class); - for(Map.Entry entry: operationsForIntent.entrySet()){ - OMSIntent.putExtra(entry.getKey()+"", entry.getValue()); + for (Map.Entry entry : operationsForIntent.entrySet()) { + OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); } OMSIntent.putExtra("account", mAccount); startService(OMSIntent); - }else{ + } else { Log.w(TAG, "There is no file to sync."); getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) .edit() @@ -357,14 +359,15 @@ public class ObserverService extends Service implements OnRemoteOperationListene /** * Method to get Id of SyncedFolder to scan + * * @return List id of SyncedFolder to scan */ - private List getIdsFromFolderToScan(){ + private List getIdsFromFolderToScan() { List result = new ArrayList<>(); - for(int i = -1, size = this.mSyncedFolders.size(); ++i < size;){ + for (int i = -1, size = this.mSyncedFolders.size(); ++i < size; ) { SyncedFolder syncedFolder = this.mSyncedFolders.get(i); - if(syncedFolder.isToSync() ){ - result.add( (long) syncedFolder.getId() ); + if (syncedFolder.isToSync()) { + result.add((long) syncedFolder.getId()); } } return result; @@ -374,15 +377,16 @@ public class ObserverService extends Service implements OnRemoteOperationListene /** * decide what to do with remote files and decide - * @param remoteFiles Remote Files to inspect + * + * @param remoteFiles Remote Files to inspect * @param syncedFileStates SyncedFileState to inspect */ - private void handleRemoteFiles(List remoteFiles, List syncedFileStates ){ + private void handleRemoteFiles(List remoteFiles, List syncedFileStates) { Log.i(TAG, "handleRemoteFiles()"); Log.d(TAG, "start to loop through remoteFiles"); ListIterator syncedFileListIterator; - for( int i =-1, size = remoteFiles.size(); ++i < size; ){ + for (int i = -1, size = remoteFiles.size(); ++i < size; ) { final RemoteFile remoteFile = (RemoteFile) remoteFiles.get(i); final String remoteFilePath = remoteFile.getRemotePath(); @@ -391,29 +395,29 @@ public class ObserverService extends Service implements OnRemoteOperationListene boolean correspondant_found = false; syncedFileListIterator = syncedFileStates.listIterator(); //reset listiterator - Log.d( TAG, "start to loop through syncedFileList for: "+remoteFilePath); + Log.d(TAG, "start to loop through syncedFileList for: " + remoteFilePath); - while( syncedFileListIterator.hasNext() ){ + while (syncedFileListIterator.hasNext()) { SyncedFileState syncedFileState = syncedFileListIterator.next(); //ignore hidden file from db - if(syncedFileState.isMediaType() && syncedFileState.getName().startsWith(".")){ + if (syncedFileState.isMediaType() && syncedFileState.getName().startsWith(".")) { syncedFileListIterator.remove(); continue; } - Log.v(TAG, "syncedFileState.getRemotePath() :"+syncedFileState.getRemotePath() ); + Log.v(TAG, "syncedFileState.getRemotePath() :" + syncedFileState.getRemotePath()); //If syncedFileState match the remote file if (remoteFilePath.equals(syncedFileState.getRemotePath())) { - Log.d(TAG, "correspondant found for "+remoteFilePath ); + Log.d(TAG, "correspondant found for " + remoteFilePath); correspondant_found = true; if (syncedFileState.isLastEtagStored() //there is an etag stored - && (!remoteFile.getEtag().equals(syncedFileState.getLastETAG()) //If etag has changed - || syncedFileState.getLocalLastModified() == 0L)) { //File hasn't been downloaded + && (!remoteFile.getEtag().equals(syncedFileState.getLastETAG()) //If etag has changed + || syncedFileState.getLocalLastModified() == 0L)) { //File hasn't been downloaded - Log.v(TAG, "etag and localLastModified are valids for "+remoteFilePath ); + Log.v(TAG, "etag and localLastModified are valids for " + remoteFilePath); //compare size with local file if (remoteFile.getLength() == new File(syncedFileState.getLocalPath()).length()) { //length is 0 is file doesn't exist @@ -422,8 +426,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene syncedFileState.setLastETAG(remoteFile.getEtag()); int affectedRows = DbHelper.manageSyncedFileStateDB(syncedFileState, "UPDATE", this); Log.v(TAG, affectedRows + " syncedFileState.s row in DB has been updated."); - }else { - Log.i(TAG, "Add download operation for file "+syncedFileState.getId()); + } else { + Log.i(TAG, "Add download operation for file " + syncedFileState.getId()); DownloadFileOperation downloadFileOperation = new DownloadFileOperation(remoteFile, syncedFileState); this.operationsForIntent.put(syncedFileState.getId(), downloadFileOperation); } @@ -433,7 +437,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } - if( correspondant_found )continue; + if (correspondant_found) continue; //If we get here, RemoteFile is a new file to download Log.v(TAG, "SyncedFileState corresponding to remoteFile not found."); @@ -442,8 +446,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene final String parentOfKnownPath = remoteFilePath.substring(0, remoteFilePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); //look for parent folder in SyncedFolders - for (int j = -1, mSyncedFolderSize = this.mSyncedFolders.size(); ++j < mSyncedFolderSize;) { - if ( mSyncedFolders.get(j).getRemoteFolder().equals( parentOfKnownPath ) ) { //We have found the parent folder + for (int j = -1, mSyncedFolderSize = this.mSyncedFolders.size(); ++j < mSyncedFolderSize; ) { + if (mSyncedFolders.get(j).getRemoteFolder().equals(parentOfKnownPath)) { //We have found the parent folder final SyncedFolder parentFolder = mSyncedFolders.get(j); String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); //get remote file's name @@ -456,7 +460,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene int storedId = DbHelper.manageSyncedFileStateDB(newRemoteFile, "INSERT", this); if (storedId > 0) { newRemoteFile.setId(storedId); - Log.i(TAG, "Add download operation for new file "+storedId); + Log.i(TAG, "Add download operation for new file " + storedId); //Create Download operation and add it into Bundle this.operationsForIntent.put(storedId, new DownloadFileOperation(remoteFile, newRemoteFile)); @@ -473,52 +477,53 @@ public class ObserverService extends Service implements OnRemoteOperationListene } //At this step, we finished to handle each remote file and we may still have synced file but without remote equivalent. // In most cases, we consider those files as remotly removed files. So we start to delete those local file. - Log.v( TAG, "Start to handle remotly missing file" ); - handleRemoteRemainingSyncedFileState( syncedFileStates ); + Log.v(TAG, "Start to handle remotly missing file"); + handleRemoteRemainingSyncedFileState(syncedFileStates); } /** * Handle the list of syncedFileState which don't have remoteFile anymore. + * * @param syncedFileStates SyncedFileState for which no remote equivalent has been found */ - private void handleRemoteRemainingSyncedFileState(List syncedFileStates){ + private void handleRemoteRemainingSyncedFileState(List syncedFileStates) { - Log.i( TAG, "handleRemoteRemainingSyncedFileState()" ); + Log.i(TAG, "handleRemoteRemainingSyncedFileState()"); //Loop through remaining file state - for(int i = -1, size = syncedFileStates.size(); ++i < size; ){ + for (int i = -1, size = syncedFileStates.size(); ++i < size; ) { SyncedFileState syncedFileState = syncedFileStates.get(i); - if( !CommonUtils.isThisSyncAllowed( mAccount, syncedFileState.isMediaType() ) ){ - Log.d(TAG, "Sync of current file: "+syncedFileState.getName()+" isn't allowed"); + if (!CommonUtils.isThisSyncAllowed(mAccount, syncedFileState.isMediaType())) { + Log.d(TAG, "Sync of current file: " + syncedFileState.getName() + " isn't allowed"); continue; } //Check that file has already been synced fully - if( syncedFileState.isLastEtagStored() && syncedFileState.getLocalLastModified() > 0L) { + if (syncedFileState.isLastEtagStored() && syncedFileState.getLocalLastModified() > 0L) { //Get local file - File file = new File( syncedFileStates.get(i).getLocalPath() ); + File file = new File(syncedFileStates.get(i).getLocalPath()); //Try to remove local file boolean fileExists = file.exists(); - if( fileExists) { - Log.d(TAG, file.getName()+" exists *1"); + if (fileExists) { + Log.d(TAG, file.getName() + " exists *1"); //delete file int rowAffected = getContentResolver().delete(MediaStore.Files.getContentUri("external"), MediaStore.Files.FileColumns.DATA + "=?", new String[]{CommonUtils.getLocalPath(file)}); - Log.d(TAG, "deleted rows by mediastore : "+rowAffected); + Log.d(TAG, "deleted rows by mediastore : " + rowAffected); //sometimes (it seems to be relative to file's type) mediastore don't remove local file from storage fileExists = !file.delete(); } //if it succeed, remove syncedFileState in DB - if(! fileExists ) { + if (!fileExists) { //It means that file has been correctly deleted from device. So update DB. if (DbHelper.manageSyncedFileStateDB(syncedFileState, "DELETE", this) <= 0) Log.e(TAG, "SyncedFileState row hasn't been deleted from DB"); - }else - Log.w(TAG, "local file:"+file.getName()+" still exist and can't be remove"); + } else + Log.w(TAG, "local file:" + file.getName() + " still exist and can't be remove"); } } } @@ -530,74 +535,74 @@ public class ObserverService extends Service implements OnRemoteOperationListene * Generate a .txt file containing list of all installed packages with their version name * I.e : " com.android.my_example_package,7.1.2 " */ - private void generateAppListFile(){ + private void generateAppListFile() { Log.i(TAG, "generateAppListFile()"); List packagesInfo = getPackageManager().getInstalledPackages(0); StringBuilder fileContents = new StringBuilder(); - for( int i =-1, size = packagesInfo.size(); ++i < size; ){ + for (int i = -1, size = packagesInfo.size(); ++i < size; ) { PackageInfo currentPackage = packagesInfo.get(i); - fileContents.append( currentPackage.packageName).append(",").append(currentPackage.versionName).append("\n"); + fileContents.append(currentPackage.packageName).append(",").append(currentPackage.versionName).append("\n"); } try { FileOutputStream tmp = openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE); tmp.write(fileContents.toString().getBytes()); tmp.close(); - String filesdir = getFilesDir().getCanonicalPath()+PATH_SEPARATOR; - File tmp_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); - File real_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME); + String filesdir = getFilesDir().getCanonicalPath() + PATH_SEPARATOR; + File tmp_file = new File(filesdir + AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); + File real_file = new File(filesdir + AppConstants.APPLICATIONS_LIST_FILE_NAME); - if ( tmp_file.length() != real_file.length() ) { + if (tmp_file.length() != real_file.length()) { //only use tmp file if content has changed tmp_file.renameTo(real_file); } else { tmp_file.delete(); } } catch (Exception e) { - Log.e(TAG, "Can't save file with package list: "+e.toString()); + Log.e(TAG, "Can't save file with package list: " + e.toString()); } } /** * Prepare the list of files and SyncedFileState for synchronisation */ - private void scanLocalFiles(){ + private void scanLocalFiles() { List fileList = new ArrayList<>(); - List folderIdList= new ArrayList<>(); + List folderIdList = new ArrayList<>(); boolean contentToSyncFound = false; //Regenere list of application's package - if(CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile(); + if (CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile(); - ListIterator iterator = mSyncedFolders.listIterator() ; + ListIterator iterator = mSyncedFolders.listIterator(); //Loop through folders - while(iterator.hasNext() ){ + while (iterator.hasNext()) { SyncedFolder syncedFolder = iterator.next(); - Log.d(TAG, "SyncedFolder :"+syncedFolder.getLibelle()+", "+syncedFolder.getLocalFolder()+", "+syncedFolder.getLastModified()+", "+syncedFolder.isScanLocal()+", "+syncedFolder.getId() ); + Log.d(TAG, "SyncedFolder :" + syncedFolder.getLibelle() + ", " + syncedFolder.getLocalFolder() + ", " + syncedFolder.getLastModified() + ", " + syncedFolder.isScanLocal() + ", " + syncedFolder.getId()); //Check it's not a hidden file - if(syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()).startsWith(".")){ + if (syncedFolder.isMediaType() && CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()).startsWith(".")) { iterator.remove(); continue; } //Check it can be scann from local - if(!syncedFolder.isScanLocal()){ + if (!syncedFolder.isScanLocal()) { iterator.remove(); continue; } //Check if it's a new folder - if ( syncedFolder.getId() == -1) { + if (syncedFolder.getId() == -1) { Log.v(TAG, "This is a new folder, we must register it"); //persist new syncedFolder int syncedFolder_id = (int) DbHelper.insertSyncedFolder(syncedFolder, this); //It will return -1 if there is an error, like an already existing folder with same value if (syncedFolder_id > 0) { Log.v(TAG, "Folder has been registered in DB"); syncedFolder.setId(syncedFolder_id); - }else { + } else { Log.w(TAG, "syncedFolder " + syncedFolder.getLocalFolder() + " remove iterator because it hasn't been registered in DB or already stored"); iterator.remove(); continue; @@ -605,38 +610,38 @@ public class ObserverService extends Service implements OnRemoteOperationListene } //Get local folder corresponding File localFolder = new File(syncedFolder.getLocalFolder()); //Obtention du fichier local - Log.d(TAG, "Local Folder (last modified / exists): "+localFolder.lastModified()+", "+localFolder.exists() ); + Log.d(TAG, "Local Folder (last modified / exists): " + localFolder.lastModified() + ", " + localFolder.exists()); //Check if local folder exists - if(!localFolder.exists()){ + if (!localFolder.exists()) { Log.v(TAG, "local folder doesn't exist anymore . So content has change"); contentToSyncFound = true; - folderIdList.add( (long) syncedFolder.getId() ); + folderIdList.add((long) syncedFolder.getId()); continue; } boolean folderHasChange = false; //consider by default that file hadn't change //Check if folder had change - if(localFolder.lastModified() > syncedFolder.getLastModified() ) { //compare last modified date + if (localFolder.lastModified() > syncedFolder.getLastModified()) { //compare last modified date Log.v(TAG, "local folder has changed"); - syncedFolder.setLastModified( localFolder.lastModified() ); //@Todo: it would be better to set it after all it's content has been synced + syncedFolder.setLastModified(localFolder.lastModified()); //@Todo: it would be better to set it after all it's content has been synced contentToSyncFound = true; //at least one dir has changed folderHasChange = true; //The folder has change - folderIdList.add( (long) syncedFolder.getId() ); //add id into list of modified folder + folderIdList.add((long) syncedFolder.getId()); //add id into list of modified folder } //Get sub files - final FileFilter filter = FileFilterFactory.getFileFilter( (syncedFolder.isMediaType()) ? "media" : syncedFolder.getLibelle() ); + final FileFilter filter = FileFilterFactory.getFileFilter((syncedFolder.isMediaType()) ? "media" : syncedFolder.getLibelle()); File[] subElements = localFolder.listFiles(filter); //hiden media files are being ignored Log.v(TAG, "loop through subfiles"); - for (int i = -1, subEltSize = (subElements != null)? subElements.length: 0; ++i < subEltSize; ) { + for (int i = -1, subEltSize = (subElements != null) ? subElements.length : 0; ++i < subEltSize; ) { File subElt = subElements[i]; - if(subElt == null) continue; + if (subElt == null) continue; if (subElt.isDirectory()) { //if its a subfolder add it to syncedFolder list //if a subfolder is found, add it to syncedFolder list - Log.v(TAG, "subfile "+subElt.getAbsolutePath()+" is a directory."); + Log.v(TAG, "subfile " + subElt.getAbsolutePath() + " is a directory."); SyncedFolder subSyncedFolder = new SyncedFolder(syncedFolder, subElt.getName() + FileUtils.PATH_SEPARATOR, 0L, "");//Need to put 0 into to be handled on next iterati iterator.add(subSyncedFolder); iterator.previous(); @@ -651,13 +656,13 @@ public class ObserverService extends Service implements OnRemoteOperationListene } //end of iterator loop - if(contentToSyncFound) { + if (contentToSyncFound) { DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, folderIdList); - if(!syncedFileStates.isEmpty() || !fileList.isEmpty() ) { + if (!syncedFileStates.isEmpty() || !fileList.isEmpty()) { handleLocalFiles(fileList, syncedFileStates); } } @@ -668,49 +673,50 @@ public class ObserverService extends Service implements OnRemoteOperationListene * If file has already be synced and modified since last synced then update (= upload) * if file has never been synced then upload * if file has already be on server once(=> SyncedFIleState.etag is valid) and not local file exist then remove syncedFile - * @param localFileList list of local file to scan + * + * @param localFileList list of local file to scan * @param syncedFileStates List of SyncedFileState to scan */ - private void handleLocalFiles(List localFileList, List syncedFileStates ){ + private void handleLocalFiles(List localFileList, List syncedFileStates) { Log.d(TAG, "Loop through local file list"); Log.v(TAG, "format: filePath, exist, lastModified) :"); Log.e("TAG", "ObserverService..handleLocalFiles...."); //Loop through local files - for(int i =-1, localFilesSize = localFileList.size(); ++i < localFilesSize;){ + for (int i = -1, localFilesSize = localFileList.size(); ++i < localFilesSize; ) { File localFile = localFileList.get(i); - String filePath = CommonUtils.getLocalPath( localFile ); + String filePath = CommonUtils.getLocalPath(localFile); boolean correspondant_found = false; - Log.v(TAG, "Current file is "+filePath+", "+localFile.exists()+", "+localFile.lastModified() ); + Log.v(TAG, "Current file is " + filePath + ", " + localFile.exists() + ", " + localFile.lastModified()); ListIterator syncedFileListIterator = syncedFileStates.listIterator(); Log.d(TAG, "Loop through syncedFileStates "); Log.v(TAG, "format: (Path, Id, last Modified)"); - while( syncedFileListIterator.hasNext() ) { + while (syncedFileListIterator.hasNext()) { SyncedFileState syncedFileState = syncedFileListIterator.next(); //Ignore hidden media file store in DB - if(syncedFileState.isMediaType() && syncedFileState.getName().startsWith(".")){ + if (syncedFileState.isMediaType() && syncedFileState.getName().startsWith(".")) { syncedFileListIterator.remove(); continue; } - Log.v(TAG, syncedFileState.getLocalPath()+", "+syncedFileState.getId()+", "+syncedFileState.getLocalLastModified()); + Log.v(TAG, syncedFileState.getLocalPath() + ", " + syncedFileState.getId() + ", " + syncedFileState.getLocalLastModified()); //if syncedFileState correspond to local file - if( syncedFileState.getLocalPath().equals( filePath ) ){ + if (syncedFileState.getLocalPath().equals(filePath)) { correspondant_found = true; //If no etag is stored in sfs, the file hasn't been sync up to server. then do upload - if( syncedFileState.getLocalLastModified() < localFile.lastModified() || !syncedFileState.isLastEtagStored()){ - Log.d(TAG+"_handleLocalFiles()", syncedFileState.getName()+" file has been modified or never sync" ); + if (syncedFileState.getLocalLastModified() < localFile.lastModified() || !syncedFileState.isLastEtagStored()) { + Log.d(TAG + "_handleLocalFiles()", syncedFileState.getName() + " file has been modified or never sync"); boolean checkEtag = false; //Look for folder to know if the folder can be scan remotly. - for(int folderIndex =-1, size = mSyncedFolders.size();++folderIndex < size;) { + for (int folderIndex = -1, size = mSyncedFolders.size(); ++folderIndex < size; ) { final SyncedFolder syncedFolder = mSyncedFolders.get(folderIndex); if (syncedFolder.getId() == syncedFileState.getSyncedFolderId()) { @@ -719,8 +725,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene break; } } - Log.i(TAG, "Add upload operation for file "+syncedFileState.getId()); - UploadFileOperation uploadFileOperation = new UploadFileOperation(syncedFileState, checkEtag ); + Log.i(TAG, "Add upload operation for file " + syncedFileState.getId()); + UploadFileOperation uploadFileOperation = new UploadFileOperation(syncedFileState, checkEtag); this.operationsForIntent.put(syncedFileState.getId(), uploadFileOperation); } // No need to reloop on it. @@ -728,7 +734,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene break; } } - if( correspondant_found ) continue; + if (correspondant_found) continue; //if no correspondance, then it is a new file Log.v(TAG, "this is a new file to sync"); @@ -737,20 +743,20 @@ public class ObserverService extends Service implements OnRemoteOperationListene final String parentPath = filePath.substring(0, filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1); //look into synced folders if folder path exist - for(SyncedFolder syncedFolder : mSyncedFolders){ - if(syncedFolder.getLocalFolder().equals(parentPath)){ + for (SyncedFolder syncedFolder : mSyncedFolders) { + if (syncedFolder.getLocalFolder().equals(parentPath)) { //create the syncedFile State SyncedFileState newSyncedFileState = new SyncedFileState(-1, localFile.getName(), filePath, syncedFolder.getRemoteFolder() + localFile.getName(), "", 0, syncedFolder.getId(), syncedFolder.isMediaType()); //Store it in DB int storedId = DbHelper.manageSyncedFileStateDB(newSyncedFileState, "INSERT", this); - if(storedId > 0){ - newSyncedFileState.setId( storedId ); - Log.i(TAG, "Add upload operation for new file "+storedId); + if (storedId > 0) { + newSyncedFileState.setId(storedId); + Log.i(TAG, "Add upload operation for new file " + storedId); //create UploadOperation and add it into bundle UploadFileOperation uploadOperation = new UploadFileOperation(newSyncedFileState, syncedFolder.isScanRemote()); this.operationsForIntent.put(storedId, uploadOperation); - }else{ + } else { Log.w(TAG, "The new file to synced cannot be store in DB. Ignore it"); } break; @@ -758,25 +764,26 @@ public class ObserverService extends Service implements OnRemoteOperationListene }//end of loop over folder }//end of loop over local files //Handle remaining file - handleLocalRemainingSyncedFileState( syncedFileStates ); + handleLocalRemainingSyncedFileState(syncedFileStates); } /** * manage rest of the list of syncedFilesState to look for remote file to delete + * * @param syncedFileStates List of SyncedFileState for which no local equivalent has been found */ - private void handleLocalRemainingSyncedFileState(List syncedFileStates){ + private void handleLocalRemainingSyncedFileState(List syncedFileStates) { Log.i(TAG, "handleLocalRemainingSyncedFileState(...)"); //Loop through remaining SyncedFileState - for(SyncedFileState fileState : syncedFileStates){ - if(fileState.isLastEtagStored() && fileState.getLocalLastModified() > 0L){ + for (SyncedFileState fileState : syncedFileStates) { + if (fileState.isLastEtagStored() && fileState.getLocalLastModified() > 0L) { //try to get File File file = new File(fileState.getLocalPath()); - Log.v(TAG, "File : "+file.getAbsolutePath()+","+file.exists()); - if(file.exists()){ + Log.v(TAG, "File : " + file.getAbsolutePath() + "," + file.exists()); + if (file.exists()) { Log.w(TAG, "The file still exist. There is a problem!"); - }else{ - Log.i(TAG, "Add remove operation for file "+fileState.getId()); + } else { + Log.i(TAG, "Add remove operation for file " + fileState.getId()); RemoveFileOperation removeOperation = new RemoveFileOperation(fileState); this.operationsForIntent.put(fileState.getId(), removeOperation); } -- GitLab From f51f103e446c2de4d57809e9e1d903010ef68c5c Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Tue, 28 Sep 2021 17:06:08 +0530 Subject: [PATCH 24/38] getting code for Download remote file --- .../e/drive/operations/DownloadFileRemoteOperation.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java b/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java index dce9dff6..cd5eab72 100644 --- a/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java @@ -24,6 +24,8 @@ */ package foundation.e.drive.operations; +import android.util.Log; + import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.OperationCancelledException; @@ -77,6 +79,7 @@ class DownloadFileRemoteOperation extends RemoteOperation { tmpFile.getParentFile().mkdirs(); int status = downloadFile(client, tmpFile); result = new RemoteOperationResult(isSuccess(status), mGet); + Log_OC.i(TAG, "Download of " + mRemotePath + " to " + getTmpPath() + ": " + result.getLogMessage()); @@ -120,6 +123,9 @@ class DownloadFileRemoteOperation extends RemoteOperation { fos.write(bytes, 0, readResult); transferred += readResult; } + + Log.e(TAG, "....line no..127 ..."+targetFile.getName()); + // Check if the file is completed // if transfer-encoding: chunked we cannot check if the file is complete Header transferEncodingHeader = mGet.getResponseHeader("Transfer-Encoding"); -- GitLab From 5326fdc0e3b006c44deae95dd1478d15c25995e3 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 29 Sep 2021 15:04:32 +0530 Subject: [PATCH 25/38] manage fileObserver event when data sync from server --- .../operations/DownloadFileRemoteOperation.java | 6 ++++-- .../e/drive/services/FileObserverService.java | 17 ++++++++++------- .../e/drive/services/InitializerService.java | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java b/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java index cd5eab72..c8d8a211 100644 --- a/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/DownloadFileRemoteOperation.java @@ -42,6 +42,8 @@ import java.io.IOException; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; +import foundation.e.drive.services.InitializerService; + /** * Remote operation performing the download of a remote file in the ownCloud server. * @@ -123,8 +125,8 @@ class DownloadFileRemoteOperation extends RemoteOperation { fos.write(bytes, 0, readResult); transferred += readResult; } - - Log.e(TAG, "....line no..127 ..."+targetFile.getName()); + // Log.e(TAG, "...DownLoad ...."+targetFile.getName()); + InitializerService.remoteDownloadFile.add(targetFile); // Check if the file is completed // if transfer-encoding: chunked we cannot check if the file is complete diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index ea3cc29b..059dfc55 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -32,6 +32,7 @@ public class FileObserverService extends Service { RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; public static List files=new ArrayList<>(); + private boolean remoteFileFlag; @Override @@ -63,11 +64,18 @@ public class FileObserverService extends Service { if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ Log.i(TAG, "...Event ..." + event+"...file ..." + file); - Log.e("TAG", "file.isDirectory() ...."+file+"......"+file.isDirectory()); + remoteFileFlag=false; if(!file.isDirectory()){ - if(!files.contains(file)){ + for(File remoteFile:InitializerService.remoteDownloadFile){ + if(remoteFile.getName().equals(file.getName())){ + remoteFileFlag=true; + break; + } + } + + if(!files.contains(file) && !remoteFileFlag){ files.add(file); } if(!ConnectivityReceiver.isConnected()){ @@ -132,11 +140,6 @@ public class FileObserverService extends Service { protected void onPostExecute(String s) { super.onPostExecute(s); try { - Log.e("Tag", "onPostExecute.........."); - - for(File f:files){ - Log.e("TAG", "...........file name in post execute.."+f.getAbsolutePath()); - } Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 05fe20e9..af507a38 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -62,7 +62,7 @@ public class InitializerService extends Service private int restartFolderCreationCounter =0; private ConnectivityReceiver connectivityReceiver; - // public static List files=new ArrayList<>(); + public static List remoteDownloadFile=new ArrayList<>(); public static boolean schedulerFlag=false; public static boolean fileObserverFlag=false; -- GitLab From 20675a4fa47f4d183cdc33bd0c7d7bf947799b63 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Tue, 5 Oct 2021 13:57:05 +0530 Subject: [PATCH 26/38] testing handler --- .../foundation/e/drive/receivers/ConnectivityReceiver.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index ec0dba30..13df5b33 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -17,7 +17,7 @@ import foundation.e.drive.services.MyApplication; public class ConnectivityReceiver extends BroadcastReceiver { - + private final static String TAG = ConnectivityReceiver.class.getSimpleName(); public static ConnectivityReceiverListener connectivityReceiverListener; public boolean isConnected; @@ -48,9 +48,9 @@ public class ConnectivityReceiver public void run() { isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - + Log.e(TAG, "connectivityReceiverListener...." + isConnected); if (connectivityReceiverListener != null) { - Log.e("TAG", "connectivityReceiverListener...." + isConnected); + connectivityReceiverListener.onNetworkConnectionChanged(isConnected); } -- GitLab From be619999f840b0521d31a77234b630a2f246a56d Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Fri, 8 Oct 2021 20:16:11 +0530 Subject: [PATCH 27/38] update gradle as per Android studio update resolved issue for isConnected --- .../drive/receivers/ConnectivityReceiver.java | 41 +++++++--- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 72 ++++++++++-------- gradlew.bat | 14 +--- 5 files changed, 78 insertions(+), 52 deletions(-) mode change 100644 => 100755 gradlew diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index 13df5b33..19bbd694 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -25,13 +25,34 @@ public class ConnectivityReceiver super(); } - public static boolean isConnected() { - ConnectivityManager - cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); - return activeNetwork != null - && activeNetwork.isConnectedOrConnecting(); + public static boolean isConnected() { +// ConnectivityManager +// cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext() +// .getSystemService(Context.CONNECTIVITY_SERVICE); +// NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); +// +// return activeNetwork != null +// && activeNetwork.isConnectedOrConnecting(); + + try { + String command = "ping -c 1 ecloud.global"; + return Runtime.getRuntime().exec(command).waitFor() == 0; + }catch (Exception ex){ + ex.printStackTrace(); + } + return false; + } + + public boolean isConecctedToInternet() { + + Runtime runtime = Runtime.getRuntime(); + try { + Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8"); + int exitValue = ipProcess.waitFor(); + return (exitValue == 0); + } catch (IOException e) { e.printStackTrace(); } + catch (InterruptedException e) { e.printStackTrace(); } + return false; } @@ -48,13 +69,13 @@ public class ConnectivityReceiver public void run() { isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - Log.e(TAG, "connectivityReceiverListener...." + isConnected); - if (connectivityReceiverListener != null) { + Log.e(TAG, "connectivityReceiverListener...isConnected." + isConnected()); + if (connectivityReceiverListener != null) { connectivityReceiverListener.onNetworkConnectionChanged(isConnected); } - if (isConnected) { + if (isConnected()) { Intent observersServiceIntent = new Intent(context, foundation.e.drive.services.ObserverService.class); if (InitializerService.schedulerFlag) { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372aef5e24af05341d49695ee84e5f9b594659..1948b9074f1016d15d505d185bc3f73deb82d8c8 100644 GIT binary patch delta 41671 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 MFUY_kaTvq{01Y&FlmGw# delta 40994 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%0AiFAzRin?fq{i}@`pyh`q+FSM-f}& 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282a..f9553162 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line -- GitLab From fa2349ea82789b8c77afd2bc7e186c6d71151068 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Fri, 8 Oct 2021 20:17:22 +0530 Subject: [PATCH 28/38] refine code --- .../drive/receivers/ConnectivityReceiver.java | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index 19bbd694..2be94ade 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -26,14 +26,6 @@ public class ConnectivityReceiver } public static boolean isConnected() { -// ConnectivityManager -// cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext() -// .getSystemService(Context.CONNECTIVITY_SERVICE); -// NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); -// -// return activeNetwork != null -// && activeNetwork.isConnectedOrConnecting(); - try { String command = "ping -c 1 ecloud.global"; return Runtime.getRuntime().exec(command).waitFor() == 0; @@ -43,17 +35,6 @@ public class ConnectivityReceiver return false; } - public boolean isConecctedToInternet() { - - Runtime runtime = Runtime.getRuntime(); - try { - Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8"); - int exitValue = ipProcess.waitFor(); - return (exitValue == 0); - } catch (IOException e) { e.printStackTrace(); } - catch (InterruptedException e) { e.printStackTrace(); } - return false; - } @Override @@ -70,7 +51,7 @@ public class ConnectivityReceiver isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - Log.e(TAG, "connectivityReceiverListener...isConnected." + isConnected()); + Log.e(TAG, "connectivityReceiverListener...." + isConnected()); if (connectivityReceiverListener != null) { connectivityReceiverListener.onNetworkConnectionChanged(isConnected); } -- GitLab From 30614c4bb990eae872c8a72ea4926327bf67ccc2 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Fri, 8 Oct 2021 20:29:35 +0530 Subject: [PATCH 29/38] refine code --- .../foundation/e/drive/receivers/ConnectivityReceiver.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java index 2be94ade..2b0a1501 100644 --- a/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/foundation/e/drive/receivers/ConnectivityReceiver.java @@ -26,6 +26,8 @@ public class ConnectivityReceiver } public static boolean isConnected() { + + try { String command = "ping -c 1 ecloud.global"; return Runtime.getRuntime().exec(command).waitFor() == 0; @@ -51,7 +53,7 @@ public class ConnectivityReceiver isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); - Log.e(TAG, "connectivityReceiverListener...." + isConnected()); + Log.e(TAG, "connectivityReceiverListener..." + isConnected()); if (connectivityReceiverListener != null) { connectivityReceiverListener.onNetworkConnectionChanged(isConnected); } -- GitLab From c2e923f6ffbadc861fe25fa513c64d7209c00b46 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 14 Oct 2021 11:56:55 +0530 Subject: [PATCH 30/38] uncomment for scheduleScanner --- .../java/foundation/e/drive/services/InitializerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index af507a38..bd5b1f64 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -91,7 +91,7 @@ public class InitializerService extends Service SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); if( prefs.getBoolean( AppConstants.INITIALIZATION_HAS_BEEN_DONE, false ) ) { - //JobUtils.scheduleScannerJob(this); + JobUtils.scheduleScannerJob(this); Log.w(TAG, "Initializer has already been run"); }else{ String accountName = prefs.getString( AccountManager.KEY_ACCOUNT_NAME, "" ); -- GitLab From 56291c19182de5c4133fa5a130b4d140b554ed20 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 17 Nov 2021 12:09:37 +0530 Subject: [PATCH 31/38] resolve ConcurrentModificationException --- .../e/drive/operations/UploadFileOperation.java | 8 +++++++- .../foundation/e/drive/services/FileObserverService.java | 8 ++++++-- .../foundation/e/drive/services/ObserverService.java | 9 ++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 258cf978..44495f77 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -23,6 +23,8 @@ import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import java.io.File; import java.util.ArrayList; +import java.util.Iterator; + import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.FileObserver; import foundation.e.drive.models.SyncedFileState; @@ -140,7 +142,11 @@ public class UploadFileOperation extends RemoteOperation implements ComparableOp //if upload is a success if( uploadResult.isSuccess() ){ - FileObserverService.files.remove(file); + try { + FileObserverService.files.remove(file); + }catch (Exception ex){ + ex.printStackTrace(); + } Object data = uploadResult.getSingleData(); if(data != null){ diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 059dfc55..3bed3765 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -19,6 +19,7 @@ import android.util.Log; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import foundation.e.drive.receivers.ConnectivityReceiver; import foundation.e.drive.utils.CommonUtils; @@ -31,7 +32,7 @@ public class FileObserverService extends Service { private final static String TAG = FileObserverService.class.getSimpleName(); RecursiveFileObserver mFileObserver = null; private int observerFlag=-1; - public static List files=new ArrayList<>(); + public static List files=new CopyOnWriteArrayList<>(); private boolean remoteFileFlag; @@ -144,7 +145,10 @@ public class FileObserverService extends Service { Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); - mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); + if(files.size()!=0) { + mBundle.putByteArray("fileObserverObject", CommonUtils.convertToBytes(new foundation.e.drive.models.FileObserver(files))); + } + observersServiceIntent.putExtras(mBundle); startService(observersServiceIntent); }catch (Exception exception){ 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 59ac3582..65d0e848 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -259,10 +259,9 @@ public class ObserverService extends Service implements OnRemoteOperationListene return; } } else { - if (isFileObserverService && null != fileObserverObject) { - - Log.e("TAG", "ObserverService..isFileObserverService...." + isFileObserverService); + if (isFileObserverService && null != fileObserverObject) { + Log.i(TAG, "calling observer service from event event with true and files list data"); // List files = fileObserverObject.getFiles(); DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. @@ -275,6 +274,10 @@ public class ObserverService extends Service implements OnRemoteOperationListene // handleLocalFiles(fileObserverObject.getFiles(), fileObserverObject.getSyncedFileStatesList()); } else { + Log.i(TAG, "calling observer service with false or files list data null "); + if(null!=FileObserverService.files){ + FileObserverService.files.removeAll(FileObserverService.files); + } scanLocalFiles(); } -- GitLab From 7e1ae97b054cc049434e0f9ea560cc1ace9cb56c Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Thu, 18 Nov 2021 18:31:10 +0530 Subject: [PATCH 32/38] update arrayList to CopyOnWriteArrayList --- .../java/foundation/e/drive/services/InitializerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index bd5b1f64..e04cc2ce 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -32,6 +32,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.operations.CreateInitialFolderRemoteOperation; @@ -62,7 +63,7 @@ public class InitializerService extends Service private int restartFolderCreationCounter =0; private ConnectivityReceiver connectivityReceiver; - public static List remoteDownloadFile=new ArrayList<>(); + public static List remoteDownloadFile=new CopyOnWriteArrayList<>(); public static boolean schedulerFlag=false; public static boolean fileObserverFlag=false; -- GitLab From 61a6b18e52f2f6401dea5d16af1d97119eafb2b9 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 22 Nov 2021 13:37:00 +0530 Subject: [PATCH 33/38] stop OperationManagerService and relaunch it --- .../e/drive/services/ObserverService.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 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 65d0e848..3c229071 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -137,6 +137,12 @@ public class ObserverService extends Service implements OnRemoteOperationListene //check OperationManagerService isn't working if (prefs.getBoolean(AppConstants.KEY_OMS_IS_WORKING, false)) { Log.w(TAG, "OperationManagerService is still performing some operation"); + + getApplicationContext().stopService(new Intent(getApplicationContext(), OperationManagerService.class)); + + startOperationManagerService(); + + return super.onStartCommand(intent, flags, startId); } @@ -339,13 +345,10 @@ public class ObserverService extends Service implements OnRemoteOperationListene //After everything has been scanned. Send Intent to OperationmanagerService with data in bundle if (operationsForIntent != null && !operationsForIntent.isEmpty()) { - Intent OMSIntent = new Intent(this, OperationManagerService.class); - for (Map.Entry entry : operationsForIntent.entrySet()) { - OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); - } - OMSIntent.putExtra("account", mAccount); - startService(OMSIntent); + startOperationManagerService(); + + } else { Log.w(TAG, "There is no file to sync."); getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) @@ -360,6 +363,16 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } + private void startOperationManagerService() { + Intent OMSIntent = new Intent(this, OperationManagerService.class); + for (Map.Entry entry : operationsForIntent.entrySet()) { + OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); + } + + OMSIntent.putExtra("account", mAccount); + startService(OMSIntent); + } + /** * Method to get Id of SyncedFolder to scan * -- GitLab From 766cd306438af91ecac5936db5e6bf86fc634c9c Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 22 Nov 2021 13:38:56 +0530 Subject: [PATCH 34/38] manage OMS_is_working --- .../main/java/foundation/e/drive/services/ObserverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3c229071..38bbc6fa 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -143,7 +143,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene startOperationManagerService(); - return super.onStartCommand(intent, flags, startId); + //return super.onStartCommand(intent, flags, startId); } //Check a minimum delay has been respected between two start. -- GitLab From ab9e75ce27b662ad02567f6d9b4da91444ecb968 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Mon, 22 Nov 2021 16:55:35 +0530 Subject: [PATCH 35/38] to manage OperationManagerService --- .../e/drive/services/ObserverService.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 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 38bbc6fa..01cd31c1 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -137,13 +137,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene //check OperationManagerService isn't working if (prefs.getBoolean(AppConstants.KEY_OMS_IS_WORKING, false)) { Log.w(TAG, "OperationManagerService is still performing some operation"); - - getApplicationContext().stopService(new Intent(getApplicationContext(), OperationManagerService.class)); - - startOperationManagerService(); - - - //return super.onStartCommand(intent, flags, startId); } //Check a minimum delay has been respected between two start. @@ -345,8 +338,14 @@ public class ObserverService extends Service implements OnRemoteOperationListene //After everything has been scanned. Send Intent to OperationmanagerService with data in bundle if (operationsForIntent != null && !operationsForIntent.isEmpty()) { + Intent OMSIntent = new Intent(this, OperationManagerService.class); + for (Map.Entry entry : operationsForIntent.entrySet()) { + OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); + } + + OMSIntent.putExtra("account", mAccount); + startService(OMSIntent); - startOperationManagerService(); } else { @@ -363,15 +362,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } - private void startOperationManagerService() { - Intent OMSIntent = new Intent(this, OperationManagerService.class); - for (Map.Entry entry : operationsForIntent.entrySet()) { - OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); - } - OMSIntent.putExtra("account", mAccount); - startService(OMSIntent); - } /** * Method to get Id of SyncedFolder to scan -- GitLab From a281fb3af5016e7886b96bc1be1ed5652acf9dcf Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Wed, 24 Nov 2021 13:11:27 +0530 Subject: [PATCH 36/38] to manage OperationManagerService --- .../e/drive/services/ObserverService.java | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 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 01cd31c1..f143c4e7 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -131,12 +131,20 @@ public class ObserverService extends Service implements OnRemoteOperationListene //Check this service isn't already working if (isWorking) { Log.w(TAG, "ObserverService is already working"); - return super.onStartCommand(intent, flags, startId); + getApplicationContext().stopService(new Intent(getApplicationContext(), ObserverService.class)); + // return super.onStartCommand(intent, flags, startId); + startService(new Intent(this, ObserverService.class)); } //check OperationManagerService isn't working if (prefs.getBoolean(AppConstants.KEY_OMS_IS_WORKING, false)) { Log.w(TAG, "OperationManagerService is still performing some operation"); + + getApplicationContext().stopService(new Intent(getApplicationContext(), OperationManagerService.class)); + if (operationsForIntent != null && !operationsForIntent.isEmpty()) { + startOperationManagerService(); + } + } //Check a minimum delay has been respected between two start. @@ -338,13 +346,15 @@ public class ObserverService extends Service implements OnRemoteOperationListene //After everything has been scanned. Send Intent to OperationmanagerService with data in bundle if (operationsForIntent != null && !operationsForIntent.isEmpty()) { - Intent OMSIntent = new Intent(this, OperationManagerService.class); - for (Map.Entry entry : operationsForIntent.entrySet()) { - OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); - } +// Intent OMSIntent = new Intent(this, OperationManagerService.class); +// for (Map.Entry entry : operationsForIntent.entrySet()) { +// OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); +// } +// +// OMSIntent.putExtra("account", mAccount); +// startService(OMSIntent); - OMSIntent.putExtra("account", mAccount); - startService(OMSIntent); + startOperationManagerService(); @@ -380,6 +390,16 @@ public class ObserverService extends Service implements OnRemoteOperationListene return result; } + private void startOperationManagerService() { + Intent OMSIntent = new Intent(this, OperationManagerService.class); + for (Map.Entry entry : operationsForIntent.entrySet()) { + OMSIntent.putExtra(entry.getKey() + "", entry.getValue()); + } + + OMSIntent.putExtra("account", mAccount); + startService(OMSIntent); + } + /* methods related to Server Scanning */ /** -- GitLab From 5046ab5fbef763b1aa195fecbe64700dea6982a5 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Fri, 26 Nov 2021 13:41:42 +0530 Subject: [PATCH 37/38] manage mp4 file --- .../e/drive/services/FileObserverService.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index 3bed3765..ae46a005 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -62,12 +62,18 @@ public class FileObserverService extends Service { public void onEvent(int event, File file) { //Modify =2, create =256, delete =512, movedTo =128 - if(event== FileObserver.CREATE || event==FileObserver.MODIFY || event== FileObserver.DELETE || event ==FileObserver.MOVED_TO){ + if(event== FileObserver.CREATE || + event==FileObserver.MODIFY || + event== FileObserver.DELETE || + event ==FileObserver.MOVED_TO){ + Log.i(TAG, "...Event ..." + event+"...file ..." + file); + String extension= file.getName().substring( + (file.getName().lastIndexOf('.')+1)); remoteFileFlag=false; - if(!file.isDirectory()){ + if(!file.isDirectory() & !extension.equals("mp4")){ for(File remoteFile:InitializerService.remoteDownloadFile){ if(remoteFile.getName().equals(file.getName())){ @@ -76,9 +82,15 @@ public class FileObserverService extends Service { } } + Log.e(TAG, "....... extension..."+extension); + + if(!files.contains(file) && !remoteFileFlag){ files.add(file); } + else { + return; + } if(!ConnectivityReceiver.isConnected()){ InitializerService.fileObserverFlag=true; } @@ -93,12 +105,7 @@ public class FileObserverService extends Service { e.printStackTrace(); } } - - - - } - } }); @@ -141,7 +148,7 @@ public class FileObserverService extends Service { protected void onPostExecute(String s) { super.onPostExecute(s); try { - + Log.d(TAG, "calling observerServiceIntent via fileObserver.."); Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class); Bundle mBundle = new Bundle(); mBundle.putBoolean("isFileObserverService", true); -- GitLab From 4a45e6308b38fa41612f2f17925d3789acae9629 Mon Sep 17 00:00:00 2001 From: Narinder Rana Date: Fri, 26 Nov 2021 16:08:56 +0530 Subject: [PATCH 38/38] manage file event type CLOSE_WRITE --- .../e/drive/services/FileObserverService.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/FileObserverService.java b/app/src/main/java/foundation/e/drive/services/FileObserverService.java index ae46a005..511a5195 100644 --- a/app/src/main/java/foundation/e/drive/services/FileObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/FileObserverService.java @@ -61,19 +61,22 @@ public class FileObserverService extends Service { @Override public void onEvent(int event, File file) { - //Modify =2, create =256, delete =512, movedTo =128 - if(event== FileObserver.CREATE || - event==FileObserver.MODIFY || - event== FileObserver.DELETE || - event ==FileObserver.MOVED_TO){ + if(event==FileObserver.CLOSE_WRITE){ + +// Log.e(TAG, "...CLOSE_WRITE ..." + event+"...file ..." + file); +// } +// +// +// //Modify =2, create =256, delete =512, movedTo =128 +// if(event== FileObserver.CREATE || +// event==FileObserver.MODIFY || +// event== FileObserver.DELETE || +// event ==FileObserver.MOVED_TO){ Log.i(TAG, "...Event ..." + event+"...file ..." + file); - String extension= file.getName().substring( - (file.getName().lastIndexOf('.')+1)); - remoteFileFlag=false; - if(!file.isDirectory() & !extension.equals("mp4")){ + if(!file.isDirectory() ){ for(File remoteFile:InitializerService.remoteDownloadFile){ if(remoteFile.getName().equals(file.getName())){ @@ -82,7 +85,7 @@ public class FileObserverService extends Service { } } - Log.e(TAG, "....... extension..."+extension); + if(!files.contains(file) && !remoteFileFlag){ -- GitLab