diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 289229b2aa8a50abea151c6b047ec39aa1a4a24b..8939223c09d463ad17d6e9ae99c34ca85521ab53 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -26,6 +26,7 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -36,7 +37,6 @@ import foundation.e.drive.receivers.ScreenOffReceiver; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.JobUtils; -import foundation.e.drive.utils.ServiceExceptionHandler; import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; @@ -44,15 +44,16 @@ import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES; import static foundation.e.drive.utils.AppConstants.SETTINGS_SYNCABLE_CATEGORIES; import androidx.annotation.Nullable; +import androidx.work.WorkManager; /** * @author Vincent Bourgmayer */ public class InitializerService extends Service implements OnRemoteOperationListener { - final private String TAG = InitializerService.class.getSimpleName(); - //Complex properties - private int existingRemoteFolderCounter; //@dev-only; Temporarily used to know if all remotePath exist - private List mSyncedFolders; //syncedFolders + private final String TAG = InitializerService.class.getSimpleName(); + + private int existingRemoteFolderCounter; //Temporarily used to know if all remotePath exist + private List mSyncedFolders; private OwnCloudClient mCloudClient; private Handler mHandler; private Account mAccount; @@ -63,7 +64,6 @@ public class InitializerService extends Service implements OnRemoteOperationList Log.i(TAG, "onCreate()"); super.onCreate(); this.existingRemoteFolderCounter = 0; - //JobUtils.scheduleInitializerJob(getApplicationContext()); } @Override @@ -74,10 +74,10 @@ public class InitializerService extends Service implements OnRemoteOperationList //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); - if( prefs.getBoolean( AppConstants.INITIALIZATION_HAS_BEEN_DONE, false ) ) { + if (prefs.getBoolean( AppConstants.INITIALIZATION_HAS_BEEN_DONE, false ) ) { JobUtils.scheduleScannerJob(this); Log.w(TAG, "Initializer has already been run"); - }else{ + } else { String accountName = prefs.getString( AccountManager.KEY_ACCOUNT_NAME, "" ); String accountType = prefs.getString( AccountManager.KEY_ACCOUNT_TYPE, "" ); @@ -86,23 +86,21 @@ public class InitializerService extends Service implements OnRemoteOperationList accountName = intent.getExtras().getString( AccountManager.KEY_ACCOUNT_NAME, "" ); accountType = intent.getExtras().getString( AccountManager.KEY_ACCOUNT_TYPE, "" ); - //If data come from intent, store them into pref because there aren't stored prefs.edit().putString( AccountManager.KEY_ACCOUNT_NAME, accountName ) .putString( AccountManager.KEY_ACCOUNT_TYPE, accountType ) .apply(); } - if(accountName.isEmpty() ) { + if (accountName.isEmpty() ) { Log.w(TAG, "Account's name not found. Neither in shared prefs nor in intent's extras"); - //JobUtils.stopScheduledJob(getApplicationContext(), JobUtils.InitializerJobId); stopSelf(); - }else{ + } else { this.mAccount = CommonUtils.getAccount( accountName, accountType, AccountManager.get(this) ); //Get OwnCloudlient if (this.mAccount != null) { this.mCloudClient = CommonUtils.getOwnCloudClient( this.mAccount, getApplicationContext()); start(); - }else { + } else { Log.w(TAG, "Got account is invalid."); stopSelf(); } @@ -123,7 +121,6 @@ public class InitializerService extends Service implements OnRemoteOperationList return; } - //Get categories of element to sync List syncCategories = new ArrayList<>(); if (CommonUtils.isMediaSyncEnabled(mAccount)) { @@ -134,7 +131,6 @@ public class InitializerService extends Service implements OnRemoteOperationList syncCategories.addAll(Arrays.asList(SETTINGS_SYNCABLE_CATEGORIES)); } - //Get SyncedFolders getInitialSyncedFolders(syncCategories); this.existingRemoteFolderCounter = 0; @@ -195,7 +191,7 @@ public class InitializerService extends Service implements OnRemoteOperationList false, true, false) ); - }catch (Exception e){ Log.e(TAG, e.toString()); } + } catch (Exception e){ Log.e(TAG, e.toString()); } break; } } @@ -212,15 +208,14 @@ public class InitializerService extends Service implements OnRemoteOperationList Log.i(TAG, "createNextRemoteFolder()"); this.restartFolderCreationCounter = 0; - if( this.mSyncedFolders == null || this.mSyncedFolders.isEmpty() ){ - //JobUtils.stopScheduledJob(getApplicationContext(), JobUtils.InitializerJobId); + if (this.mSyncedFolders == null || this.mSyncedFolders.isEmpty() ){ this.stopSelf(); } //It means that there are still folders to create - if( this.existingRemoteFolderCounter < this.mSyncedFolders.size() ){ + if (this.existingRemoteFolderCounter < this.mSyncedFolders.size() ){ - if( this.mHandler == null ) this.mHandler = new Handler(); + if (this.mHandler == null ) this.mHandler = new Handler(); CreateInitialFolderRemoteOperation createFolderOperation = new CreateInitialFolderRemoteOperation( @@ -230,11 +225,11 @@ public class InitializerService extends Service implements OnRemoteOperationList createFolderOperation.execute(this.mCloudClient, this, this.mHandler); - }else if(this.existingRemoteFolderCounter == this.mSyncedFolders.size() ){ + } else if (this.existingRemoteFolderCounter == this.mSyncedFolders.size() ){ doLastStep(); - }else{ + } else { Log.e(TAG, "this.existingRemoteFolderCounter : "+this.existingRemoteFolderCounter+" > this.mSyncedFolders.size() : "+this.mSyncedFolders.size() ); this.stopSelf(); } @@ -243,26 +238,26 @@ public class InitializerService extends Service implements OnRemoteOperationList @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { Log.i(TAG, "onRemoteOperationFinish()"); - if(operation instanceof CreateInitialFolderRemoteOperation){ + if (operation instanceof CreateInitialFolderRemoteOperation){ - if(result.isSuccess() || result.getCode() == RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS){ + if (result.isSuccess() || result.getCode() == RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS){ this.existingRemoteFolderCounter+=1; CreateNextRemoteFolder(); - }else if( result.getHttpCode() == 423 || result.getHttpCode() == 409){//file locked or conflict in result + } else if (result.getHttpCode() == 423 || result.getHttpCode() == 409){//file locked or conflict in result Log.e( TAG, result.getLogMessage() ); - if( this.restartFolderCreationCounter < 3) { + if (this.restartFolderCreationCounter < 3) { Log.w( TAG, " restart operation" ); operation.execute( this.mCloudClient, this, this.mHandler ); this.restartFolderCreationCounter+=1; - }else{ + } else { Log.e(TAG, "Remote folder's creation failed due to conflict with server"); stopSelf(); } - }else{ + } else { Log.e(TAG, result.getLogMessage()+" "+result.getHttpCode() ); stopSelf(); } @@ -275,8 +270,7 @@ public class InitializerService extends Service implements OnRemoteOperationList **/ private void doLastStep(){ Log.i(TAG, "doLastStep()"); - - Context appContext = getApplicationContext(); + final Context appContext = getApplicationContext(); appContext.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ) .edit() @@ -284,9 +278,11 @@ public class InitializerService extends Service implements OnRemoteOperationList .putInt( INITIALFOLDERS_NUMBER, mSyncedFolders.size() ) .apply(); + CommonUtils.registerPeriodicFullScanWorker(WorkManager.getInstance(appContext)); + //all folder have been created //JobUtils.stopScheduledJob(appContext, JobUtils.InitializerJobId); - JobUtils.scheduleScannerJob(appContext); + //JobUtils.scheduleScannerJob(appContext); Log.d(TAG, "RegisterReceiver: screenOffReceiver"); IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); @@ -299,7 +295,6 @@ public class InitializerService extends Service implements OnRemoteOperationList stopSelf(); - } @Override diff --git a/app/src/main/java/foundation/e/drive/services/ResetService.java b/app/src/main/java/foundation/e/drive/services/ResetService.java index dad3cb20a6b024884a57bb35bd0e62e24ee7e55a..e0e1bb530ad074092a073e71a377a5f167bfa0a6 100644 --- a/app/src/main/java/foundation/e/drive/services/ResetService.java +++ b/app/src/main/java/foundation/e/drive/services/ResetService.java @@ -27,6 +27,7 @@ import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; import androidx.annotation.Nullable; +import androidx.work.WorkManager; /** * @author Vincent Bourgmayer @@ -67,6 +68,9 @@ public class ResetService extends Service { //2. Stop the scheduledJob JobUtils.stopScheduledJob(this, JobUtils.ScannerJobId); //JobUtils.stopScheduledJob(this, JobUtils.InitializerJobId); + + WorkManager.getInstance(this).cancelAllWorkByTag(AppConstants.WORK_GENERIC_TAG); + //3. delete DB result = this.deleteDatabase(DbHelper.DATABASE_NAME); Log.d(TAG, "Remove Database: "+result); diff --git a/app/src/main/java/foundation/e/drive/utils/AppConstants.java b/app/src/main/java/foundation/e/drive/utils/AppConstants.java index 1e180424b8cb05744a5e37cb6f1d72a6f92d46a6..7506a525ee466e117113fcc3f5e778712f6ba2d7 100644 --- a/app/src/main/java/foundation/e/drive/utils/AppConstants.java +++ b/app/src/main/java/foundation/e/drive/utils/AppConstants.java @@ -40,7 +40,7 @@ public abstract class AppConstants { public final static String notificationChannelID ="3310"; public final static String notificationChannelName="eDrive channel"; - + public final static String WORK_GENERIC_TAG="eDrive"; public final static String USER_AGENT = "eos("+getBuildTime()+")-eDrive("+ BuildConfig.VERSION_NAME +")"; 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 e0f762fcb4f2d104db8baa88938f26276ddbee85..5ba7a072c956ccbd29df8d654ce4245fb40adf1f 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -17,7 +17,6 @@ import android.content.ContentResolver; import android.content.Context; import android.media.MediaScannerConnection; import android.net.ConnectivityManager; -import android.net.Network; import android.net.NetworkInfo; import android.net.Uri; import android.util.Log; @@ -31,13 +30,20 @@ import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.resources.files.FileUtils; import java.io.File; +import java.util.concurrent.TimeUnit; import foundation.e.drive.receivers.ScreenOffReceiver; +import foundation.e.drive.work.FullScanWorker; import static foundation.e.drive.utils.AppConstants.MEDIASYNC_PROVIDER_AUTHORITY; import static foundation.e.drive.utils.AppConstants.SETTINGSYNC_PROVIDER_AUTHORITY; import androidx.annotation.NonNull; +import androidx.work.Constraints; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.NetworkType; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; /** @@ -45,7 +51,7 @@ import androidx.annotation.NonNull; */ public abstract class CommonUtils { - final private static String TAG = CommonUtils.class.getSimpleName(); + private final static String TAG = CommonUtils.class.getSimpleName(); /** * Set ServiceUncaughtExceptionHandler to be the MainThread Exception Handler @@ -163,7 +169,7 @@ public abstract class CommonUtils { oc.setCredentials(new OwnCloudBasicCredentials(account.name, AccountManager.get(context).getPassword(account))); Log.d(TAG, "user agent: "+AppConstants.USER_AGENT); - if(!AppConstants.USER_AGENT.equals(OwnCloudClientManagerFactory.getUserAgent())) { + if (!AppConstants.USER_AGENT.equals(OwnCloudClientManagerFactory.getUserAgent()) ){ OwnCloudClientManagerFactory.setUserAgent(AppConstants.USER_AGENT); } @@ -293,4 +299,25 @@ public abstract class CommonUtils { + "\n File can be read?: " + f.canRead() + "\n File can be written?: " + f.canWrite(); } + + /** + * 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){ + final Constraints constraints = new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .setRequiresBatteryNotLow(true) + .build(); + + final PeriodicWorkRequest periodicFullScanRequest = + new PeriodicWorkRequest.Builder(FullScanWorker.class, + 31, TimeUnit.MINUTES, + 5, TimeUnit.MINUTES) + .setConstraints(constraints) + .addTag(AppConstants.WORK_GENERIC_TAG) + .build(); + + workManager.enqueueUniquePeriodicWork(FullScanWorker.UNIQUE_WORK_NAME , ExistingPeriodicWorkPolicy.KEEP, periodicFullScanRequest); + } } \ 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 new file mode 100644 index 0000000000000000000000000000000000000000..08d5b8750608dd09d445006589686aee1dadde22 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/work/FullScanWorker.java @@ -0,0 +1,63 @@ +/* + * Copyright © Vincent Bourgmayer (/e/ foundation). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ + +package foundation.e.drive.work; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.util.Log; + +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; + +/** + * 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 { + private final static String TAG = FullScanWorker.class.getSimpleName(); + public final static String UNIQUE_WORK_NAME="FullScan"; + + public FullScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + Log.d(TAG, "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 { + Log.w(TAG, "Intent for ObserverService not send : account is null or \"settings sync\" & \"media sync\" settings are disabled"); + } + + return Result.success(); + } +} \ No newline at end of file