From 384accb519ae43371001219a08e15a6c668249b3 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Thu, 2 Feb 2023 17:27:29 +0100 Subject: [PATCH 1/8] add specific worker for listing installed app --- .../e/drive/services/ObserverService.java | 38 +------ .../e/drive/work/ListAppsWorker.java | 107 ++++++++++++++++++ 2 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/work/ListAppsWorker.java 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 418b28df..7d608a6d 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -1,6 +1,6 @@ /* * Copyright © CLEUS SAS 2018-2019. - * Copyright © ECORP SAS 2022. + * Copyright © MURENA 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 @@ -9,7 +9,6 @@ package foundation.e.drive.services; -import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; import android.accounts.Account; @@ -19,7 +18,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -33,7 +31,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.resources.files.model.RemoteFile; import java.io.File; -import java.io.FileOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -362,44 +359,13 @@ public class ObserverService extends Service implements OnRemoteOperationListene /* Methods related to device Scanning */ - /** - * 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() { - Timber.d("generateAppListFile()"); - final List packagesInfo = getPackageManager().getInstalledPackages(0); - - final StringBuilder fileContents = new StringBuilder(); - for(int i =-1, size = packagesInfo.size(); ++i < size;) { - PackageInfo currentPackage = packagesInfo.get(i); - fileContents.append( currentPackage.packageName).append(",").append(currentPackage.versionName).append("\n"); - } - try { - final FileOutputStream tmp = openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE); - tmp.write(fileContents.toString().getBytes()); - tmp.close(); - - final String filesdir = getFilesDir().getCanonicalPath()+PATH_SEPARATOR; - final File tmp_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); - final File real_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME); - - if (tmp_file.length() != real_file.length()) { - tmp_file.renameTo(real_file); - } else { - tmp_file.delete(); - } - } catch (Exception exception) { - Timber.w(exception); - } - } + /** * Prepare the list of files and SyncedFileState for synchronisation */ private void scanLocalFiles(){ Timber.i("scanLocalFiles()"); - if (CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile(); final LocalFileLister fileLister = new LocalFileLister(mSyncedFolders); diff --git a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java new file mode 100644 index 00000000..3a4d0089 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -0,0 +1,107 @@ +/* + * Copyright © MURENA 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 static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.database.Cursor; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.List; + +import foundation.e.drive.utils.AppConstants; +import timber.log.Timber; + +/** + * Class responsible for building a list of installed app and save that in a file that must be synchronized + * @author vincent Bourgmayer + */ +public class ListAppsWorker extends Worker { + public final static String UNIQUE_WORK_NAME = "ListApps"; + private final static String SEPARATOR =","; + + public ListAppsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + Timber.d("generateAppListFile()"); + final Context context = getApplicationContext(); + final StringBuilder fileContents = listRegularApps(context); + listPWAs(context, fileContents); + if (fileContents.length() == 0) return Result.success(); + + final boolean success = WriteToFile(fileContents); + return success ? Result.success() : Result.failure(); + } + + private StringBuilder listRegularApps(@NonNull final Context context) { + final List packagesInfo = context.getPackageManager().getInstalledPackages(0); + final StringBuilder result = new StringBuilder(); + for (PackageInfo currentPkg : packagesInfo) { + result.append( currentPkg.packageName).append(SEPARATOR).append(currentPkg.versionName).append("\n"); + } + return result; + } + + private void listPWAs(@NonNull final Context context, @NonNull final StringBuilder stringBuilder) { + final String PWA_PLAYER = "content://foundation.e.pwaplayer.provider/pwa"; + final Cursor cursor = context.getContentResolver().query( + Uri.parse(PWA_PLAYER), null, null, null, null); + + if (cursor.getCount() <= 0) return; + + stringBuilder.append("\n---- PWAs ----\n"); + cursor.moveToFirst(); + do { + try { + final String pwaTitle = cursor.getString(cursor.getColumnIndexOrThrow("title")); + final String pwaUrl = cursor.getString(cursor.getColumnIndexOrThrow("url")); + final Long pwaDbId = cursor.getLong(cursor.getColumnIndexOrThrow("_id")); + stringBuilder.append(pwaDbId).append(SEPARATOR).append(pwaTitle).append(SEPARATOR).append(pwaUrl).append("\n"); + + } catch (IllegalArgumentException exception) { + Timber.e(exception, "Catched exception: invalid column names for cursor"); + } + } while (cursor.moveToNext()); + cursor.close(); + } + + private boolean WriteToFile(@NonNull final StringBuilder fileContents) { + try { + final FileOutputStream tmp = getApplicationContext().openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE); + tmp.write(fileContents.toString().getBytes()); + tmp.close(); + + final String filesdir = getApplicationContext().getFilesDir().getCanonicalPath()+PATH_SEPARATOR; + final File tmp_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); + final File real_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME); + + if (tmp_file.length() != real_file.length()) { + tmp_file.renameTo(real_file); + } else { + tmp_file.delete(); + } + } catch (Exception exception) { + Timber.e(exception, "catched exception: can't write app list in file"); + return false; + } + return true; + } +} \ No newline at end of file -- GitLab From f853ccc77088cdfcbea77467c2067785f3d2f201 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Fri, 3 Feb 2023 10:08:46 +0100 Subject: [PATCH 2/8] refactoring triggering periodic work: periodic sync & apps list file generation --- .../foundation/e/drive/utils/CommonUtils.java | 13 ----------- .../e/drive/work/FirstStartWorker.java | 22 ++++++++++++++++--- .../e/drive/work/WorkRequestFactory.java | 15 ++++++++++++- 3 files changed, 33 insertions(+), 17 deletions(-) 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 3f488756..ff7b6886 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -42,7 +42,6 @@ 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.work.FullScanWorker; import foundation.e.drive.work.WorkRequestFactory; import timber.log.Timber; @@ -274,18 +273,6 @@ public abstract class CommonUtils { return String.format(Locale.ENGLISH, "%.1f %cB", value / 1024.0, ci.current()); } - /** - * Enqueue a unique periodic worker to look for file to be synchronized (remote files + local files - * - * @param workManager the instance of workManager - */ - public static void registerPeriodicFullScanWorker(WorkManager workManager) { - workManager.enqueueUniquePeriodicWork(FullScanWorker.UNIQUE_WORK_NAME, - ExistingPeriodicWorkPolicy.KEEP, - WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.FULL_SCAN)); - } - - /** * This method create a chain of WorkRequests to perform Initialization tasks: * Firstly, it creates WorkRequest to create remote root folders on ecloud diff --git a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java index 4898f79b..897f5d62 100644 --- a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java +++ b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java @@ -1,5 +1,5 @@ /* - * Copyright © ECORP SAS 2022. + * Copyright © MURENA 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 @@ -14,13 +14,13 @@ 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 foundation.e.drive.utils.CommonUtils; import timber.log.Timber; /** @@ -47,7 +47,8 @@ public class FirstStartWorker extends Worker { .putInt(INITIALFOLDERS_NUMBER, 9) .apply(); - CommonUtils.registerPeriodicFullScanWorker(WorkManager.getInstance(appContext)); + + registerPeriodicWork(appContext); getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.SynchronizationService.class)); getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class)); @@ -57,4 +58,19 @@ public class FirstStartWorker extends Worker { return Result.success(); } + + + private void registerPeriodicWork(@NonNull final Context context) { + final WorkManager workManager = WorkManager.getInstance(context); + + //Generate apps list file + workManager.enqueueUniquePeriodicWork(ListAppsWorker.UNIQUE_WORK_NAME, + ExistingPeriodicWorkPolicy.KEEP, + WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.PERIODIC_APP_LIST)); + + //Periodic sync + workManager.enqueueUniquePeriodicWork(FullScanWorker.UNIQUE_WORK_NAME, + ExistingPeriodicWorkPolicy.KEEP, + WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.FULL_SCAN)); + } } 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 e3daf516..b3a0894f 100644 --- a/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java +++ b/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java @@ -29,6 +29,7 @@ public class WorkRequestFactory { public enum WorkType { FULL_SCAN, PERIODIC_USER_INFO, + PERIODIC_APP_LIST, ONE_TIME_USER_INFO, CREATE_REMOTE_DIR, FIRST_START @@ -36,7 +37,7 @@ public class WorkRequestFactory { /** * Build an instance of PeriodicWorkRequest depending of the work type specified - * @param type WorkType. Should be FULL_SCAN or PERIODIC_USER_INFO. + * @param type WorkType. Should be FULL_SCAN or PERIODIC_USER_INFO or PERIODIC_APP_LIST * If not, it will throw an InvalidParameterException * @return Periodic WorkRequest */ @@ -46,11 +47,23 @@ public class WorkRequestFactory { return createPeriodicFullScanWorkRequest(); case PERIODIC_USER_INFO: return createPeriodicGetUserInfoWorkRequest(); + case PERIODIC_APP_LIST: + return createPeriodicAppListGenerationWorkRequest(); default: throw new InvalidParameterException("Unsupported Work Type: " + type); } } + private static PeriodicWorkRequest createPeriodicAppListGenerationWorkRequest() { + final PeriodicWorkRequest workRequest = + new PeriodicWorkRequest.Builder(ListAppsWorker.class, + 6, TimeUnit.HOURS, + 1, TimeUnit.HOURS) + .addTag(AppConstants.WORK_GENERIC_TAG) + .build(); + return workRequest; + } + /** * Build an instance of OneTimeWorkRequest depending of the work type specified. * @param type Should be ONE_TIME_USER_INFO, or FIRST_START, or CREATE_REMOTE_DIR -- GitLab From 11de596cd6fdaa5388cb7db97a2e20fda2a275e9 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 6 Feb 2023 09:18:15 +0100 Subject: [PATCH 3/8] apply Jonathan's suggestion --- .../e/drive/work/FirstStartWorker.java | 10 +++++----- .../e/drive/work/ListAppsWorker.java | 20 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java index 897f5d62..62c34eb2 100644 --- a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java +++ b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java @@ -9,6 +9,8 @@ package foundation.e.drive.work; import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; +import static foundation.e.drive.work.WorkRequestFactory.WorkType.FULL_SCAN; +import static foundation.e.drive.work.WorkRequestFactory.WorkType.PERIODIC_APP_LIST; import android.content.Context; import android.content.Intent; @@ -47,7 +49,6 @@ public class FirstStartWorker extends Worker { .putInt(INITIALFOLDERS_NUMBER, 9) .apply(); - registerPeriodicWork(appContext); getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.SynchronizationService.class)); @@ -59,18 +60,17 @@ public class FirstStartWorker extends Worker { return Result.success(); } - private void registerPeriodicWork(@NonNull final Context context) { final WorkManager workManager = WorkManager.getInstance(context); //Generate apps list file workManager.enqueueUniquePeriodicWork(ListAppsWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, - WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.PERIODIC_APP_LIST)); + WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_APP_LIST)); //Periodic sync workManager.enqueueUniquePeriodicWork(FullScanWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, - WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.FULL_SCAN)); + WorkRequestFactory.getPeriodicWorkRequest(FULL_SCAN)); } -} +} \ 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/work/ListAppsWorker.java index 3a4d0089..b87e464d 100644 --- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -21,6 +21,7 @@ import androidx.work.WorkerParameters; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.util.List; import foundation.e.drive.utils.AppConstants; @@ -32,6 +33,7 @@ import timber.log.Timber; */ public class ListAppsWorker extends Worker { public final static String UNIQUE_WORK_NAME = "ListApps"; + private final static String PWA_PLAYER = "content://foundation.e.pwaplayer.provider/pwa"; private final static String SEPARATOR =","; public ListAppsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { @@ -47,7 +49,7 @@ public class ListAppsWorker extends Worker { listPWAs(context, fileContents); if (fileContents.length() == 0) return Result.success(); - final boolean success = WriteToFile(fileContents); + final boolean success = writeToFile(fileContents); return success ? Result.success() : Result.failure(); } @@ -61,7 +63,6 @@ public class ListAppsWorker extends Worker { } private void listPWAs(@NonNull final Context context, @NonNull final StringBuilder stringBuilder) { - final String PWA_PLAYER = "content://foundation.e.pwaplayer.provider/pwa"; final Cursor cursor = context.getContentResolver().query( Uri.parse(PWA_PLAYER), null, null, null, null); @@ -83,22 +84,21 @@ public class ListAppsWorker extends Worker { cursor.close(); } - private boolean WriteToFile(@NonNull final StringBuilder fileContents) { - try { - final FileOutputStream tmp = getApplicationContext().openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE); + private boolean writeToFile(@NonNull final StringBuilder fileContents) { + try (final FileOutputStream tmp = getApplicationContext().openFileOutput(AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP, Context.MODE_PRIVATE); + ) { tmp.write(fileContents.toString().getBytes()); - tmp.close(); - final String filesdir = getApplicationContext().getFilesDir().getCanonicalPath()+PATH_SEPARATOR; - final File tmp_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); - final File real_file = new File(filesdir+AppConstants.APPLICATIONS_LIST_FILE_NAME); + final String filesDir = getApplicationContext().getFilesDir().getCanonicalPath()+PATH_SEPARATOR; + final File tmp_file = new File(filesDir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); + final File real_file = new File(filesDir+AppConstants.APPLICATIONS_LIST_FILE_NAME); if (tmp_file.length() != real_file.length()) { tmp_file.renameTo(real_file); } else { tmp_file.delete(); } - } catch (Exception exception) { + } catch (IOException exception) { Timber.e(exception, "catched exception: can't write app list in file"); return false; } -- GitLab From 43386fd74f227781fad968c169be9e8e35a6a729 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 6 Feb 2023 10:07:26 +0100 Subject: [PATCH 4/8] implement a workaround to chain periodic work requests --- .../e/drive/work/FirstStartWorker.java | 12 +- .../e/drive/work/ListAppsWorker.java | 2 +- .../e/drive/work/PeriodicWorker.java | 52 ++++++++ .../e/drive/work/WorkRequestFactory.java | 115 ++++++++++-------- 4 files changed, 122 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/work/PeriodicWorker.java diff --git a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java index 62c34eb2..c97e8937 100644 --- a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java +++ b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java @@ -9,8 +9,7 @@ package foundation.e.drive.work; import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; -import static foundation.e.drive.work.WorkRequestFactory.WorkType.FULL_SCAN; -import static foundation.e.drive.work.WorkRequestFactory.WorkType.PERIODIC_APP_LIST; +import static foundation.e.drive.work.WorkRequestFactory.WorkType.PERIODIC_SCAN; import android.content.Context; import android.content.Intent; @@ -64,13 +63,8 @@ public class FirstStartWorker extends Worker { final WorkManager workManager = WorkManager.getInstance(context); //Generate apps list file - workManager.enqueueUniquePeriodicWork(ListAppsWorker.UNIQUE_WORK_NAME, + workManager.enqueueUniquePeriodicWork(PeriodicWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, - WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_APP_LIST)); - - //Periodic sync - workManager.enqueueUniquePeriodicWork(FullScanWorker.UNIQUE_WORK_NAME, - ExistingPeriodicWorkPolicy.KEEP, - WorkRequestFactory.getPeriodicWorkRequest(FULL_SCAN)); + WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_SCAN)); } } \ 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/work/ListAppsWorker.java index b87e464d..563707c7 100644 --- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -1,5 +1,5 @@ /* - * Copyright © MURENA SAS 2022. + * 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 diff --git a/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java b/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java new file mode 100644 index 00000000..838628ba --- /dev/null +++ b/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java @@ -0,0 +1,52 @@ +/* + * 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.work; + +import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_APP_LIST; +import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_FULL_SCAN; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.ExistingWorkPolicy; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import java.util.List; + +/** + * Worker that trigger the chain of worker that really need to be periodic + * This worker is required because we cannot chain periodic work through WorkerAPI + * 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) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + final WorkManager workManager = WorkManager.getInstance(getApplicationContext()); + + final List workRequestsLists = List.of( + WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_APP_LIST, null), + WorkRequestFactory.getOneTimeWorkRequest(ONE_TIME_FULL_SCAN, null)); + + workManager.beginUniqueWork(FullScanWorker.UNIQUE_WORK_NAME, ExistingWorkPolicy.KEEP, workRequestsLists) + .enqueue(); + + return Result.success(); + } +} \ 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 b3a0894f..02def9d4 100644 --- a/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java +++ b/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java @@ -27,9 +27,10 @@ import foundation.e.drive.utils.AppConstants; public class WorkRequestFactory { public enum WorkType { - FULL_SCAN, PERIODIC_USER_INFO, - PERIODIC_APP_LIST, + PERIODIC_SCAN, + ONE_TIME_FULL_SCAN, + ONE_TIME_APP_LIST, ONE_TIME_USER_INFO, CREATE_REMOTE_DIR, FIRST_START @@ -43,27 +44,50 @@ public class WorkRequestFactory { */ public static PeriodicWorkRequest getPeriodicWorkRequest(WorkType type) { switch (type) { - case FULL_SCAN: - return createPeriodicFullScanWorkRequest(); + case PERIODIC_SCAN: + return createPeriodicScanWorkRequest(); case PERIODIC_USER_INFO: return createPeriodicGetUserInfoWorkRequest(); - case PERIODIC_APP_LIST: - return createPeriodicAppListGenerationWorkRequest(); default: throw new InvalidParameterException("Unsupported Work Type: " + type); } } - private static PeriodicWorkRequest createPeriodicAppListGenerationWorkRequest() { + /** + * Create a PeridocWorkRequest instance for + * a Full scan with constraints on network (should + * be unmetered) and battery (shouldn't be low) + * @return instance of PeriodicWorkRequest + */ + private static PeriodicWorkRequest createPeriodicScanWorkRequest() { + final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints(); + final PeriodicWorkRequest workRequest = - new PeriodicWorkRequest.Builder(ListAppsWorker.class, - 6, TimeUnit.HOURS, - 1, TimeUnit.HOURS) + new PeriodicWorkRequest.Builder(PeriodicWorker.class, + 26, TimeUnit.MINUTES, 5, TimeUnit.MINUTES) + .setConstraints(constraints) .addTag(AppConstants.WORK_GENERIC_TAG) .build(); return workRequest; } + /** + * Create a periodic work request to get userInfo + * @return instance of PeriodicWorkRequest + */ + private static PeriodicWorkRequest createPeriodicGetUserInfoWorkRequest() { + final Constraints constraints = new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build(); + + final PeriodicWorkRequest workRequest = + new PeriodicWorkRequest.Builder(AccountUserInfoWorker.class, + 30, TimeUnit.MINUTES) + .addTag(AppConstants.WORK_GENERIC_TAG) + .setConstraints(constraints) + .build(); + return workRequest; + } /** * Build an instance of OneTimeWorkRequest depending of the work type specified. * @param type Should be ONE_TIME_USER_INFO, or FIRST_START, or CREATE_REMOTE_DIR @@ -73,6 +97,10 @@ public class WorkRequestFactory { */ public static OneTimeWorkRequest getOneTimeWorkRequest(WorkType type, @Nullable SyncedFolder syncedFolder) { switch (type) { + case ONE_TIME_APP_LIST: + return createOneTimeAppListGenerationWorkRequest(); + case ONE_TIME_FULL_SCAN: + return createOneTimeFullScanWorkRequest(); case ONE_TIME_USER_INFO: return createOneTimeGetUserInfoWorkRequest(); case FIRST_START: @@ -85,44 +113,34 @@ public class WorkRequestFactory { } } - - /** - * Create a PeridocWorkRequest instance for - * a Full scan with constraints on network (should - * be unmetered) and battery (shouldn't be low) - * @return instance of PeriodicWorkRequest - */ - private static PeriodicWorkRequest createPeriodicFullScanWorkRequest() { - final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints(); - - final PeriodicWorkRequest workRequest = - new PeriodicWorkRequest.Builder(FullScanWorker.class, - 31, TimeUnit.MINUTES, - 5, TimeUnit.MINUTES) - .setConstraints(constraints) + private static OneTimeWorkRequest createOneTimeAppListGenerationWorkRequest() { + final OneTimeWorkRequest workRequest = + new OneTimeWorkRequest.Builder(ListAppsWorker.class) + .setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES) .addTag(AppConstants.WORK_GENERIC_TAG) .build(); return workRequest; } /** - * Create a periodic work request to get userInfo - * @return instance of PeriodicWorkRequest + * Create a OneTimeWorkRequest instance for + * a Full scan with constraints on network (should + * be unmetered) and battery (shouldn't be low) + * @return instance of OneTimeWorkRequest */ - private static PeriodicWorkRequest createPeriodicGetUserInfoWorkRequest() { - final Constraints constraints = new Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build(); + private static OneTimeWorkRequest createOneTimeFullScanWorkRequest() { + final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints(); - final PeriodicWorkRequest workRequest = - new PeriodicWorkRequest.Builder(AccountUserInfoWorker.class, - 30, TimeUnit.MINUTES) - .addTag(AppConstants.WORK_GENERIC_TAG) - .setConstraints(constraints) - .build(); + final OneTimeWorkRequest workRequest = + new OneTimeWorkRequest.Builder(FullScanWorker.class) + .setBackoffCriteria(BackoffPolicy.LINEAR, 2, TimeUnit.MINUTES) + .setConstraints(constraints) + .addTag(AppConstants.WORK_GENERIC_TAG) + .build(); return workRequest; } + /** * Instanciate a OneTimeWorkRequest to retrieve user info * @return instance of OneTimeWorkRequest @@ -186,7 +204,6 @@ public class WorkRequestFactory { return constraint; } - /** * Parse SyncedFolder instance in Data, used as data for WorkRequest * @param folder SyncedFolder instance @@ -194,16 +211,16 @@ public class WorkRequestFactory { */ private static Data createDataFromSyncedFolder(SyncedFolder folder) { return new Data.Builder() - .putInt(DATA_KEY_ID, folder.getId()) - .putString(DATA_KEY_LIBELLE, folder.getLibelle()) - .putString(DATA_KEY_LOCAL_PATH, folder.getLocalFolder()) - .putString(DATA_KEY_REMOTE_PATH, folder.getRemoteFolder()) - .putString(DATA_KEY_LAST_ETAG, folder.getLastEtag()) - .putLong(DATA_KEY_LAST_MODIFIED, folder.getLastModified()) - .putBoolean(DATA_KEY_SCAN_LOCAL, folder.isScanLocal()) - .putBoolean(DATA_KEY_SCAN_REMOTE, folder.isScanRemote()) - .putBoolean(DATA_KEY_ENABLE, folder.isEnabled()) - .putBoolean(DATA_KEY_MEDIATYPE, folder.isMediaType()) - .build(); + .putInt(DATA_KEY_ID, folder.getId()) + .putString(DATA_KEY_LIBELLE, folder.getLibelle()) + .putString(DATA_KEY_LOCAL_PATH, folder.getLocalFolder()) + .putString(DATA_KEY_REMOTE_PATH, folder.getRemoteFolder()) + .putString(DATA_KEY_LAST_ETAG, folder.getLastEtag()) + .putLong(DATA_KEY_LAST_MODIFIED, folder.getLastModified()) + .putBoolean(DATA_KEY_SCAN_LOCAL, folder.isScanLocal()) + .putBoolean(DATA_KEY_SCAN_REMOTE, folder.isScanRemote()) + .putBoolean(DATA_KEY_ENABLE, folder.isEnabled()) + .putBoolean(DATA_KEY_MEDIATYPE, folder.isMediaType()) + .build(); } } -- GitLab From 0e739b790c155b01603d0b113481a09349dbd939 Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Mon, 6 Feb 2023 10:25:13 +0100 Subject: [PATCH 5/8] add or update licence headers --- .../e/drive/services/ObserverService.java | 8 +------- .../foundation/e/drive/utils/CommonUtils.java | 2 +- .../e/drive/work/FirstStartWorker.java | 6 ++---- .../foundation/e/drive/work/PeriodicWorker.java | 1 - .../e/drive/work/WorkRequestFactory.java | 17 +++++++++++++---- 5 files changed, 17 insertions(+), 17 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 7d608a6d..46b351bf 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -1,6 +1,6 @@ /* * Copyright © CLEUS SAS 2018-2019. - * Copyright © MURENA 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 @@ -220,7 +220,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } - /** * Clear cached file unused: * remove each cached file which isn't in OperationManagerService.lockedSyncedFileState(); @@ -357,10 +356,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } } - /* Methods related to device Scanning */ - - - /** * Prepare the list of files and SyncedFileState for synchronisation */ @@ -386,7 +381,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene syncRequests.putAll(scanner.scanContent(fileList, syncedFileStates)); } } - /* end of methods related to device Scanning */ @Nullable @Override 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 ff7b6886..9a6ba862 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -1,6 +1,6 @@ /* * Copyright © CLEUS SAS 2018-2019. - * Copyright © ECORP SAS 2022. + * Copyright © ECORP 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 diff --git a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java index c97e8937..6663c143 100644 --- a/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java +++ b/app/src/main/java/foundation/e/drive/work/FirstStartWorker.java @@ -1,5 +1,5 @@ /* - * Copyright © MURENA 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 @@ -39,7 +39,7 @@ public class FirstStartWorker extends Worker { @NonNull @Override public Result doWork() { - Timber.v("doWork()"); + Timber.v("FirstStartWorker.doWork()"); final Context appContext = getApplicationContext(); appContext.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) @@ -53,7 +53,6 @@ public class FirstStartWorker extends Worker { getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.SynchronizationService.class)); getApplicationContext().startService(new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class)); - //all folder have been created ((EdriveApplication) getApplicationContext()).startRecursiveFileObserver(); return Result.success(); @@ -62,7 +61,6 @@ public class FirstStartWorker extends Worker { private void registerPeriodicWork(@NonNull final Context context) { final WorkManager workManager = WorkManager.getInstance(context); - //Generate apps list file workManager.enqueueUniquePeriodicWork(PeriodicWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.KEEP, WorkRequestFactory.getPeriodicWorkRequest(PERIODIC_SCAN)); diff --git a/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java b/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java index 838628ba..fb485654 100644 --- a/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java +++ b/app/src/main/java/foundation/e/drive/work/PeriodicWorker.java @@ -14,7 +14,6 @@ import static foundation.e.drive.work.WorkRequestFactory.WorkType.ONE_TIME_FULL_ import android.content.Context; import androidx.annotation.NonNull; -import androidx.work.ExistingPeriodicWorkPolicy; import androidx.work.ExistingWorkPolicy; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; 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 02def9d4..8627ceb6 100644 --- a/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java +++ b/app/src/main/java/foundation/e/drive/work/WorkRequestFactory.java @@ -1,3 +1,11 @@ +/* + * 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.work.CreateRemoteFolderWorker.DATA_KEY_ENABLE; @@ -11,6 +19,7 @@ import static foundation.e.drive.work.CreateRemoteFolderWorker.DATA_KEY_REMOTE_P import static foundation.e.drive.work.CreateRemoteFolderWorker.DATA_KEY_SCAN_LOCAL; import static foundation.e.drive.work.CreateRemoteFolderWorker.DATA_KEY_SCAN_REMOTE; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.work.BackoffPolicy; import androidx.work.Constraints; @@ -42,7 +51,7 @@ public class WorkRequestFactory { * If not, it will throw an InvalidParameterException * @return Periodic WorkRequest */ - public static PeriodicWorkRequest getPeriodicWorkRequest(WorkType type) { + public static PeriodicWorkRequest getPeriodicWorkRequest(@NonNull WorkType type) { switch (type) { case PERIODIC_SCAN: return createPeriodicScanWorkRequest(); @@ -95,7 +104,7 @@ public class WorkRequestFactory { * @param syncedFolder this parameter is required for CREATE_REMOTE_DIR work type. If null it will throw an NPE. * @return OneTimeWorkRequest's instance. */ - public static OneTimeWorkRequest getOneTimeWorkRequest(WorkType type, @Nullable SyncedFolder syncedFolder) { + public static OneTimeWorkRequest getOneTimeWorkRequest(@NonNull WorkType type, @Nullable SyncedFolder syncedFolder) { switch (type) { case ONE_TIME_APP_LIST: return createOneTimeAppListGenerationWorkRequest(); @@ -163,7 +172,7 @@ public class WorkRequestFactory { * @param syncedFolder SyncedFolder instance with data about folder to create * @return Instance OneTimeWorkRequest */ - private static OneTimeWorkRequest createOneTimeCreateRemoteFolderWorkRequest(SyncedFolder syncedFolder) { + private static OneTimeWorkRequest createOneTimeCreateRemoteFolderWorkRequest(@NonNull SyncedFolder syncedFolder) { final Constraints constraints = createUnmeteredNetworkAndHighBatteryConstraints(); final OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder( @@ -209,7 +218,7 @@ public class WorkRequestFactory { * @param folder SyncedFolder instance * @return Data instance */ - private static Data createDataFromSyncedFolder(SyncedFolder folder) { + private static Data createDataFromSyncedFolder(@NonNull SyncedFolder folder) { return new Data.Builder() .putInt(DATA_KEY_ID, folder.getId()) .putString(DATA_KEY_LIBELLE, folder.getLibelle()) -- GitLab From 37a01db75fc934327c3fc6a557ea2d28198b8051 Mon Sep 17 00:00:00 2001 From: Fahim Salam Chowdhury Date: Mon, 6 Feb 2023 10:04:42 +0000 Subject: [PATCH 6/8] Apply Fahim's suggestion --- .../foundation/e/drive/work/ListAppsWorker.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java index 563707c7..6a84432a 100644 --- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -57,7 +57,10 @@ public class ListAppsWorker extends Worker { final List packagesInfo = context.getPackageManager().getInstalledPackages(0); final StringBuilder result = new StringBuilder(); for (PackageInfo currentPkg : packagesInfo) { - result.append( currentPkg.packageName).append(SEPARATOR).append(currentPkg.versionName).append("\n"); + result.append( currentPkg.packageName) + .append(SEPARATOR) + .append(currentPkg.versionName) + .append("\n"); } return result; } @@ -70,17 +73,24 @@ public class ListAppsWorker extends Worker { stringBuilder.append("\n---- PWAs ----\n"); cursor.moveToFirst(); + do { try { final String pwaTitle = cursor.getString(cursor.getColumnIndexOrThrow("title")); final String pwaUrl = cursor.getString(cursor.getColumnIndexOrThrow("url")); final Long pwaDbId = cursor.getLong(cursor.getColumnIndexOrThrow("_id")); - stringBuilder.append(pwaDbId).append(SEPARATOR).append(pwaTitle).append(SEPARATOR).append(pwaUrl).append("\n"); + stringBuilder.append(pwaDbId) + .append(SEPARATOR) + .append(pwaTitle) + .append(SEPARATOR) + .append(pwaUrl) + .append("\n"); } catch (IllegalArgumentException exception) { Timber.e(exception, "Catched exception: invalid column names for cursor"); } } while (cursor.moveToNext()); + cursor.close(); } -- GitLab From 0447ecde55e6092de56be7cd66aa730faf9aea7f Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Mon, 6 Feb 2023 14:24:59 +0000 Subject: [PATCH 7/8] apply coding style fix from Sayantan --- app/src/main/java/foundation/e/drive/work/ListAppsWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java index 6a84432a..c21efea1 100644 --- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -57,7 +57,7 @@ public class ListAppsWorker extends Worker { final List packagesInfo = context.getPackageManager().getInstalledPackages(0); final StringBuilder result = new StringBuilder(); for (PackageInfo currentPkg : packagesInfo) { - result.append( currentPkg.packageName) + result.append(currentPkg.packageName) .append(SEPARATOR) .append(currentPkg.versionName) .append("\n"); @@ -99,7 +99,7 @@ public class ListAppsWorker extends Worker { ) { tmp.write(fileContents.toString().getBytes()); - final String filesDir = getApplicationContext().getFilesDir().getCanonicalPath()+PATH_SEPARATOR; + final String filesDir = getApplicationContext().getFilesDir().getCanonicalPath() + PATH_SEPARATOR; final File tmp_file = new File(filesDir+AppConstants.APPLICATIONS_LIST_FILE_NAME_TMP); final File real_file = new File(filesDir+AppConstants.APPLICATIONS_LIST_FILE_NAME); -- GitLab From 974f86aa740e06fe40fc96cca362706269bc6f5c Mon Sep 17 00:00:00 2001 From: vincent Bourgmayer Date: Tue, 7 Feb 2023 11:03:30 +0100 Subject: [PATCH 8/8] set PWA section separator as constant --- app/src/main/java/foundation/e/drive/work/ListAppsWorker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java index c21efea1..be79084d 100644 --- a/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java +++ b/app/src/main/java/foundation/e/drive/work/ListAppsWorker.java @@ -32,9 +32,9 @@ import timber.log.Timber; * @author vincent Bourgmayer */ public class ListAppsWorker extends Worker { - public final static String UNIQUE_WORK_NAME = "ListApps"; private final static String PWA_PLAYER = "content://foundation.e.pwaplayer.provider/pwa"; private final static String SEPARATOR =","; + private final static String PWA_SECTION_SEPARATOR = "\n---- PWAs ----\n"; public ListAppsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); @@ -71,7 +71,7 @@ public class ListAppsWorker extends Worker { if (cursor.getCount() <= 0) return; - stringBuilder.append("\n---- PWAs ----\n"); + stringBuilder.append(PWA_SECTION_SEPARATOR); cursor.moveToFirst(); do { -- GitLab