diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 177f5488b06b08e947ab429251ff9d7f6bdd5ff8..f8c0bfe3a27bf3c8676e74696719bd83647883ca 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -83,9 +83,6 @@
android:exported="true"
android:label="@string/account_setting_metered_network"
tools:ignore="ExportedContentProvider" />
-
= ArrayList()
for (folder in rootSyncedFolderList) {
- val createRemoteFolderWorkRequest = getOneTimeWorkRequest(
- WorkType.CREATE_REMOTE_DIR,
+ val rootFolderSetupWorkRequest = getOneTimeWorkRequest(
+ WorkType.ONE_TIME_ROOT_FOLDER_SETUP,
folder
)
- workRequests.add(createRemoteFolderWorkRequest)
+ workRequests.add(rootFolderSetupWorkRequest)
}
return workRequests
}
diff --git a/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java b/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java
index 3363425bf2e82d044f602bf7b5cc1c3ecc6bb955..bcfd6b5e6b3588b39fbaa487de87f7e811b3f985 100644
--- a/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java
+++ b/app/src/main/java/foundation/e/drive/account/receivers/AccountRemoveCallbackReceiver.java
@@ -26,7 +26,6 @@ import java.io.File;
import foundation.e.drive.EdriveApplication;
import foundation.e.drive.database.DbHelper;
import foundation.e.drive.database.FailedSyncPrefsManager;
-import foundation.e.drive.services.ObserverService;
import foundation.e.drive.services.SynchronizationService;
import foundation.e.drive.utils.AppConstants;
import foundation.e.drive.utils.DavClientProvider;
@@ -95,9 +94,6 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver {
}
private void stopAllServices(@NonNull Context applicationContext) {
- Intent observerServiceIntent = new Intent(applicationContext, ObserverService.class);
- boolean observerServiceStopResult = applicationContext.stopService(observerServiceIntent);
- Timber.d("stop ObserverService: %s", observerServiceStopResult);
Intent synchronizationServiceIntent = new Intent(applicationContext, SynchronizationService.class);
boolean syncServiceStopResult = applicationContext.stopService(synchronizationServiceIntent);
@@ -111,7 +107,7 @@ public class AccountRemoveCallbackReceiver extends BroadcastReceiver {
.remove(AccountManager.KEY_ACCOUNT_TYPE)
.remove(SETUP_COMPLETED)
.remove(INITIAL_FOLDER_NUMBER)
- .remove(AppConstants.KEY_LAST_SYNC_TIME)
+ .remove(AppConstants.KEY_LAST_SCAN_TIME)
.apply();
}
diff --git a/app/src/main/java/foundation/e/drive/account/setup/FinishSetupWorker.java b/app/src/main/java/foundation/e/drive/account/setup/FinishSetupWorker.java
new file mode 100644
index 0000000000000000000000000000000000000000..1563cf01cbf0b2af40f4bfb9af174522f328840d
--- /dev/null
+++ b/app/src/main/java/foundation/e/drive/account/setup/FinishSetupWorker.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright © MURENA SAS 2022-2023.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package foundation.e.drive.account.setup;
+
+import static android.content.Context.MODE_PRIVATE;
+import static foundation.e.drive.utils.AppConstants.INITIAL_FOLDER_NUMBER;
+import static foundation.e.drive.utils.AppConstants.SHARED_PREFERENCE_NAME;
+import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_APP_LIST;
+import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_FORCED_FULL_SCAN;
+import static foundation.e.drive.work.WorkRequestFactory.WorkType.PERIODIC_SCAN;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.work.ExistingPeriodicWorkPolicy;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.WorkManager;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+
+import foundation.e.drive.periodicScan.FullScanWorker;
+import foundation.e.drive.periodicScan.PeriodicScanWorker;
+import foundation.e.drive.utils.AppConstants;
+import foundation.e.drive.work.WorkRequestFactory;
+import timber.log.Timber;
+
+/**
+ * This class perform last task of setup
+ * It contains job to start FileObserver, periodic fullScan and Synchronization service
+ * for the first time
+ * @author Vincent Bourgmayer
+ */
+public class FinishSetupWorker extends Worker {
+ public FinishSetupWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
+ super(context, workerParams);
+ }
+
+ @NonNull
+ @Override
+ public Result doWork() {
+ Timber.v("FinishSetupWorker.doWork()");
+ try {
+ final Context appContext = getApplicationContext();
+ enqueueWorkers(appContext);
+ updateSharedPreferences(appContext);
+
+ return Result.success();
+
+ } catch (Exception exception) {
+ Timber.e(exception);
+ }
+ return Result.retry();
+ }
+
+ private void updateSharedPreferences(Context appContext) {
+ appContext.getSharedPreferences(SHARED_PREFERENCE_NAME, MODE_PRIVATE)
+ .edit()
+ .putBoolean(AppConstants.SETUP_COMPLETED, true)
+ .putInt(INITIAL_FOLDER_NUMBER, 9)
+ .apply();
+ }
+
+ private void enqueueWorkers(@NonNull final Context appContext) {
+ final WorkManager workManager = WorkManager.getInstance(appContext);
+ enqueueAppListGenerationWorker(workManager);
+ enqueueFullScanWorker(workManager);
+ enqueuePeriodicFileScanWorker(workManager);
+ }
+
+ private void enqueueFullScanWorker(@NonNull final WorkManager workManager) {
+ workManager.enqueueUniqueWork(
+ FullScanWorker.UNIQUE_WORK_NAME,
+ ExistingWorkPolicy.KEEP,
+ WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_FORCED_FULL_SCAN, null)
+ );
+ }
+
+ private void enqueueAppListGenerationWorker(@NonNull final WorkManager workManager) {
+ workManager.enqueue(WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_APP_LIST, null));
+ }
+
+ private void enqueuePeriodicFileScanWorker(@NonNull final WorkManager workManager) {
+ workManager.enqueueUniquePeriodicWork(PeriodicScanWorker.UNIQUE_WORK_NAME,
+ ExistingPeriodicWorkPolicy.KEEP,
+ WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_SCAN));
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/work/RootFolderSetupWorker.java b/app/src/main/java/foundation/e/drive/account/setup/RootFolderSetupWorker.java
similarity index 99%
rename from app/src/main/java/foundation/e/drive/work/RootFolderSetupWorker.java
rename to app/src/main/java/foundation/e/drive/account/setup/RootFolderSetupWorker.java
index 8ff54f22354017e337a2c49519737a3b8c39f5a9..6488eeb54c74b1c487105bf1090d945cf72f8d29 100644
--- a/app/src/main/java/foundation/e/drive/work/RootFolderSetupWorker.java
+++ b/app/src/main/java/foundation/e/drive/account/setup/RootFolderSetupWorker.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.work;
+package foundation.e.drive.account.setup;
import android.accounts.Account;
import android.accounts.AccountManager;
diff --git a/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt b/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0a4776aec98e1fdc537fe9b6552278250523b81d
--- /dev/null
+++ b/app/src/main/java/foundation/e/drive/periodicScan/FullScanWorker.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright © MURENA SAS 2023.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+package foundation.e.drive.periodicScan
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.app.Application
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import com.owncloud.android.lib.common.operations.RemoteOperationResult
+import com.owncloud.android.lib.resources.files.model.RemoteFile
+import foundation.e.drive.R
+import foundation.e.drive.database.DbHelper
+import foundation.e.drive.models.SyncRequest
+import foundation.e.drive.models.SyncedFolder
+import foundation.e.drive.periodicScan.contentScanner.LocalContentScanner
+import foundation.e.drive.periodicScan.contentScanner.LocalFileLister
+import foundation.e.drive.periodicScan.contentScanner.RemoteContentScanner
+import foundation.e.drive.synchronization.SyncProxy
+import foundation.e.drive.synchronization.SyncRequestCollector
+import foundation.e.drive.utils.AppConstants
+import foundation.e.drive.utils.AppConstants.KEY_LAST_SCAN_TIME
+import foundation.e.drive.utils.CommonUtils
+import foundation.e.drive.utils.DavClientProvider
+import timber.log.Timber
+
+class FullScanWorker(private val context: Context, private val workerParams: WorkerParameters) :
+ Worker(context, workerParams)
+{
+
+ private val syncRequests = HashMap()
+
+ companion object {
+ private const val SYNC_MINIMUM_DELAY = 900000 // min delay between two run in ms.
+ const val ACTION_FORCED_SYNC_KEY = "forced_sync"
+ const val UNIQUE_WORK_NAME = "fullScan"
+ }
+
+ override fun doWork(): Result {
+ try {
+ val requestCollector: SyncRequestCollector = SyncProxy
+
+ val prefs = context.getSharedPreferences(
+ AppConstants.SHARED_PREFERENCE_NAME,
+ Context.MODE_PRIVATE
+ )
+ val account = loadAccount(prefs)
+
+ val startAllowed = checkStartConditions(account, prefs, requestCollector)
+ if (!startAllowed) {
+ Timber.d("Start Periodic Scan is not allowed")
+ requestCollector.startListeningFiles(applicationContext as Application)
+ return Result.failure()
+ }
+
+ val syncFolders = loadSyncedFolders(account!!)
+ if (syncFolders.isEmpty()) {
+ requestCollector.startListeningFiles(applicationContext as Application)
+ return Result.success()
+ }
+
+ val remoteSyncRequests = scanRemoteFiles(account, syncFolders.toMutableList())
+ syncRequests.putAll(remoteSyncRequests)
+
+ Timber.d("${remoteSyncRequests.size} request collected from cloud")
+
+ val localSyncRequests = scanLocalFiles(syncFolders.toMutableList())
+ syncRequests.putAll(localSyncRequests)
+ Timber.d("${localSyncRequests.size} request collected from device")
+
+ prefs.edit()
+ .putLong(KEY_LAST_SCAN_TIME, System.currentTimeMillis())
+ .apply();
+
+ if (syncRequests.isEmpty()) {
+ Timber.d("Nothing to sync")
+ requestCollector.startListeningFiles(applicationContext as Application)
+ return Result.success()
+ }
+
+ Timber.d("${syncRequests.size} files to sync")
+ requestCollector.queueSyncRequests(syncRequests.values, context)
+ requestCollector.startSynchronization(applicationContext)
+ return Result.success()
+
+ } catch (exception: Exception) {
+ Timber.e(exception)
+ return Result.failure()
+ }
+ }
+
+ private fun checkStartConditions(account: Account?, prefs : SharedPreferences, requestCollector: SyncRequestCollector): Boolean {
+ Timber.d("FullScanWorker.checkStartConditions()")
+
+ if (account == null) return false
+
+ if (!isSetupDone(prefs)) return false
+
+ if (isFileSyncDisabled(account)) return false //@todo could be replaced by checking list of sync folders not empty after loading them
+
+ val forcedSync = workerParams.inputData.getBoolean(ACTION_FORCED_SYNC_KEY, false)
+
+ if (!forcedSync && !isMinimumDelayRespected(prefs)) return false
+
+ if (!isConnectedToAllowedNetwork(account)) return false
+
+ if (!requestCollector.onPeriodicScanStart(applicationContext as Application)) return false
+
+ return true
+ }
+
+ private fun loadAccount(prefs: SharedPreferences): Account? {
+ val accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, "") ?: return null
+ val accountType = context.getString(R.string.eelo_account_type)
+
+ return CommonUtils.getAccount(accountName, accountType, AccountManager.get(context))
+ }
+
+ /**
+ * indicate if minimum delay between two periodic scan is respected
+ */
+ private fun isMinimumDelayRespected(prefs: SharedPreferences): Boolean {
+ val lastSyncTime = prefs.getLong(KEY_LAST_SCAN_TIME, 0L)
+ val currentTime = System.currentTimeMillis()
+ val deltaTime = currentTime - lastSyncTime
+
+ return deltaTime >= SYNC_MINIMUM_DELAY
+ }
+
+ /**
+ * Indicates if user has disable both media and settings files synchronization
+ */
+ private fun isFileSyncDisabled(account: Account) : Boolean {
+ return !CommonUtils.isMediaSyncEnabled(account) && !CommonUtils.isSettingsSyncEnabled(account)
+ }
+
+ /**
+ * Indicates if account has been set up and Remote root folders created
+ */
+ private fun isSetupDone(prefs: SharedPreferences): Boolean {
+ return prefs.getBoolean(AppConstants.SETUP_COMPLETED, false)
+ }
+
+ /**
+ * Check if device is connected to an allowed network type for synchronization
+ * note: because user can disable sync over metered network
+ */
+ private fun isConnectedToAllowedNetwork(account: Account): Boolean {
+ val isMeteredNetworkAllowed = CommonUtils.isMeteredNetworkAllowed(account)
+ return CommonUtils.haveNetworkConnection(context, isMeteredNetworkAllowed)
+ }
+
+ /**
+ * Fetch SyncedFolders list from Database
+ */
+ private fun loadSyncedFolders(account: Account): List {
+ val isMediaSyncEnabled = CommonUtils.isMediaSyncEnabled(account)
+ val isSettingsSyncEnabled = CommonUtils.isSettingsSyncEnabled(account)
+
+ return if (isMediaSyncEnabled && isSettingsSyncEnabled) DbHelper.getAllSyncedFolders(context)
+ else if (isMediaSyncEnabled) DbHelper.getSyncedFolderList(context, true)
+ else if (isSettingsSyncEnabled) DbHelper.getSyncedFolderList(context, false)
+ else ArrayList()
+ }
+
+ /**
+ * generate SyncRequest for files on the cloud
+ */
+ private fun scanRemoteFiles(account: Account, syncedFolders: List): HashMap {
+ val ocClient = DavClientProvider.getInstance().getClientInstance(account, context)?: return HashMap()
+ val listRemoteFilesOperation =
+ ListFileRemoteOperation(
+ syncedFolders,
+ context
+ )
+
+ try {
+ @Suppress("DEPRECATION")
+ val result = listRemoteFilesOperation.execute(ocClient) as RemoteOperationResult>
+ if (!result.isSuccess) {
+ Timber.d("Fails to check remote files")
+ }
+ val remoteFiles = result.resultData as List
+
+ val syncedFoldersIds = listRemoteFilesOperation.syncedFoldersId
+ val syncedFileStates = DbHelper.getSyncedFileStatesByFolders(context, syncedFoldersIds)
+
+ if (remoteFiles.isNotEmpty() || syncedFileStates.isNotEmpty()) {
+ val scanner = RemoteContentScanner(context, syncedFolders)
+ return scanner.scanContent(remoteFiles, syncedFileStates)
+ }
+
+ } catch(exception: IllegalArgumentException) {
+ Timber.e(exception)
+ }
+ return HashMap()
+ }
+
+ /**
+ * generate SyncRequest for files on the device
+ */
+ private fun scanLocalFiles(syncedFolders: List): HashMap {
+ val localFileLister = LocalFileLister(syncedFolders)
+ val isContentToScan = localFileLister.listContentToScan(context)
+
+ if (!isContentToScan) {
+ return HashMap()
+ }
+
+ val localFiles = localFileLister.contentToScan
+ val syncedFoldersIds = localFileLister.syncedFoldersId
+ val syncedFileStates = DbHelper.getSyncedFileStatesByFolders(context, syncedFoldersIds)
+
+ if (localFiles.isNotEmpty() || syncedFileStates.isNotEmpty()) {
+ val scanner = LocalContentScanner(context, syncedFolders)
+ return scanner.scanContent(localFiles, syncedFileStates)
+ }
+ return HashMap()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java b/app/src/main/java/foundation/e/drive/periodicScan/ListAppsWorker.java
similarity index 99%
rename from app/src/main/java/foundation/e/drive/work/ListAppsWorker.java
rename to app/src/main/java/foundation/e/drive/periodicScan/ListAppsWorker.java
index 1309f6eeafbd62a3f9c6e8a6d1084926f6a52c66..6c6b9062f1efa9be72c633f7b855443c898bcfef 100644
--- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/ListAppsWorker.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.work;
+package foundation.e.drive.periodicScan;
import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR;
diff --git a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java b/app/src/main/java/foundation/e/drive/periodicScan/ListFileRemoteOperation.java
similarity index 85%
rename from app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java
rename to app/src/main/java/foundation/e/drive/periodicScan/ListFileRemoteOperation.java
index c5aa5ec6f617a00d2fe3292224672590eda41e18..0e07ee51dadf2f24f5632110e2d2ea979bf3e950 100644
--- a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/ListFileRemoteOperation.java
@@ -1,36 +1,31 @@
/*
* Copyright © CLEUS SAS 2018-2019.
- * Copyright © ECORP SAS 2022.
+ * Copyright © MURENA SAS 2022-2023.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.operations;
+package foundation.e.drive.periodicScan;
import android.content.Context;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
-import java.io.File;
+
import java.util.ArrayList;
import java.util.List;
-import java.util.ListIterator;
-import foundation.e.drive.contentScanner.RemoteFileLister;
+import foundation.e.drive.periodicScan.contentScanner.RemoteFileLister;
import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFolder;
-import foundation.e.drive.utils.CommonUtils;
import timber.log.Timber;
-
/**
* /!\ Doesn't require NextcloudClient yet
* @author Vincent Bourgmayer
@@ -63,8 +58,8 @@ public class ListFileRemoteOperation extends RemoteOperation(RemoteOperationResult.ResultCode.OK);
if (isContentToScan) {
DbHelper.updateSyncedFolders(this.syncedFolders, this.context);
- result.setResultData(fileLister.getContentToScan());
}
+ result.setResultData(fileLister.getContentToScan());
updatedSyncedFoldersId.addAll(fileLister.getSyncedFoldersId());
return result;
diff --git a/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java b/app/src/main/java/foundation/e/drive/periodicScan/PeriodicScanWorker.java
similarity index 85%
rename from app/src/main/java/foundation/e/drive/work/PeriodicWorker.java
rename to app/src/main/java/foundation/e/drive/periodicScan/PeriodicScanWorker.java
index 560ef9f90ddf6382a7e1ea9b1aa6fb4bef3ff7e4..ffaf89c664679dfe4d7dfe296b43381fbba9a216 100644
--- a/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/PeriodicScanWorker.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.work;
+package foundation.e.drive.periodicScan;
import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_APP_LIST;
import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_FULL_SCAN;
@@ -23,6 +23,7 @@ import androidx.work.WorkerParameters;
import java.util.ArrayList;
import java.util.List;
+import foundation.e.drive.work.WorkRequestFactory;
import timber.log.Timber;
/**
@@ -31,9 +32,9 @@ import timber.log.Timber;
* at the moment
* @author vincent Bourgmayer
*/
-public class PeriodicWorker extends Worker {
- public final static String UNIQUE_WORK_NAME = "periodicWork";
- public PeriodicWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
+public class PeriodicScanWorker extends Worker {
+ public final static String UNIQUE_WORK_NAME = "periodicScanWork";
+ public PeriodicScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/AbstractContentScanner.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractContentScanner.java
similarity index 98%
rename from app/src/main/java/foundation/e/drive/contentScanner/AbstractContentScanner.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractContentScanner.java
index c8b843c9d76bf22cb1db17c1b3765d86833eb883..6bb3deb25f3cecd27c15567c9034599945340bb9 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/AbstractContentScanner.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractContentScanner.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import android.content.Context;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/AbstractFileLister.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractFileLister.java
similarity index 99%
rename from app/src/main/java/foundation/e/drive/contentScanner/AbstractFileLister.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractFileLister.java
index 0e45cdcdc6ea30967fd96977c05db5212487d9cb..da8a6cb7543f40a74342b869f60c96119681dc20 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/AbstractFileLister.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/AbstractFileLister.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import android.content.Context;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/FileDiffUtils.kt b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtils.kt
similarity index 98%
rename from app/src/main/java/foundation/e/drive/contentScanner/FileDiffUtils.kt
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtils.kt
index 273dfe5c7e5d6a2e0798dc54ed480ea736cc7dd5..41e34693a48ec0db9eaecad4105ac9f66bdb97b6 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/FileDiffUtils.kt
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtils.kt
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner
+package foundation.e.drive.periodicScan.contentScanner
import androidx.annotation.VisibleForTesting
import com.owncloud.android.lib.resources.files.model.RemoteFile
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/FolderWrapper.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FolderWrapper.java
similarity index 97%
rename from app/src/main/java/foundation/e/drive/contentScanner/FolderWrapper.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FolderWrapper.java
index 49a5ee37b32a3e2b59d5ef92f5b187847b348c75..4c9bb0bcada6c0522408362ff2f9fbd320dcf060 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/FolderWrapper.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/FolderWrapper.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import androidx.annotation.NonNull;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScanner.java
similarity index 98%
rename from app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScanner.java
index 6e62d02d61f0a0a7f8f44fb62921f8c4d4552658..83a656fa6e5380c4bf0743986f439c1ff145d30f 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScanner.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static foundation.e.drive.models.SyncedFileStateKt.DO_NOT_SCAN;
import static foundation.e.drive.models.SyncedFileStateKt.SCAN_ON_CLOUD;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/LocalFileLister.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalFileLister.java
similarity index 98%
rename from app/src/main/java/foundation/e/drive/contentScanner/LocalFileLister.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalFileLister.java
index 80a9fa8e3796d08d29c3e139540b0c66b72b40f1..11d2c58d891490445fbf7b8caf58c80caad28899 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/LocalFileLister.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/LocalFileLister.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import android.content.Context;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScanner.java
similarity index 97%
rename from app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScanner.java
index 3848eb8931b81fdc3a4bbda4b09a3f0616cc5151..d4f22e7440504fc7a7b110a9d9a099ce11f276ef 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScanner.java
@@ -5,13 +5,13 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING;
import static foundation.e.drive.models.SyncedFileStateKt.DO_NOT_SCAN;
import static foundation.e.drive.models.SyncedFileStateKt.SCAN_ON_CLOUD;
import static foundation.e.drive.models.SyncedFileStateKt.SCAN_ON_DEVICE;
-import static foundation.e.drive.contentScanner.FileDiffUtils.getActionForFileDiff;
+import static foundation.e.drive.periodicScan.contentScanner.FileDiffUtils.getActionForFileDiff;
import android.content.Context;
diff --git a/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileLister.java
similarity index 98%
rename from app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java
rename to app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileLister.java
index 8c54a6492588d6c419edfe4583dbbf5752cf4cb7..de99d1c6a316d094c648c5ba79e2c1a7dec94d77 100644
--- a/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java
+++ b/app/src/main/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileLister.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import android.content.Context;
diff --git a/app/src/main/java/foundation/e/drive/receivers/DebugCmdReceiver.java b/app/src/main/java/foundation/e/drive/receivers/DebugCmdReceiver.java
index b5abb15948e84790e1fac10c2db5d3eadd44fd69..b4b6cf2956e2b002cc6f0c56f96b7809ab332c88 100644
--- a/app/src/main/java/foundation/e/drive/receivers/DebugCmdReceiver.java
+++ b/app/src/main/java/foundation/e/drive/receivers/DebugCmdReceiver.java
@@ -7,16 +7,21 @@
*/
package foundation.e.drive.receivers;
+import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_FORCED_FULL_SCAN;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
import foundation.e.drive.database.DbHelper;
-import foundation.e.drive.services.ObserverService;
+import foundation.e.drive.periodicScan.FullScanWorker;
import foundation.e.drive.utils.ReleaseTree;
+import foundation.e.drive.work.WorkRequestFactory;
import timber.log.Timber;
/**
@@ -35,7 +40,11 @@ public class DebugCmdReceiver extends BroadcastReceiver {
switch (intent.getAction()) {
case ACTION_FORCE_SYNC:
Timber.d("Force Sync intent received");
- context.startService(new Intent(ACTION_FORCE_SYNC, null, context, ObserverService.class));
+ final WorkManager workManager = WorkManager.getInstance(context);
+ final OneTimeWorkRequest fullScanWorkRequest = WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_FORCED_FULL_SCAN, null);
+ workManager.enqueueUniqueWork(FullScanWorker.UNIQUE_WORK_NAME,
+ ExistingWorkPolicy.KEEP,
+ fullScanWorkRequest);
break;
case ACTION_DUMP_DATABASE:
Timber.d("Dump database intent received");
diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java
deleted file mode 100644
index fe8faf1adaf7d6ab3106e0828f16b3d732d5eb0b..0000000000000000000000000000000000000000
--- a/app/src/main/java/foundation/e/drive/services/ObserverService.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright © CLEUS SAS 2018-2019.
- * Copyright © MURENA SAS 2022-2023.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Public License v3.0
- * which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/gpl.html
- */
-
-package foundation.e.drive.services;
-
-import static foundation.e.drive.utils.AppConstants.SETUP_COMPLETED;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-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.model.RemoteFile;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import foundation.e.drive.R;
-import foundation.e.drive.contentScanner.LocalContentScanner;
-import foundation.e.drive.contentScanner.LocalFileLister;
-import foundation.e.drive.contentScanner.RemoteContentScanner;
-import foundation.e.drive.database.DbHelper;
-import foundation.e.drive.fileFilters.CrashlogsFileFilter;
-import foundation.e.drive.fileFilters.OnlyFileFilter;
-import foundation.e.drive.models.SyncRequest;
-import foundation.e.drive.models.SyncedFileState;
-import foundation.e.drive.models.SyncedFolder;
-import foundation.e.drive.operations.ListFileRemoteOperation;
-import foundation.e.drive.receivers.DebugCmdReceiver;
-import foundation.e.drive.synchronization.SyncRequestCollector;
-import foundation.e.drive.synchronization.SyncProxy;
-import foundation.e.drive.utils.AppConstants;
-import foundation.e.drive.utils.CommonUtils;
-import foundation.e.drive.utils.DavClientProvider;
-import foundation.e.drive.utils.ServiceExceptionHandler;
-import timber.log.Timber;
-
-/**
- * @author Vincent Bourgmayer
- * @author Nicolas Gelot
- * @author Jonathan Klee
- * This service look for remote or looale file to synchronize
- */
-public class ObserverService extends Service implements OnRemoteOperationListener{
- private final static int INTERSYNC_MINIMUM_DELAY = 900000; // min delay execution two sync in ms.
-
- private List mSyncedFolders; //List of synced folder
- private Account mAccount;
- private HashMap syncRequests; //integer is SyncedFileState id; Parcelable is the operation
-
- private final SyncRequestCollector syncManager = SyncProxy.INSTANCE;
-
- private Handler handler;
- private HandlerThread handlerThread;
- // protected to avoid SyntheticAccessor
- protected boolean forcedSync = false;
-
- /* Lifecycle Methods */
- @Override
- public void onDestroy(){
- Timber.v("onDestroy()");
- if (handlerThread != null) handlerThread.quitSafely();
- mSyncedFolders = null;
- super.onDestroy();
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Timber.tag(ObserverService.class.getSimpleName());
- }
-
- @Override
-
- public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
- Timber.v("onStartCommand(%s)", startId);
-
- CommonUtils.setServiceUnCaughtExceptionHandler(this);
-
- final SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
- final String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, "");
- final String accountType = getApplicationContext().getString(R.string.eelo_account_type);
- this.mAccount = CommonUtils.getAccount(accountName, accountType, AccountManager.get(this));
-
- forcedSync = intent != null && DebugCmdReceiver.ACTION_FORCE_SYNC.equals(intent.getAction());
-
- this.syncRequests = new HashMap<>();
-
- if (!checkStartCondition(prefs, forcedSync)) {
- syncManager.startListeningFiles(getApplication());
- stopSelf();
- return START_NOT_STICKY;
- }
-
- begin();
- return START_STICKY;
- }
-
- /**
- * This method check that all condition are met
- * to start ObserverService:
- * - a valid account as been registered
- * - Synchronization of media and/or settings is enabled
- * - Initialization task has been done properly
- * - Service isn't already running
- * - Check minimum delay since last call if not forced sync
- * - Check that network is available depending of metered network allowed or not
- *
- * It also display log depending of the failure and send intent for initialization if this has
- * not been done
- * @return false if at least one condition is false
- */
- // protected to avoid SyntheticAccessor
- protected boolean checkStartCondition(@NonNull final SharedPreferences prefs, final boolean forcedSync) {
- Timber.v("checkStartCondition()");
-
- if (mAccount == null) {
- Timber.d("No account registered");
- return false;
- }
-
- if (!CommonUtils.isMediaSyncEnabled(mAccount) && !CommonUtils.isSettingsSyncEnabled(mAccount)) {
- Timber.d("Synchronization has been disabled in account's settings");
- return false;
- }
-
- if (!prefs.getBoolean(SETUP_COMPLETED, false)) {
- Timber.d("setup hasn't been done");
- return false;
- }
-
- // Check minimum delay since last call & not forced sync
- /*@todo is it really usefull to check time beetween to start as it is started by WorkManager?
- it matters only if we want to consider forced sync */
- final long lastSyncTime = prefs.getLong(AppConstants.KEY_LAST_SYNC_TIME, 0L);
- final long currentTime = System.currentTimeMillis();
- if (!forcedSync && (currentTime - lastSyncTime ) < INTERSYNC_MINIMUM_DELAY ) {
- Timber.d("Delay between now and last call is too short");
- return false;
- }
-
- final boolean meteredNetworkAllowed = CommonUtils.isMeteredNetworkAllowed(mAccount);
- //check for the case where intent has been launched by initializerService
- if (!CommonUtils.haveNetworkConnection(this, meteredNetworkAllowed)) {
- Timber.d("There is no allowed internet connexion.");
- return false;
- }
-
-
- final boolean startAllowed = syncManager.onPeriodicScanStart(getApplication());
- Timber.d("starting periodic scan is allowed ? %s", startAllowed);
- return startAllowed;
- }
-
- /* 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
- */
- // protected to avoid SyntheticAccessor
- protected void begin(){
- clearCachedFile();
- deleteOldestCrashlogs();
- startScan(true);
- }
-
- /**
- * This method remove all the crash-logs file
- * in external dir that are 10 days or more old.
- */
- private void deleteOldestCrashlogs(){
- Timber.i("deleteOldestCrashLogs()");
- final File externalFilesDir = getExternalFilesDir(ServiceExceptionHandler.CRASH_LOG_FOLDER);
- if (externalFilesDir == null) {
- Timber.d("getExternalFilesDir() returned null. Preventing a NPE");
- return;
- }
-
- final File[] fileToRemove = externalFilesDir.listFiles(new CrashlogsFileFilter());
- if (fileToRemove == null) {
- Timber.d("getExternalFilesDir() returned null. Preventing a NPE");
- return;
- }
-
- for (File file : fileToRemove) {
- try {
- file.delete();
- } catch (SecurityException exception) {
- Timber.e(exception);
- }
- }
- }
-
- /**
- * Clear cached file unused:
- */
- private void clearCachedFile(){
- Timber.i("clearCachedFile()");
- final File[] fileToRemove = this.getApplicationContext().getExternalCacheDir().listFiles(new OnlyFileFilter() );
- if (fileToRemove == null) return;
-
- for (File file : fileToRemove) {
- try {
- file.delete();
- } catch (SecurityException exception) {
- Timber.e(exception);
- }
- }
- }
-
- /**
- * 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) {
- Timber.i("startScan(%s)", remote);
- this.mSyncedFolders = loadSyncedFolders();
-
- if (mSyncedFolders.isEmpty()) {
- Timber.d("List of synced folders is empty");
- this.stopSelf();
- return;
- }
-
- if (remote) {
- final OwnCloudClient client = DavClientProvider.getInstance().getClientInstance(mAccount, getApplicationContext());
- if (client == null) {
- Timber.d("OwnCloudClient is null");
- return;
- }
-
- try {
- handlerThread = new HandlerThread("syncService_onResponse");
- handlerThread.start();
- handler = new Handler(handlerThread.getLooper());
- final ListFileRemoteOperation loadOperation = new ListFileRemoteOperation(this.mSyncedFolders, this);
- loadOperation.execute(client, this, handler);
- } catch (IllegalArgumentException exception) {
- Timber.e(exception);
- }
- } else {
- scanLocalFiles();
- }
- }
-
- /**
- * Get list of synced folder depending of if media and setting sync are enabled.
- * @return
- */
- private List loadSyncedFolders(){
- final boolean mediaSyncEnabled = CommonUtils.isMediaSyncEnabled(mAccount);
- final boolean settingsSyncedEnabled = CommonUtils.isSettingsSyncEnabled(mAccount);
-
- if (mediaSyncEnabled && settingsSyncedEnabled) {
- return DbHelper.getAllSyncedFolders(this);
- } else if (mediaSyncEnabled) {
- return DbHelper.getSyncedFolderList(this, true);
- } else if (settingsSyncedEnabled) {
- return DbHelper.getSyncedFolderList(this, false);
- } 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
- */
- @Override
- public void onRemoteOperationFinish(@Nullable RemoteOperation operation, @NonNull RemoteOperationResult result) {
- Timber.d("onRemoteOperationFinish()");
- if (!(operation instanceof ListFileRemoteOperation)) return;
-
- if (!result.isSuccess()) {
- Timber.d("ListRemoteFileOperation failed. Http code: %s", result.getHttpCode());
- }
-
- final List remoteFiles = ((RemoteOperationResult>)result).getResultData();
-
- if (remoteFiles != null) {
- final ListFileRemoteOperation listFileOperation = (ListFileRemoteOperation) operation;
- final List syncedFoldersId = listFileOperation.getSyncedFoldersId();
-
- final List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this,
- syncedFoldersId);
-
- if (!remoteFiles.isEmpty() || !syncedFileStates.isEmpty()) {
- final RemoteContentScanner scanner = new RemoteContentScanner(getApplicationContext(), mSyncedFolders);
- syncRequests.putAll(scanner.scanContent(remoteFiles, syncedFileStates));
- }
- }
-
- startScan(false);
-
- if (!syncRequests.isEmpty()) {
- Timber.d("syncRequests contains %s", syncRequests.size());
- syncManager.queueSyncRequests(syncRequests.values(), getApplicationContext());
- syncManager.startSynchronization(getApplicationContext());
- } else {
- Timber.i("There is no file to sync.");
- getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
- .edit()
- .putLong(AppConstants.KEY_LAST_SYNC_TIME, System.currentTimeMillis())
- .apply();
- syncManager.startListeningFiles(getApplication());
- }
-
- this.stopSelf();
- }
-
- /**
- * Prepare the list of files and SyncedFileState for synchronisation
- */
- private void scanLocalFiles(){
- Timber.i("scanLocalFiles()");
-
- final LocalFileLister fileLister = new LocalFileLister(mSyncedFolders);
-
- final boolean isContentToScan = fileLister.listContentToScan(getApplicationContext());
-
- if (!isContentToScan) {
- return;
- }
-
- final List fileList = fileLister.getContentToScan();
- final List folderIdList = fileLister.getSyncedFoldersId();
-
- final List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this,
- folderIdList);
-
- if (!syncedFileStates.isEmpty() || !fileList.isEmpty() ) {
- final LocalContentScanner scanner= new LocalContentScanner(getApplicationContext(), mSyncedFolders);
- syncRequests.putAll(scanner.scanContent(fileList, syncedFileStates));
- }
- }
-
- @Nullable
- @Override
- public IBinder onBind(@Nullable Intent intent) {
- throw new UnsupportedOperationException();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/utils/AppConstants.kt b/app/src/main/java/foundation/e/drive/utils/AppConstants.kt
index 49d2b5d636b20375ac27eb63fd22fd116083d35c..f3721e603596a662ec46eb6bc5444160002f82bc 100644
--- a/app/src/main/java/foundation/e/drive/utils/AppConstants.kt
+++ b/app/src/main/java/foundation/e/drive/utils/AppConstants.kt
@@ -22,11 +22,11 @@ object AppConstants {
const val SETTINGS_SYNC_PROVIDER_AUTHORITY = "foundation.e.drive.providers.SettingsSyncProvider"
const val METERED_NETWORK_ALLOWED_AUTHORITY =
"foundation.e.drive.providers.MeteredConnectionAllowedProvider"
- const val SETUP_COMPLETED = "initService_has_run"
+ const val SETUP_COMPLETED = "setup_completed"
+ const val KEY_LAST_SCAN_TIME = "lastScanTimestamp"
const val INITIAL_FOLDER_NUMBER = "initial_folder_number"
const val APPLICATIONS_LIST_FILE_NAME = "packages_list.csv"
const val SHARED_PREFERENCE_NAME = "preferences"
- const val KEY_LAST_SYNC_TIME = "lastSyncTimestamp"
const val ACCOUNT_DATA_NAME = "display_name"
const val ACCOUNT_DATA_USED_QUOTA_KEY = "used_quota"
const val ACCOUNT_DATA_TOTAL_QUOTA_KEY = "total_quota"
@@ -37,7 +37,7 @@ object AppConstants {
const val ACCOUNT_USER_ID_KEY = "USERID"
const val notificationChannelID = "foundation.e.drive"
const val WORK_GENERIC_TAG = "eDrive"
- const val WORK_INITIALIZATION_TAG = "eDrive-init"
+ const val WORK_SETUP_TAG = "eDrive-init"
const val CORRUPTED_TIMESTAMP_IN_SECOND = 4294967295L
@JvmField
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 1d6ec907f01c140beead7dce0c18e6a17865cbf0..a9fd0c00e519b24d65f0f3e41dc179d78e0d7ea4 100644
--- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java
+++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java
@@ -29,12 +29,9 @@ import java.lang.reflect.Method;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Locale;
-import java.util.ArrayList;
-import java.util.List;
import foundation.e.drive.R;
-import foundation.e.drive.models.SyncedFolder;
-import foundation.e.drive.work.AccountUserInfoWorker;
+import foundation.e.drive.account.AccountUserInfoWorker;
import foundation.e.drive.work.WorkRequestFactory;
import timber.log.Timber;
@@ -45,7 +42,6 @@ import static foundation.e.drive.utils.AppConstants.SETTINGS_SYNC_PROVIDER_AUTHO
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.work.ExistingPeriodicWorkPolicy;
-import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
diff --git a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java
deleted file mode 100644
index 0ebce10f2fa3c48ccfd0f327ff9280b3c2cb94a9..0000000000000000000000000000000000000000
--- a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright © MURENA SAS 2022-2023.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Public License v3.0
- * which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/gpl.html
- */
-
-package foundation.e.drive.work;
-
-import static foundation.e.drive.utils.AppConstants.INITIAL_FOLDER_NUMBER;
-import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_APP_LIST;
-import static foundation.e.drive.work.WorkRequestFactory.WorkType.PERIODIC_SCAN;
-
-import android.content.Context;
-import android.content.Intent;
-
-import androidx.annotation.NonNull;
-import androidx.work.ExistingPeriodicWorkPolicy;
-import androidx.work.WorkManager;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import foundation.e.drive.EdriveApplication;
-import foundation.e.drive.utils.AppConstants;
-import timber.log.Timber;
-
-/**
- * This class start eDrive work after initialization.
- * It contains job to start FileObserver, periodic fullScan and Synchronization service
- * for the first time
- * @author Vincent Bourgmayer
- */
-public class FirstStartWorker extends Worker {
- public FirstStartWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
- super(context, workerParams);
- Timber.tag(FirstStartWorker.class.getSimpleName());
- }
-
- @NonNull
- @Override
- public Result doWork() {
- Timber.v("FirstStartWorker.doWork()");
- try {
- final Context appContext = getApplicationContext();
-
- enqueueAppListGenerationWorkRequest(appContext);
-
- appContext.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME,
- Context.MODE_PRIVATE)
- .edit()
- .putBoolean(AppConstants.SETUP_COMPLETED, true)
- .putInt(INITIAL_FOLDER_NUMBER, 9)
- .apply();
-
- enqueuePeriodicFileScanWorkRequest(appContext);
-
- getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class));
-
- return Result.success();
- } catch (Exception exception) {
- Timber.e(exception);
- }
- return Result.retry();
- }
-
- private void enqueueAppListGenerationWorkRequest(@NonNull final Context context) {
- final WorkManager workManager = WorkManager.getInstance(context);
- workManager.enqueue(WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_APP_LIST, null));
- }
-
- private void enqueuePeriodicFileScanWorkRequest(@NonNull final Context context) {
- final WorkManager workManager = WorkManager.getInstance(context);
-
- workManager.enqueueUniquePeriodicWork(PeriodicWorker.UNIQUE_WORK_NAME,
- ExistingPeriodicWorkPolicy.KEEP,
- WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_SCAN));
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/work/FullScanWorker.java b/app/src/main/java/foundation/e/drive/work/FullScanWorker.java
deleted file mode 100644
index 156bcb7350dc3793cbf5ad3b176113df737c65dc..0000000000000000000000000000000000000000
--- a/app/src/main/java/foundation/e/drive/work/FullScanWorker.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright © ECORP SAS 2022.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Public License v3.0
- * which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/gpl.html
- */
-
-package foundation.e.drive.work;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-
-import androidx.annotation.NonNull;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import foundation.e.drive.services.ObserverService;
-import foundation.e.drive.utils.AppConstants;
-import foundation.e.drive.utils.CommonUtils;
-import timber.log.Timber;
-
-/**
- * As a first step, this class must replace foundation.e.drive.jobs.ScannerJob
- * in order to allow to use Jetpack Work API
- *
- * In further development it will be a part of Workers that will replace ObserverService
- * I will update this header accordingly
- *
- * @author Vincent Bourgmayer
- */
-public class FullScanWorker extends Worker {
- public final static String UNIQUE_WORK_NAME = "FullScan";
-
- public FullScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
- super(context, workerParams);
- Timber.tag(FullScanWorker.class.getSimpleName());
- }
-
- @NonNull
- @Override
- public Result doWork() {
- try {
- Timber.v("doWork(): going to send intent to ObserverService");
- final SharedPreferences prefs = getApplicationContext().getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME,
- Context.MODE_PRIVATE);
- final String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, "");
- final String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, "");
-
- final Account mAccount = CommonUtils.getAccount(accountName, accountType, AccountManager.get(this.getApplicationContext()));
-
- if (mAccount != null && CommonUtils.isSettingsSyncEnabled(mAccount) && CommonUtils.isMediaSyncEnabled(mAccount)) {
- final Intent observerServiceIntent = new Intent(this.getApplicationContext(), ObserverService.class);
- this.getApplicationContext().startService(observerServiceIntent);
- } else {
- Timber.d("Intent for ObserverService not send : account is null or \"settings sync\" & \"media sync\" settings are disabled");
- }
-
- return Result.success();
- } catch (Exception exception) {
- Timber.e(exception);
- return Result.retry();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java b/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java
index 0bef2fd5cd524958f5861cea2d7f6e8c5a4fed01..324b5deffe149920cc984cd8b3a2f851be78f69e 100644
--- a/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java
+++ b/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java
@@ -8,20 +8,23 @@
package foundation.e.drive.work;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_ENABLE;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_ID;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_LAST_ETAG;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_LAST_MODIFIED;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_LIBELLE;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_LOCAL_PATH;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_MEDIATYPE;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_REMOTE_PATH;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_SCAN_LOCAL;
-import static foundation.e.drive.work.RootFolderSetupWorker.DATA_KEY_SCAN_REMOTE;
+import static androidx.work.BackoffPolicy.LINEAR;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_ENABLE;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_ID;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_LAST_ETAG;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_LAST_MODIFIED;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_LIBELLE;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_LOCAL_PATH;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_MEDIATYPE;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_REMOTE_PATH;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_SCAN_LOCAL;
+import static foundation.e.drive.account.setup.RootFolderSetupWorker.DATA_KEY_SCAN_REMOTE;
+import static foundation.e.drive.utils.AppConstants.WORK_GENERIC_TAG;
+import static foundation.e.drive.utils.AppConstants.WORK_SETUP_TAG;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
import androidx.work.Data;
import androidx.work.NetworkType;
@@ -29,22 +32,30 @@ import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import java.security.InvalidParameterException;
-import java.util.concurrent.TimeUnit;
+import foundation.e.drive.account.AccountUserInfoWorker;
+import foundation.e.drive.account.setup.FinishSetupWorker;
+import foundation.e.drive.account.setup.RootFolderSetupWorker;
import foundation.e.drive.models.SyncedFolder;
-import foundation.e.drive.utils.AppConstants;
+import foundation.e.drive.periodicScan.FullScanWorker;
+import foundation.e.drive.periodicScan.ListAppsWorker;
+import foundation.e.drive.periodicScan.PeriodicScanWorker;
public class WorkRequestFactory {
public enum WorkType {
PERIODIC_USER_INFO,
PERIODIC_SCAN,
ONE_TIME_FULL_SCAN,
+ ONE_TIME_FORCED_FULL_SCAN,
ONE_TIME_APP_LIST,
ONE_TIME_USER_INFO,
- CREATE_REMOTE_DIR,
- FIRST_START
+ ONE_TIME_ROOT_FOLDER_SETUP,
+ ONE_TIME_FINISH_SETUP
}
+ private final static int PERIODIC_WORK_REPEAT_INTERVAL = 30;
+ private final static int PERIODIC_SCAN_FLEX_TIME = 5;
+
/**
* Build an instance of PeriodicWorkRequest depending of the work type specified
* @param type WorkType. Should be FULL_SCAN or PERIODIC_USER_INFO or PERIODIC_APP_LIST
@@ -64,7 +75,7 @@ public class WorkRequestFactory {
}
/**
- * Create a PeridocWorkRequest instance for
+ * Create a PeriodicWorkRequest instance for
* a Full scan with constraints on network (should
* be unmetered) and battery (shouldn't be low)
* @return instance of PeriodicWorkRequest
@@ -73,11 +84,14 @@ public class WorkRequestFactory {
private static PeriodicWorkRequest createPeriodicScanWorkRequest() {
final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints();
- return new PeriodicWorkRequest.Builder(PeriodicWorker.class,
- 26, TimeUnit.MINUTES, 5, TimeUnit.MINUTES)
- .setConstraints(constraints)
- .addTag(AppConstants.WORK_GENERIC_TAG)
- .build();
+ final PeriodicWorkRequest.Builder workRequestBuilder = new PeriodicWorkRequest.Builder(
+ PeriodicScanWorker.class,
+ PERIODIC_WORK_REPEAT_INTERVAL, MINUTES,
+ PERIODIC_SCAN_FLEX_TIME, MINUTES);
+
+ return workRequestBuilder.setConstraints(constraints)
+ .addTag(WORK_GENERIC_TAG)
+ .build();
}
/**
@@ -90,11 +104,12 @@ public class WorkRequestFactory {
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
- return new PeriodicWorkRequest.Builder(AccountUserInfoWorker.class,
- 30, TimeUnit.MINUTES)
- .addTag(AppConstants.WORK_GENERIC_TAG)
- .setConstraints(constraints)
- .build();
+ final PeriodicWorkRequest.Builder workRequestBuilder = new PeriodicWorkRequest.Builder(AccountUserInfoWorker.class,
+ PERIODIC_WORK_REPEAT_INTERVAL, MINUTES);
+
+ return workRequestBuilder.addTag(WORK_GENERIC_TAG)
+ .setConstraints(constraints)
+ .build();
}
/**
@@ -108,16 +123,18 @@ public class WorkRequestFactory {
public static OneTimeWorkRequest getOneTimeWorkRequest(@NonNull WorkType type, @Nullable SyncedFolder syncedFolder) {
switch (type) {
case ONE_TIME_APP_LIST:
- return createOneTimeAppListGenerationWorkRequest();
+ return createAppListGenerationWorkRequest();
case ONE_TIME_FULL_SCAN:
- return createOneTimeFullScanWorkRequest();
+ return createFullScanWorkRequest(false);
+ case ONE_TIME_FORCED_FULL_SCAN:
+ return createFullScanWorkRequest(true);
case ONE_TIME_USER_INFO:
- return createOneTimeGetUserInfoWorkRequest();
- case FIRST_START:
- return createOneTimeFirstStartWorkRequest();
- case CREATE_REMOTE_DIR:
+ return createGetUserInfoWorkRequest();
+ case ONE_TIME_FINISH_SETUP:
+ return createFinishSetupWorkRequest();
+ case ONE_TIME_ROOT_FOLDER_SETUP:
if (syncedFolder == null) throw new NullPointerException("Synced folder is null");
- return createOneTimeCreateRemoteFolderWorkRequest(syncedFolder);
+ return createRootFolderSetupWorkRequest(syncedFolder);
default:
throw new InvalidParameterException("Unsupported Work Type: " + type);
}
@@ -128,11 +145,11 @@ public class WorkRequestFactory {
* @return the workRequest
*/
@NonNull
- private static OneTimeWorkRequest createOneTimeAppListGenerationWorkRequest() {
+ private static OneTimeWorkRequest createAppListGenerationWorkRequest() {
final OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(ListAppsWorker.class);
- return builder.setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES)
- .addTag(AppConstants.WORK_GENERIC_TAG)
+ return builder.setBackoffCriteria(LINEAR, 2, MINUTES)
+ .addTag(WORK_GENERIC_TAG)
.build();
}
@@ -143,14 +160,19 @@ public class WorkRequestFactory {
* @return instance of OneTimeWorkRequest
*/
@NonNull
- private static OneTimeWorkRequest createOneTimeFullScanWorkRequest() {
+ private static OneTimeWorkRequest createFullScanWorkRequest(boolean forced) {
final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints();
final OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(FullScanWorker.class);
- return builder.setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES)
+ final Data data = new Data.Builder()
+ .putBoolean(FullScanWorker.ACTION_FORCED_SYNC_KEY, forced)
+ .build();
+
+ return builder.setBackoffCriteria(LINEAR, 2, MINUTES)
.setConstraints(constraints)
- .addTag(AppConstants.WORK_GENERIC_TAG)
+ .setInputData(data)
+ .addTag(WORK_GENERIC_TAG)
.build();
}
@@ -160,14 +182,14 @@ public class WorkRequestFactory {
* @return instance of OneTimeWorkRequest
*/
@NonNull
- private static OneTimeWorkRequest createOneTimeGetUserInfoWorkRequest() {
+ private static OneTimeWorkRequest createGetUserInfoWorkRequest() {
final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints();
final OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(AccountUserInfoWorker.class);
- return builder.setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES)
- .addTag(AppConstants.WORK_GENERIC_TAG)
- .addTag(AppConstants.WORK_INITIALIZATION_TAG)
+ return builder.setBackoffCriteria(LINEAR, 2, MINUTES)
+ .addTag(WORK_GENERIC_TAG)
+ .addTag(WORK_SETUP_TAG)
.setConstraints(constraints)
.build();
}
@@ -179,30 +201,29 @@ public class WorkRequestFactory {
* @return Instance OneTimeWorkRequest
*/
@NonNull
- private static OneTimeWorkRequest createOneTimeCreateRemoteFolderWorkRequest(@NonNull SyncedFolder syncedFolder) {
+ private static OneTimeWorkRequest createRootFolderSetupWorkRequest(@NonNull SyncedFolder syncedFolder) {
final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints();
return new OneTimeWorkRequest.Builder(
RootFolderSetupWorker.class)
- .setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES)
+ .setBackoffCriteria(LINEAR, 2, MINUTES)
.setInputData(createDataFromSyncedFolder(syncedFolder))
- .addTag(AppConstants.WORK_GENERIC_TAG)
- .addTag(AppConstants.WORK_INITIALIZATION_TAG)
+ .addTag(WORK_GENERIC_TAG)
+ .addTag(WORK_SETUP_TAG)
.setConstraints(constraints)
.build();
}
/**
- * Create a OneTime WorkRequest which start eDrive
- * after initialization
+ * Create a OneTime WorkRequest which finish setup process
* @return Instance of OneTimeWorkRequest
*/
@NonNull
- private static OneTimeWorkRequest createOneTimeFirstStartWorkRequest() {
- return new OneTimeWorkRequest.Builder(FirstStartWorker.class)
- .setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES)
- .addTag(AppConstants.WORK_GENERIC_TAG)
- .addTag(AppConstants.WORK_INITIALIZATION_TAG)
+ private static OneTimeWorkRequest createFinishSetupWorkRequest() {
+ return new OneTimeWorkRequest.Builder(FinishSetupWorker.class)
+ .setBackoffCriteria(LINEAR, 2, MINUTES)
+ .addTag(WORK_GENERIC_TAG)
+ .addTag(WORK_SETUP_TAG)
.build();
}
diff --git a/app/src/test/java/foundation/e/drive/contentScanner/FileDiffUtilsTest.kt b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtilsTest.kt
similarity index 99%
rename from app/src/test/java/foundation/e/drive/contentScanner/FileDiffUtilsTest.kt
rename to app/src/test/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtilsTest.kt
index 8bae8a20bdb1d840fe044c581c88a25a2c76446a..f078df1d2bc0eef1bbd7e5df11527f216460ab4a 100644
--- a/app/src/test/java/foundation/e/drive/contentScanner/FileDiffUtilsTest.kt
+++ b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/FileDiffUtilsTest.kt
@@ -5,10 +5,11 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner
+package foundation.e.drive.periodicScan.contentScanner
import com.owncloud.android.lib.resources.files.model.RemoteFile
import foundation.e.drive.models.SyncedFileState
+import foundation.e.drive.periodicScan.contentScanner.FileDiffUtils
import org.junit.Assert
import org.junit.Test
import org.mockito.Mockito
diff --git a/app/src/test/java/foundation/e/drive/contentScanner/LocalContentScannerTest.java b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScannerTest.java
similarity index 98%
rename from app/src/test/java/foundation/e/drive/contentScanner/LocalContentScannerTest.java
rename to app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScannerTest.java
index e57efbf6383017b08e88d4e122eff293a0abab59..6468357ae399d682b4a208049dd3c3d3207966d3 100644
--- a/app/src/test/java/foundation/e/drive/contentScanner/LocalContentScannerTest.java
+++ b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalContentScannerTest.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static org.mockito.Mockito.when;
import static foundation.e.drive.models.SyncedFileStateKt.SCAN_EVERYWHERE;
@@ -33,6 +33,7 @@ import java.util.List;
import foundation.e.drive.models.SyncRequest;
import foundation.e.drive.models.SyncedFileState;
import foundation.e.drive.models.SyncedFolder;
+import foundation.e.drive.periodicScan.contentScanner.LocalContentScanner;
/**
* @author vincent Bourgmayer
diff --git a/app/src/test/java/foundation/e/drive/contentScanner/LocalFileListerTest.java b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalFileListerTest.java
similarity index 98%
rename from app/src/test/java/foundation/e/drive/contentScanner/LocalFileListerTest.java
rename to app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalFileListerTest.java
index 40e41d2ce12206ca56a59ea6ef965613e1c93482..38a6907050e3133747815328f1f07756e197e068 100644
--- a/app/src/test/java/foundation/e/drive/contentScanner/LocalFileListerTest.java
+++ b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/LocalFileListerTest.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static foundation.e.drive.models.SyncedFileStateKt.SCAN_EVERYWHERE;
@@ -36,6 +36,8 @@ import foundation.e.drive.TestUtils;
import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFileState;
import foundation.e.drive.models.SyncedFolder;
+import foundation.e.drive.periodicScan.contentScanner.FolderWrapper;
+import foundation.e.drive.periodicScan.contentScanner.LocalFileLister;
/**
* @author vincent Bourgmayer
diff --git a/app/src/test/java/foundation/e/drive/contentScanner/RemoteContentScannerTest.java b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScannerTest.java
similarity index 98%
rename from app/src/test/java/foundation/e/drive/contentScanner/RemoteContentScannerTest.java
rename to app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScannerTest.java
index 476d96166759c33677d5260be9506ebaae749674..a985db22d10da44ecaea06643c7da89e599e9365 100644
--- a/app/src/test/java/foundation/e/drive/contentScanner/RemoteContentScannerTest.java
+++ b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteContentScannerTest.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static org.junit.Assert.assertEquals;
@@ -36,6 +36,7 @@ import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncRequest;
import foundation.e.drive.models.SyncedFileState;
import foundation.e.drive.models.SyncedFolder;
+import foundation.e.drive.periodicScan.contentScanner.RemoteContentScanner;
/**
* @author vincent Bourgmayer
diff --git a/app/src/test/java/foundation/e/drive/contentScanner/RemoteFileListerTest.java b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileListerTest.java
similarity index 99%
rename from app/src/test/java/foundation/e/drive/contentScanner/RemoteFileListerTest.java
rename to app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileListerTest.java
index c421c8a72006aa8b044dc8eeb63c0605e3558198..2f4c9e7ad481f9f2d12afebdbad52a8122fe8404 100644
--- a/app/src/test/java/foundation/e/drive/contentScanner/RemoteFileListerTest.java
+++ b/app/src/test/java/foundation/e/drive/periodicScan/contentScanner/RemoteFileListerTest.java
@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
-package foundation.e.drive.contentScanner;
+package foundation.e.drive.periodicScan.contentScanner;
import static org.mockito.Mockito.when;
@@ -41,6 +41,7 @@ import foundation.e.drive.TestUtils;
import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFileState;
import foundation.e.drive.models.SyncedFolder;
+import foundation.e.drive.periodicScan.contentScanner.RemoteFileLister;
import foundation.e.drive.utils.DavClientProvider;
/**
diff --git a/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java b/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java
deleted file mode 100644
index 998157602efeb7a6b112107d884f02aedf119506..0000000000000000000000000000000000000000
--- a/app/src/test/java/foundation/e/drive/services/AbstractServiceIT.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package foundation.e.drive.services;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Service;
-import android.app.job.JobScheduler;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.ConnectivityManager;
-import android.os.Build;
-
-import org.junit.BeforeClass;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.android.controller.ServiceController;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLog;
-
-import foundation.e.drive.TestUtils;
-import foundation.e.drive.database.DbHelper;
-import foundation.e.drive.utils.AppConstants;
-import static foundation.e.drive.TestUtils.TEST_ACCOUNT_NAME;
-import static foundation.e.drive.TestUtils.TEST_ACCOUNT_TYPE;
-import static foundation.e.drive.utils.AppConstants.MEDIA_SYNC_PROVIDER_AUTHORITY;
-import static foundation.e.drive.utils.AppConstants.SETTINGS_SYNC_PROVIDER_AUTHORITY;
-
-import com.nextcloud.common.NextcloudClient;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(sdk = Build.VERSION_CODES.O, manifest = Config.NONE)
-public abstract class AbstractServiceIT {
-
- /**
- * By making the below field static it is done once
- * for all test class that extends this instead of
- * one time by class.
- */
- protected static Context context;
-
- protected T mService;
- protected ServiceController mServiceController;
-
- protected AccountManager accountManager;
- protected ContentResolver contentResolver;
- protected SharedPreferences sharedPreferences;
- protected ConnectivityManager connectivityManager;
- protected JobScheduler jobScheduler;
- protected DbHelper dbHelper;
- protected NextcloudClient client;
- protected int initial_folder_number=0; //number of folders to sync at initialization
- protected long last_sync_time=0l; //Timestamp of the end of the last synchronisation
- protected boolean init_done = true; //true if InitializerService did its job
- protected boolean oms_running=false; //true if OperationManagerService is already running
-
- @BeforeClass
- public static void beforeAll(){
- TestUtils.loadServerCredentials();
- ShadowLog.stream = System.out; //give access to log
- }
-
- /**
- * Create and register one validAccount
- */
- protected void prepareValidAccount(){
- TestUtils.prepareValidAccount(accountManager);
- }
-
- /**
- * enable Media & settings sync
- */
- protected void enableMediaAndSettingsSync(Account account){ //replace this by robolectric the contentResolver
- contentResolver.setSyncAutomatically(account, MEDIA_SYNC_PROVIDER_AUTHORITY, true);
- contentResolver.setSyncAutomatically(account, SETTINGS_SYNC_PROVIDER_AUTHORITY, true);
- }
-
- /**
- * disable Media & enable settings sync
- */
- protected void disableMediaSync(Account account){ //replace this by robolectric the contentResolver
- contentResolver.setSyncAutomatically(account, MEDIA_SYNC_PROVIDER_AUTHORITY, false);
- contentResolver.setSyncAutomatically(account, SETTINGS_SYNC_PROVIDER_AUTHORITY, true);
- }
-
- /**
- * enable Media and disable settings sync
- */
- protected void disableSettingsSync(Account account){ //replace this by robolectric the contentResolver
- contentResolver.setSyncAutomatically(account, MEDIA_SYNC_PROVIDER_AUTHORITY, true);
- contentResolver.setSyncAutomatically(account, SETTINGS_SYNC_PROVIDER_AUTHORITY, false);
- }
-
- /**
- * disable Media & settings sync
- */
- protected void disableMediaAndSettingsSync(Account account){ //replace this by robolectric the contentResolver
- contentResolver.setSyncAutomatically(account, MEDIA_SYNC_PROVIDER_AUTHORITY, false);
- contentResolver.setSyncAutomatically(account, SETTINGS_SYNC_PROVIDER_AUTHORITY, false);
- }
-
- /**
- * Register sharedPreferences common to all services
- * - OMS is working (bool)
- * - Account name (String)
- * - Account type (String)
- * - initial folders number (int)
- * - last sync time (long)
- * - Initialization has been done (bool)
- *
- * Use default value of the instance field
- * So update the field before to call this to store specific value
- */
- protected void registerSharedPref(){
- sharedPreferences.edit().putBoolean( AppConstants.SETUP_COMPLETED, init_done)
- .putString(AccountManager.KEY_ACCOUNT_NAME, TEST_ACCOUNT_NAME)
- .putString(AccountManager.KEY_ACCOUNT_TYPE, TEST_ACCOUNT_TYPE)
- .putInt(AppConstants.INITIAL_FOLDER_NUMBER, initial_folder_number)
- .putLong(AppConstants.KEY_LAST_SYNC_TIME, last_sync_time)
- .apply();
- }
-}