Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5aa533e3 authored by Vincent Bourgmayer's avatar Vincent Bourgmayer
Browse files

Merge branch '669-list-pwa' into 'main'

669 list pwa

See merge request !198
parents 2b2b7bb5 a534ba1d
Loading
Loading
Loading
Loading
Loading
+1 −41
Original line number Diff line number Diff line
/*
 * 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
@@ -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;
@@ -223,7 +220,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene
        }
    }


    /**
     * Clear cached file unused:
     * remove each cached file which isn't in OperationManagerService.lockedSyncedFileState();
@@ -360,46 +356,11 @@ 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<PackageInfo> 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);

@@ -420,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
+1 −14
Original line number Diff line number Diff line
/*
 * 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
@@ -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
+14 −6
Original line number Diff line number Diff line
/*
 * 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
@@ -9,18 +9,19 @@
package foundation.e.drive.work;

import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER;
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 foundation.e.drive.utils.CommonUtils;
import timber.log.Timber;

/**
@@ -38,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)
@@ -47,14 +48,21 @@ 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));

        //all folder have been created
        ((EdriveApplication) getApplicationContext()).startRecursiveFileObserver();

        return Result.success();
    }

    private void registerPeriodicWork(@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
+117 −0
Original line number Diff line number Diff line
/*
 * 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 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.io.IOException;
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 {
    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);
    }

    @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<PackageInfo> 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 Cursor cursor = context.getContentResolver().query(
                Uri.parse(PWA_PLAYER), null, null, null, null);

        if (cursor.getCount() <= 0) return;

        stringBuilder.append(PWA_SECTION_SEPARATOR);
        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());

            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 (IOException exception) {
            Timber.e(exception, "catched exception: can't write app list in file");
            return false;
        }
        return true;
    }
}
 No newline at end of file
+51 −0
Original line number Diff line number Diff line
/*
 * 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.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<OneTimeWorkRequest> 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
Loading