Browse Source

Merge pull request #4787 from ArisuOngaku/auto-upload-start-date-persistence

Make synced folder init/enable date persistent
Tobias Kaminsky 5 years ago
parent
commit
94502f66b5

+ 2 - 0
src/main/java/com/nextcloud/client/di/ComponentsModule.java

@@ -32,6 +32,7 @@ import com.owncloud.android.files.services.FileDownloader;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.jobs.NotificationJob;
 import com.owncloud.android.providers.DiskLruImageCacheFileProvider;
+import com.owncloud.android.providers.FileContentProvider;
 import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
 import com.owncloud.android.services.AccountManagerService;
 import com.owncloud.android.services.OperationsService;
@@ -148,6 +149,7 @@ abstract class ComponentsModule {
     @ContributesAndroidInjector abstract BootupBroadcastReceiver bootupBroadcastReceiver();
     @ContributesAndroidInjector abstract NotificationJob.NotificationReceiver notificationJobBroadcastReceiver();
 
+    @ContributesAndroidInjector abstract FileContentProvider fileContentProvider();
     @ContributesAndroidInjector abstract UsersAndGroupsSearchProvider usersAndGroupsSearchProvider();
     @ContributesAndroidInjector abstract DiskLruImageCacheFileProvider diskLruImageCacheFileProvider();
 

+ 6 - 3
src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt

@@ -26,6 +26,7 @@ import androidx.annotation.RequiresApi
 import androidx.work.ListenableWorker
 import androidx.work.WorkerFactory
 import androidx.work.WorkerParameters
+import com.nextcloud.client.core.Clock
 import com.nextcloud.client.device.DeviceInfo
 import com.nextcloud.client.device.PowerManagementService
 import com.nextcloud.client.preferences.AppPreferences
@@ -40,6 +41,7 @@ import javax.inject.Provider
 class BackgroundJobFactory @Inject constructor(
     private val preferences: AppPreferences,
     private val contentResolver: ContentResolver,
+    private val clock: Clock,
     private val powerManagerService: PowerManagementService,
     private val backgroundJobManager: Provider<BackgroundJobManager>,
     private val deviceInfo: DeviceInfo
@@ -58,13 +60,14 @@ class BackgroundJobFactory @Inject constructor(
         }
 
         return when (workerClass) {
-            ContentObserverWork::class -> createContentObserverJob(context, workerParameters)
+            ContentObserverWork::class -> createContentObserverJob(context, workerParameters, clock)
             else -> null // falls back to default factory
         }
     }
 
-    private fun createContentObserverJob(context: Context, workerParameters: WorkerParameters): ListenableWorker? {
-        val folderResolver = SyncedFolderProvider(contentResolver, preferences)
+    private fun createContentObserverJob(context: Context, workerParameters: WorkerParameters, clock: Clock):
+        ListenableWorker? {
+        val folderResolver = SyncedFolderProvider(contentResolver, preferences, clock)
         @RequiresApi(Build.VERSION_CODES.N)
         if (deviceInfo.apiLevel >= Build.VERSION_CODES.N) {
             return ContentObserverWork(

+ 22 - 15
src/main/java/com/owncloud/android/MainApp.java

@@ -45,6 +45,7 @@ import com.evernote.android.job.JobManager;
 import com.evernote.android.job.JobRequest;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.appinfo.AppInfo;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.di.ActivityInjector;
 import com.nextcloud.client.di.DaggerAppComponent;
@@ -161,6 +162,9 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
     @Inject
     BackgroundJobManager backgroundJobManager;
 
+    @Inject
+    Clock clock;
+
     private PassCodeManager passCodeManager;
 
     @SuppressWarnings("unused")
@@ -268,7 +272,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
                 preferences,
                 uploadsStorageManager,
                 connectivityService,
-                powerManagementService
+                powerManagementService,
+                clock
             )
         );
 
@@ -304,7 +309,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
                            accountManager,
                            connectivityService,
                            powerManagementService,
-                           backgroundJobManager);
+                           backgroundJobManager,
+                           clock);
         initContactsBackup(accountManager);
         notificationChannels();
 
@@ -462,23 +468,24 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
         final UserAccountManager accountManager,
         final ConnectivityService connectivityService,
         final PowerManagementService powerManagementService,
-        final BackgroundJobManager jobManager
+        final BackgroundJobManager jobManager,
+        final Clock clock
     ) {
         updateToAutoUpload();
-        cleanOldEntries();
-        updateAutoUploadEntries();
+        cleanOldEntries(clock);
+        updateAutoUploadEntries(clock);
 
         if (getAppContext() != null) {
             if (PermissionUtil.checkSelfPermission(getAppContext(),
                                                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
-                splitOutAutoUploadEntries();
+                splitOutAutoUploadEntries(clock);
             } else {
                 AppPreferences preferences = AppPreferencesImpl.fromContext(getAppContext());
                 preferences.setAutoUploadSplitEntriesEnabled(true);
             }
         }
 
-        initiateExistingAutoUploadEntries();
+        initiateExistingAutoUploadEntries(clock);
 
         FilesSyncHelper.scheduleFilesSyncIfNeeded(mContext, jobManager);
         FilesSyncHelper.restartJobsIfNeeded(
@@ -685,18 +692,18 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
         }
     }
 
-    private static void updateAutoUploadEntries() {
+    private static void updateAutoUploadEntries(Clock clock) {
         // updates entries to reflect their true paths
         Context context = getAppContext();
         AppPreferences preferences = AppPreferencesImpl.fromContext(context);
         if (!preferences.isAutoUploadPathsUpdateEnabled()) {
             SyncedFolderProvider syncedFolderProvider =
-                new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences);
+                new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences, clock);
             syncedFolderProvider.updateAutoUploadPaths(mContext);
         }
     }
 
-    private static void splitOutAutoUploadEntries() {
+    private static void splitOutAutoUploadEntries(Clock clock) {
         Context context = getAppContext();
         AppPreferences preferences = AppPreferencesImpl.fromContext(context);
         if (!preferences.isAutoUploadSplitEntriesEnabled()) {
@@ -705,7 +712,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
             Log_OC.i(TAG, "Migrate synced_folders records for image/video split");
             ContentResolver contentResolver = context.getContentResolver();
 
-            SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver, preferences);
+            SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver, preferences, clock);
 
             final List<MediaFolder> imageMediaFolders = MediaProvider.getImageFolders(contentResolver, 1, null, true);
             final List<MediaFolder> videoMediaFolders = MediaProvider.getVideoFolders(contentResolver, 1, null, true);
@@ -751,12 +758,12 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
         }
     }
 
-    private static void initiateExistingAutoUploadEntries() {
+    private static void initiateExistingAutoUploadEntries(Clock clock) {
         new Thread(() -> {
             AppPreferences preferences = AppPreferencesImpl.fromContext(getAppContext());
             if (!preferences.isAutoUploadInitialized()) {
                 SyncedFolderProvider syncedFolderProvider =
-                    new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences);
+                    new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences, clock);
 
                 for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
                     if (syncedFolder.isEnabled()) {
@@ -770,7 +777,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
         }).start();
     }
 
-    private static void cleanOldEntries() {
+    private static void cleanOldEntries(Clock clock) {
         // previous versions of application created broken entries in the SyncedFolderProvider
         // database, and this cleans all that and leaves 1 (newest) entry per synced folder
 
@@ -779,7 +786,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
 
         if (!preferences.isLegacyClean()) {
             SyncedFolderProvider syncedFolderProvider =
-                new SyncedFolderProvider(context.getContentResolver(), preferences);
+                new SyncedFolderProvider(context.getContentResolver(), preferences, clock);
 
             List<SyncedFolder> syncedFolderList = syncedFolderProvider.getSyncedFolders();
             Map<Pair<String, String>, Long> syncedFolders = new HashMap<>();

+ 36 - 14
src/main/java/com/owncloud/android/datamodel/SyncedFolder.java

@@ -30,23 +30,23 @@ import lombok.Setter;
 /**
  * Synced folder entity containing all information per synced folder.
  */
-@Getter
-@Setter
 @AllArgsConstructor
 public class SyncedFolder implements Serializable, Cloneable {
     public static final long UNPERSISTED_ID = Long.MIN_VALUE;
+    public static final long EMPTY_ENABLED_TIMESTAMP_MS = -1;
     private static final long serialVersionUID = -793476118299906429L;
 
-    private long id = UNPERSISTED_ID;
-    private String localPath;
-    private String remotePath;
-    private Boolean wifiOnly;
-    private Boolean chargingOnly;
-    private Boolean subfolderByDate;
-    private String account;
-    private Integer uploadAction;
-    private boolean enabled;
-    private MediaFolderType type;
+    @Getter @Setter private long id;
+    @Getter @Setter private String localPath;
+    @Getter @Setter private String remotePath;
+    @Getter @Setter private Boolean wifiOnly;
+    @Getter @Setter private Boolean chargingOnly;
+    @Getter @Setter private Boolean subfolderByDate;
+    @Getter @Setter private String account;
+    @Getter @Setter private Integer uploadAction;
+    @Getter private boolean enabled;
+    @Getter private long enabledTimestampMs;
+    @Getter @Setter private MediaFolderType type;
 
     /**
      * constructor for new, to be persisted entity.
@@ -59,11 +59,25 @@ public class SyncedFolder implements Serializable, Cloneable {
      * @param account         the account owning the synced folder
      * @param uploadAction    the action to be done after the upload
      * @param enabled         flag if synced folder config is active
+     * @param timestampMs     the current timestamp in milliseconds
      * @param type            the type of the folder
      */
     public SyncedFolder(String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
                         Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
-                        MediaFolderType type) {
+                        long timestampMs, MediaFolderType type) {
+        this(UNPERSISTED_ID, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction,
+             enabled, timestampMs, type);
+    }
+
+    /**
+     * constructor for wrapping existing folders.
+     *
+     * @param id id
+     */
+    protected SyncedFolder(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
+                           Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
+                           long timestampMs, MediaFolderType type) {
+        this.id = id;
         this.localPath = localPath;
         this.remotePath = remotePath;
         this.wifiOnly = wifiOnly;
@@ -71,10 +85,18 @@ public class SyncedFolder implements Serializable, Cloneable {
         this.subfolderByDate = subfolderByDate;
         this.account = account;
         this.uploadAction = uploadAction;
-        this.enabled = enabled;
+        this.setEnabled(enabled, timestampMs);
         this.type = type;
     }
 
+    /**
+     * @param timestampMs the current timestamp in milliseconds
+     */
+    public void setEnabled(boolean enabled, long timestampMs) {
+        this.enabled = enabled;
+        this.enabledTimestampMs = enabled ? timestampMs : EMPTY_ENABLED_TIMESTAMP_MS;
+    }
+
     public Object clone() {
         try {
             return super.clone();

+ 7 - 4
src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java

@@ -56,9 +56,11 @@ public class SyncedFolderDisplayItem extends SyncedFolder {
      */
     public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
                                    Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
-                                   List<String> filePaths, String folderName, long numberOfFiles, MediaFolderType type)
+                                   long timestampMs, List<String> filePaths, String folderName, long numberOfFiles,
+                                   MediaFolderType type)
     {
-        super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, type);
+        super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled,
+              timestampMs, type);
         this.filePaths = filePaths;
         this.folderName = folderName;
         this.numberOfFiles = numberOfFiles;
@@ -66,8 +68,9 @@ public class SyncedFolderDisplayItem extends SyncedFolder {
 
     public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
                                    Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
-                                   String folderName, MediaFolderType type) {
-        super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, type);
+                                   long timestampMs, String folderName, MediaFolderType type) {
+        super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled,
+              timestampMs, type);
         this.folderName = folderName;
     }
 }

+ 11 - 5
src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java

@@ -27,6 +27,7 @@ import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.preferences.AppPreferencesImpl;
 import com.owncloud.android.db.ProviderMeta;
@@ -47,20 +48,22 @@ import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR;
 public class SyncedFolderProvider extends Observable {
     static private final String TAG = SyncedFolderProvider.class.getSimpleName();
 
-    private ContentResolver mContentResolver;
-    private AppPreferences preferences;
+    private final ContentResolver mContentResolver;
+    private final AppPreferences preferences;
+    private final Clock clock;
 
     /**
      * constructor.
      *
      * @param contentResolver the ContentResolver to work with.
      */
-    public SyncedFolderProvider(ContentResolver contentResolver, AppPreferences preferences) {
+    public SyncedFolderProvider(ContentResolver contentResolver, AppPreferences preferences, Clock clock) {
         if (contentResolver == null) {
             throw new IllegalArgumentException("Cannot create an instance with a NULL contentResolver");
         }
         mContentResolver = contentResolver;
         this.preferences = preferences;
+        this.clock = clock;
     }
 
     /**
@@ -162,7 +165,7 @@ public class SyncedFolderProvider extends Observable {
                 // read sync folder object and update
                 SyncedFolder syncedFolder = createSyncedFolderFromCursor(cursor);
 
-                syncedFolder.setEnabled(enabled);
+                syncedFolder.setEnabled(enabled, clock.getCurrentTime());
 
                 // update sync folder object in db
                 result = updateSyncFolder(syncedFolder);
@@ -347,11 +350,13 @@ public class SyncedFolderProvider extends Observable {
                     ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION));
             Boolean enabled = cursor.getInt(cursor.getColumnIndex(
                     ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED)) == 1;
+            long enabledTimestampMs = cursor.getLong(cursor.getColumnIndex(
+                    ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS));
             MediaFolderType type = MediaFolderType.getById(cursor.getInt(cursor.getColumnIndex(
                     ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE)));
 
             syncedFolder = new SyncedFolder(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate,
-                    accountName, uploadAction, enabled, type);
+                    accountName, uploadAction, enabled, enabledTimestampMs, type);
         }
         return syncedFolder;
     }
@@ -370,6 +375,7 @@ public class SyncedFolderProvider extends Observable {
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY, syncedFolder.getWifiOnly());
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY, syncedFolder.getChargingOnly());
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED, syncedFolder.isEnabled());
+        cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS, syncedFolder.getEnabledTimestampMs());
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE, syncedFolder.getSubfolderByDate());
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT, syncedFolder.getAccount());
         cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION, syncedFolder.getUploadAction());

+ 2 - 1
src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -31,7 +31,7 @@ import com.owncloud.android.MainApp;
  */
 public class ProviderMeta {
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 49;
+    public static final int DB_VERSION = 50;
 
     private ProviderMeta() {
         // No instance
@@ -220,6 +220,7 @@ public class ProviderMeta {
         public static final String SYNCED_FOLDER_WIFI_ONLY = "wifi_only";
         public static final String SYNCED_FOLDER_CHARGING_ONLY = "charging_only";
         public static final String SYNCED_FOLDER_ENABLED = "enabled";
+        public static final String SYNCED_FOLDER_ENABLED_TIMESTAMP_MS = "enabled_timestamp_ms";
         public static final String SYNCED_FOLDER_TYPE = "type";
         public static final String SYNCED_FOLDER_SUBFOLDER_BY_DATE = "subfolder_by_date";
         public static final String SYNCED_FOLDER_ACCOUNT = "account";

+ 4 - 1
src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java

@@ -28,6 +28,7 @@ import android.content.Context;
 import android.content.Intent;
 
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ConnectivityService;
@@ -53,6 +54,7 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
     @Inject ConnectivityService connectivityService;
     @Inject PowerManagementService powerManagementService;
     @Inject BackgroundJobManager backgroundJobManager;
+    @Inject Clock clock;
 
     /**
      * Receives broadcast intent reporting that the system was just boot up.
@@ -69,7 +71,8 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
                                        accountManager,
                                        connectivityService,
                                        powerManagementService,
-                                       backgroundJobManager);
+                                       backgroundJobManager,
+                                       clock);
             MainApp.initContactsBackup(accountManager);
         } else {
             Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction());

+ 10 - 9
src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java

@@ -38,6 +38,7 @@ import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.google.gson.Gson;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.preferences.AppPreferencesImpl;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -57,7 +58,6 @@ import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
 import com.owncloud.android.ui.events.AccountRemovedEvent;
 import com.owncloud.android.utils.EncryptionUtils;
 import com.owncloud.android.utils.FileStorageUtils;
-import com.owncloud.android.utils.FilesSyncHelper;
 import com.owncloud.android.utils.PushUtils;
 
 import org.greenrobot.eventbus.EventBus;
@@ -81,12 +81,14 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
     public static final String ACCOUNT = "account";
     public static final String REMOTE_WIPE = "remote_wipe";
 
-    private UploadsStorageManager uploadsStorageManager;
-    private UserAccountManager userAccountManager;
+    private final UploadsStorageManager uploadsStorageManager;
+    private final UserAccountManager userAccountManager;
+    private final Clock clock;
 
-    public AccountRemovalJob(UploadsStorageManager uploadStorageManager, UserAccountManager accountManager) {
+    public AccountRemovalJob(UploadsStorageManager uploadStorageManager, UserAccountManager accountManager, Clock clock) {
         this.uploadsStorageManager = uploadStorageManager;
         this.userAccountManager = accountManager;
+        this.clock = clock;
     }
 
     @NonNull
@@ -129,7 +131,7 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
             arbitraryDataProvider.deleteKeyForAccount(account.name, PENDING_FOR_REMOVAL);
 
             // remove synced folders set for account
-            remoceSyncedFolders(context, account, arbitraryDataProvider);
+            remoceSyncedFolders(context, account, clock);
 
             // delete all uploads for account
             uploadsStorageManager.removeAccountUploads(account);
@@ -174,17 +176,16 @@ public class AccountRemovalJob extends Job implements AccountManagerCallback<Boo
         }
     }
 
-    private void remoceSyncedFolders(Context context, Account account, ArbitraryDataProvider arbitraryDataProvider) {
+    private void remoceSyncedFolders(Context context, Account account, Clock clock) {
         SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(context.getContentResolver(),
-                                                                             AppPreferencesImpl.fromContext(context));
+                                                                             AppPreferencesImpl.fromContext(context),
+                                                                             clock);
         List<SyncedFolder> syncedFolders = syncedFolderProvider.getSyncedFolders();
 
         List<Long> syncedFolderIds = new ArrayList<>();
 
         for (SyncedFolder syncedFolder : syncedFolders) {
             if (syncedFolder.getAccount().equals(account.name)) {
-                arbitraryDataProvider.deleteKeyForAccount(FilesSyncHelper.GLOBAL,
-                                                          FilesSyncHelper.SYNCEDFOLDERINITIATED + syncedFolder.getId());
                 syncedFolderIds.add(syncedFolder.getId());
             }
         }

+ 12 - 9
src/main/java/com/owncloud/android/jobs/FilesSyncJob.java

@@ -34,6 +34,7 @@ import android.text.TextUtils;
 import com.evernote.android.job.Job;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
@@ -76,22 +77,25 @@ public class FilesSyncJob extends Job {
     public static final String OVERRIDE_POWER_SAVING = "overridePowerSaving";
     private static final String WAKELOCK_TAG_SEPARATION = ":";
 
-    private UserAccountManager userAccountManager;
-    private AppPreferences preferences;
-    private UploadsStorageManager uploadsStorageManager;
-    private ConnectivityService connectivityService;
-    private PowerManagementService powerManagementService;
+    private final UserAccountManager userAccountManager;
+    private final AppPreferences preferences;
+    private final UploadsStorageManager uploadsStorageManager;
+    private final ConnectivityService connectivityService;
+    private final PowerManagementService powerManagementService;
+    private final Clock clock;
 
     FilesSyncJob(final UserAccountManager userAccountManager,
                         final AppPreferences preferences,
                         final UploadsStorageManager uploadsStorageManager,
                         final ConnectivityService connectivityService,
-                        final PowerManagementService powerManagementService) {
+                        final PowerManagementService powerManagementService,
+                        final Clock clock) {
         this.userAccountManager = userAccountManager;
         this.preferences = preferences;
         this.uploadsStorageManager = uploadsStorageManager;
         this.connectivityService = connectivityService;
         this.powerManagementService = powerManagementService;
+        this.clock = clock;
     }
 
     @NonNull
@@ -126,13 +130,12 @@ public class FilesSyncJob extends Job {
                                             userAccountManager,
                                             connectivityService,
                                             powerManagementService);
-        FilesSyncHelper.insertAllDBEntries(preferences, skipCustom);
+        FilesSyncHelper.insertAllDBEntries(preferences, clock, skipCustom);
 
         // Create all the providers we'll need
         final ContentResolver contentResolver = context.getContentResolver();
         final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
-        SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver,
-                                                                             preferences);
+        SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver, preferences, clock);
 
         Locale currentLocale = context.getResources().getConfiguration().locale;
         SimpleDateFormat sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale);

+ 8 - 4
src/main/java/com/owncloud/android/jobs/MediaFoldersDetectionJob.java

@@ -39,6 +39,7 @@ import android.text.TextUtils;
 import com.evernote.android.job.Job;
 import com.google.gson.Gson;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.preferences.AppPreferencesImpl;
 import com.owncloud.android.R;
@@ -74,11 +75,13 @@ public class MediaFoldersDetectionJob extends Job {
 
     private static final String DISABLE_DETECTION_CLICK = "DISABLE_DETECTION_CLICK";
 
-    private UserAccountManager userAccountManager;
-    private Random randomId = new Random();
+    private final UserAccountManager userAccountManager;
+    private final Clock clock;
+    private final Random randomId = new Random();
 
-    MediaFoldersDetectionJob(UserAccountManager accountManager) {
+    MediaFoldersDetectionJob(UserAccountManager accountManager, Clock clock) {
         this.userAccountManager = accountManager;
+        this.clock = clock;
     }
 
     @NonNull
@@ -88,7 +91,8 @@ public class MediaFoldersDetectionJob extends Job {
         ContentResolver contentResolver = context.getContentResolver();
         ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
         SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver,
-                                                                             AppPreferencesImpl.fromContext(context));
+                                                                             AppPreferencesImpl.fromContext(context),
+                                                                             clock);
         Gson gson = new Gson();
         String arbitraryDataString;
         MediaFoldersModel mediaFoldersModel;

+ 9 - 4
src/main/java/com/owncloud/android/jobs/NCJobCreator.java

@@ -29,6 +29,7 @@ import android.content.Context;
 import com.evernote.android.job.Job;
 import com.evernote.android.job.JobCreator;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
@@ -48,6 +49,7 @@ public class NCJobCreator implements JobCreator {
     private final UploadsStorageManager uploadsStorageManager;
     private final ConnectivityService connectivityService;
     private final PowerManagementService powerManagementService;
+    private final Clock clock;
 
     public NCJobCreator(
         Context context,
@@ -55,7 +57,8 @@ public class NCJobCreator implements JobCreator {
         AppPreferences preferences,
         UploadsStorageManager uploadsStorageManager,
         ConnectivityService connectivityServices,
-        PowerManagementService powerManagementService
+        PowerManagementService powerManagementService,
+        Clock clock
     ) {
         this.context = context;
         this.accountManager = accountManager;
@@ -63,6 +66,7 @@ public class NCJobCreator implements JobCreator {
         this.uploadsStorageManager = uploadsStorageManager;
         this.connectivityService = connectivityServices;
         this.powerManagementService = powerManagementService;
+        this.clock = clock;
     }
 
     @Override
@@ -73,19 +77,20 @@ public class NCJobCreator implements JobCreator {
             case ContactsImportJob.TAG:
                 return new ContactsImportJob();
             case AccountRemovalJob.TAG:
-                return new AccountRemovalJob(uploadsStorageManager, accountManager);
+                return new AccountRemovalJob(uploadsStorageManager, accountManager, clock);
             case FilesSyncJob.TAG:
                 return new FilesSyncJob(accountManager,
                                         preferences,
                                         uploadsStorageManager,
                                         connectivityService,
-                                        powerManagementService);
+                                        powerManagementService,
+                                        clock);
             case OfflineSyncJob.TAG:
                 return new OfflineSyncJob(accountManager, connectivityService, powerManagementService);
             case NotificationJob.TAG:
                 return new NotificationJob(context, accountManager);
             case MediaFoldersDetectionJob.TAG:
-                return new MediaFoldersDetectionJob(accountManager);
+                return new MediaFoldersDetectionJob(accountManager, clock);
             default:
                 return null;
         }

+ 32 - 0
src/main/java/com/owncloud/android/providers/FileContentProvider.java

@@ -42,9 +42,11 @@ import android.net.Uri;
 import android.os.Binder;
 import android.text.TextUtils;
 
+import com.nextcloud.client.core.Clock;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.datamodel.SyncedFolder;
 import com.owncloud.android.db.ProviderMeta;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
 import com.owncloud.android.lib.common.accounts.AccountUtils;
@@ -58,7 +60,10 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Locale;
 
+import javax.inject.Inject;
+
 import androidx.annotation.NonNull;
+import dagger.android.AndroidInjection;
 
 /**
  * The ContentProvider for the ownCloud App.
@@ -91,6 +96,7 @@ public class FileContentProvider extends ContentProvider {
     public static final int ARBITRARY_DATA_TABLE_INTRODUCTION_VERSION = 20;
     public static final int MINIMUM_PATH_SEGMENTS_SIZE = 1;
 
+    @Inject protected Clock clock;
     private DataBaseHelper mDbHelper;
     private Context mContext;
     private UriMatcher mUriMatcher;
@@ -414,6 +420,7 @@ public class FileContentProvider extends ContentProvider {
 
     @Override
     public boolean onCreate() {
+        AndroidInjection.inject(this);
         mDbHelper = new DataBaseHelper(getContext());
         mContext = getContext();
 
@@ -822,6 +829,7 @@ public class FileContentProvider extends ContentProvider {
                        + ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY + " INTEGER, "         // wifi_only
                        + ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY + " INTEGER, "     // charging only
                        + ProviderTableMeta.SYNCED_FOLDER_ENABLED + " INTEGER, "           // enabled
+                       + ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS + " INTEGER, "           // enable date
                        + ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE + " INTEGER, " // subfolder by date
                        + ProviderTableMeta.SYNCED_FOLDER_ACCOUNT + "  TEXT, "             // account
                        + ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION + " INTEGER, "     // upload action
@@ -2013,6 +2021,30 @@ public class FileContentProvider extends ContentProvider {
             if (!upgraded) {
                 Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
             }
+
+            if (oldVersion < 50 && newVersion >= 50) {
+                Log_OC.i(SQL, "Entering in the #50 add persistent enable date to synced_folders table");
+                db.beginTransaction();
+                try {
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS + " INTEGER ");
+
+                    db.execSQL("UPDATE " + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME + " SET " +
+                                   ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS + " = CASE " +
+                                   " WHEN enabled = 0 THEN " + SyncedFolder.EMPTY_ENABLED_TIMESTAMP_MS + " " +
+                                   " ELSE " + clock.getCurrentTime() +
+                                   " END ");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+
+            if (!upgraded) {
+                Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
+            }
         }
 
         @Override

+ 11 - 25
src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java

@@ -41,13 +41,13 @@ import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.BuildConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
-import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.MediaFolder;
 import com.owncloud.android.datamodel.MediaFolderType;
 import com.owncloud.android.datamodel.MediaProvider;
@@ -113,6 +113,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
     private int type;
     @Inject AppPreferences preferences;
     @Inject PowerManagementService powerManagementService;
+    @Inject Clock clock;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -223,8 +224,8 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
 
         final int gridWidth = getResources().getInteger(R.integer.media_grid_width);
         boolean lightVersion = getResources().getBoolean(R.bool.syncedFolder_light);
-        mAdapter = new SyncedFolderAdapter(this, gridWidth, this, lightVersion);
-        mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences);
+        mAdapter = new SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion);
+        mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver(), preferences, clock);
 
         final GridLayoutManager lm = new GridLayoutManager(this, gridWidth);
         mAdapter.setLayoutManager(lm);
@@ -386,6 +387,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                 syncedFolder.getAccount(),
                 syncedFolder.getUploadAction(),
                 syncedFolder.isEnabled(),
+                clock.getCurrentTime(),
                 filePaths,
                 localFolder.getName(),
                 files.length,
@@ -411,6 +413,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                 syncedFolder.getAccount(),
                 syncedFolder.getUploadAction(),
                 syncedFolder.isEnabled(),
+                clock.getCurrentTime(),
                 mediaFolder.filePaths,
                 mediaFolder.folderName,
                 mediaFolder.numberOfFiles,
@@ -432,9 +435,10 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                 true,
                 false,
                 false,
-            getAccount().name,
+                getAccount().name,
                 FileUploader.LOCAL_BEHAVIOUR_FORGET,
                 false,
+                clock.getCurrentTime(),
                 mediaFolder.filePaths,
                 mediaFolder.folderName,
                 mediaFolder.numberOfFiles,
@@ -519,7 +523,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                 SyncedFolderDisplayItem emptyCustomFolder = new SyncedFolderDisplayItem(
                     SyncedFolder.UNPERSISTED_ID, null, null, true, false,
                     false, getAccount().name,
-                    FileUploader.LOCAL_BEHAVIOUR_FORGET, false, null, MediaFolderType.CUSTOM);
+                    FileUploader.LOCAL_BEHAVIOUR_FORGET, false, clock.getCurrentTime(), null, MediaFolderType.CUSTOM);
                 onSyncFolderSettingsClick(0, emptyCustomFolder);
             }
 
@@ -548,9 +552,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
 
     @Override
     public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) {
-        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext().
-                getContentResolver());
-
         if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) {
             mSyncedFolderProvider.updateSyncedFolderEnabled(syncedFolderDisplayItem.getId(),
                     syncedFolderDisplayItem.isEnabled());
@@ -565,9 +566,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
             FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolderDisplayItem);
 
             showBatteryOptimizationInfo();
-        } else {
-            String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + syncedFolderDisplayItem.getId();
-            arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
         }
     }
 
@@ -600,9 +598,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
 
     @Override
     public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) {
-        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext().
-                getContentResolver());
-
         // custom folders newly created aren't in the list already,
         // so triggering a refresh
         if (MediaFolderType.CUSTOM == syncedFolder.getType() && syncedFolder.getId() == UNPERSISTED_ID) {
@@ -610,15 +605,12 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                     SyncedFolder.UNPERSISTED_ID, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(),
                     syncedFolder.getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(),
                     syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.getEnabled(),
-                    new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType());
+                    clock.getCurrentTime(), new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType());
             long storedId = mSyncedFolderProvider.storeSyncedFolder(newCustomFolder);
             if (storedId != -1) {
                 newCustomFolder.setId(storedId);
                 if (newCustomFolder.isEnabled()) {
                     FilesSyncHelper.insertAllDBEntriesForSyncedFolder(newCustomFolder);
-                } else {
-                    String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + newCustomFolder.getId();
-                    arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
                 }
             }
             mAdapter.addSyncFolderItem(newCustomFolder);
@@ -635,9 +627,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                     item.setId(storedId);
                     if (item.isEnabled()) {
                         FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item);
-                    } else {
-                        String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId();
-                        arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
                     }
                 }
             } else {
@@ -645,9 +634,6 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
                 mSyncedFolderProvider.updateSyncFolder(item);
                 if (item.isEnabled()) {
                     FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item);
-                } else {
-                    String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId();
-                    arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
                 }
             }
 
@@ -699,7 +685,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
         item.setChargingOnly(chargingOnly);
         item.setSubfolderByDate(subfolderByDate);
         item.setUploadAction(uploadAction);
-        item.setEnabled(enabled);
+        item.setEnabled(enabled, clock.getCurrentTime());
         return item;
     }
 

+ 6 - 3
src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java

@@ -33,6 +33,7 @@ import android.widget.TextView;
 
 import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter;
 import com.afollestad.sectionedrecyclerview.SectionedViewHolder;
+import com.nextcloud.client.core.Clock;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.MediaFolderType;
 import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
@@ -54,14 +55,16 @@ import butterknife.ButterKnife;
 public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedViewHolder> {
 
     private final Context mContext;
+    private final Clock clock;
     private final int mGridWidth;
     private final int mGridTotal;
     private final ClickListener mListener;
     private final List<SyncedFolderDisplayItem> mSyncFolderItems;
     private final boolean mLight;
 
-    public SyncedFolderAdapter(Context context, int gridWidth, ClickListener listener, boolean light) {
+    public SyncedFolderAdapter(Context context, Clock clock, int gridWidth, ClickListener listener, boolean light) {
         mContext = context;
+        this.clock = clock;
         mGridWidth = gridWidth;
         mGridTotal = gridWidth * 2;
         mListener = listener;
@@ -148,7 +151,7 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
         holder.syncStatusButton.setVisibility(View.VISIBLE);
         holder.syncStatusButton.setTag(section);
         holder.syncStatusButton.setOnClickListener(v -> {
-            mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled());
+            mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled(), clock.getCurrentTime());
             setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
             mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section));
         });
@@ -157,7 +160,7 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter<SectionedV
         holder.syncStatusButton.setVisibility(View.VISIBLE);
         holder.syncStatusButton.setTag(section);
         holder.syncStatusButton.setOnClickListener(v -> {
-            mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled());
+            mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled(), clock.getCurrentTime());
             setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
             mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section));
         });

+ 27 - 58
src/main/java/com/owncloud/android/utils/FilesSyncHelper.java

@@ -30,18 +30,16 @@ import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
 import android.provider.MediaStore;
-import android.text.TextUtils;
-import android.util.Log;
 
 import com.evernote.android.job.JobManager;
 import com.evernote.android.job.JobRequest;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.client.core.Clock;
 import com.nextcloud.client.device.PowerManagementService;
 import com.nextcloud.client.jobs.BackgroundJobManager;
 import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.MainApp;
-import com.owncloud.android.datamodel.ArbitraryDataProvider;
 import com.owncloud.android.datamodel.FilesystemDataProvider;
 import com.owncloud.android.datamodel.MediaFolderType;
 import com.owncloud.android.datamodel.SyncedFolder;
@@ -51,6 +49,7 @@ import com.owncloud.android.db.OCUpload;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.jobs.FilesSyncJob;
 import com.owncloud.android.jobs.OfflineSyncJob;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 import org.lukhnos.nnio.file.FileVisitResult;
 import org.lukhnos.nnio.file.Files;
@@ -73,7 +72,6 @@ public final class FilesSyncHelper {
     public static final String TAG = "FileSyncHelper";
 
     public static final String GLOBAL = "global";
-    public static final String SYNCEDFOLDERINITIATED = "syncedFolderIntitiated_";
 
     public static final int ContentSyncJobId = 315;
 
@@ -84,59 +82,34 @@ public final class FilesSyncHelper {
     public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder) {
         final Context context = MainApp.getAppContext();
         final ContentResolver contentResolver = context.getContentResolver();
-        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
 
-        Long currentTime = System.currentTimeMillis();
-        double currentTimeInSeconds = currentTime / 1000.0;
-        String currentTimeString = Long.toString((long) currentTimeInSeconds);
+        final long enabledTimestampMs = syncedFolder.getEnabledTimestampMs();
 
-        String syncedFolderInitiatedKey = SYNCEDFOLDERINITIATED + syncedFolder.getId();
-        boolean dryRun = TextUtils.isEmpty(arbitraryDataProvider.getValue
-                (GLOBAL, syncedFolderInitiatedKey));
-
-        if (MediaFolderType.IMAGE == syncedFolder.getType()) {
-            if (dryRun) {
-                arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
-                        currentTimeString);
-            } else {
-                FilesSyncHelper.insertContentIntoDB(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI
-                        , syncedFolder);
+        if (syncedFolder.isEnabled() && enabledTimestampMs >= 0) {
+            MediaFolderType mediaType = syncedFolder.getType();
+            if (mediaType == MediaFolderType.IMAGE) {
+                FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.INTERNAL_CONTENT_URI
+                    , syncedFolder);
                 FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                        syncedFolder);
-            }
-
-        } else if (MediaFolderType.VIDEO == syncedFolder.getType()) {
-
-            if (dryRun) {
-                arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
-                        currentTimeString);
-            } else {
-                FilesSyncHelper.insertContentIntoDB(android.provider.MediaStore.Video.Media.INTERNAL_CONTENT_URI,
-                        syncedFolder);
+                                                    syncedFolder);
+            } else if (mediaType == MediaFolderType.VIDEO) {
+                FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.INTERNAL_CONTENT_URI,
+                                                    syncedFolder);
                 FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
-                        syncedFolder);
-            }
-
-        } else {
-            try {
-                if (dryRun) {
-                    arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
-                            currentTimeString);
-                } else {
+                                                    syncedFolder);
+            } else {
+                try {
                     FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
                     Path path = Paths.get(syncedFolder.getLocalPath());
 
-                    String dateInitiated = arbitraryDataProvider.getValue(GLOBAL,
-                            syncedFolderInitiatedKey);
-
                     Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                         @Override
                         public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
-
                             File file = path.toFile();
-                            if (attrs.lastModifiedTime().toMillis() >= Long.parseLong(dateInitiated) * 1000) {
+                            if (attrs.lastModifiedTime().toMillis() >= enabledTimestampMs) {
                                 filesystemDataProvider.storeOrUpdateFileValue(path.toAbsolutePath().toString(),
-                                        attrs.lastModifiedTime().toMillis(), file.isDirectory(), syncedFolder);
+                                                                              attrs.lastModifiedTime().toMillis(),
+                                                                              file.isDirectory(), syncedFolder);
                             }
 
                             return FileVisitResult.CONTINUE;
@@ -147,20 +120,17 @@ public final class FilesSyncHelper {
                             return FileVisitResult.CONTINUE;
                         }
                     });
-
+                } catch (IOException e) {
+                    Log_OC.e(TAG, "Something went wrong while indexing files for auto upload", e);
                 }
-
-            } catch (IOException e) {
-                Log.e(TAG, "Something went wrong while indexing files for auto upload " + e.getLocalizedMessage());
             }
         }
     }
 
-    public static void insertAllDBEntries(AppPreferences preferences, boolean skipCustom) {
+    public static void insertAllDBEntries(AppPreferences preferences, Clock clock, boolean skipCustom) {
         final Context context = MainApp.getAppContext();
         final ContentResolver contentResolver = context.getContentResolver();
-        SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver,
-                                                                             preferences);
+        SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver, preferences, clock);
 
         for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
             if (syncedFolder.isEnabled() && (MediaFolderType.CUSTOM != syncedFolder.getType() || !skipCustom)) {
@@ -172,7 +142,6 @@ public final class FilesSyncHelper {
     private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder) {
         final Context context = MainApp.getAppContext();
         final ContentResolver contentResolver = context.getContentResolver();
-        ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
 
         Cursor cursor;
         int column_index_data;
@@ -191,11 +160,10 @@ public final class FilesSyncHelper {
         }
         path = path + "%";
 
-        String syncedFolderInitiatedKey = SYNCEDFOLDERINITIATED + syncedFolder.getId();
-        String dateInitiated = arbitraryDataProvider.getValue(GLOBAL, syncedFolderInitiatedKey);
+        long enabledTimestampMs = syncedFolder.getEnabledTimestampMs();
 
         cursor = context.getContentResolver().query(uri, projection, MediaStore.MediaColumns.DATA + " LIKE ?",
-                new String[]{path}, null);
+                                                    new String[]{path}, null);
 
         if (cursor != null) {
             column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
@@ -203,9 +171,10 @@ public final class FilesSyncHelper {
             while (cursor.moveToNext()) {
                 contentPath = cursor.getString(column_index_data);
                 isFolder = new File(contentPath).isDirectory();
-                if (cursor.getLong(column_index_date_modified) >= Long.parseLong(dateInitiated)) {
+                if (cursor.getLong(column_index_date_modified) >= enabledTimestampMs / 1000.0) {
                     filesystemDataProvider.storeOrUpdateFileValue(contentPath,
-                            cursor.getLong(column_index_date_modified), isFolder, syncedFolder);
+                                                                  cursor.getLong(column_index_date_modified), isFolder,
+                                                                  syncedFolder);
                 }
             }
             cursor.close();

+ 5 - 0
src/test/java/com/nextcloud/client/jobs/BackgroundJobFactoryTest.kt

@@ -24,6 +24,7 @@ import android.content.ContentResolver
 import android.content.Context
 import android.os.Build
 import androidx.work.WorkerParameters
+import com.nextcloud.client.core.Clock
 import com.nextcloud.client.device.DeviceInfo
 import com.nextcloud.client.device.PowerManagementService
 import com.nextcloud.client.preferences.AppPreferences
@@ -59,6 +60,9 @@ class BackgroundJobFactoryTest {
     @Mock
     private lateinit var deviceInfo: DeviceInfo
 
+    @Mock
+    private lateinit var clock: Clock
+
     private lateinit var factory: BackgroundJobFactory
 
     @Before
@@ -67,6 +71,7 @@ class BackgroundJobFactoryTest {
         factory = BackgroundJobFactory(
             preferences,
             contentResolver,
+            clock,
             powerManagementService,
             Provider { backgroundJobManager },
             deviceInfo

+ 1 - 0
src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java

@@ -177,6 +177,7 @@ public class SyncedFoldersActivityTest {
                                            "test@nextcloud.com",
                                            1,
                                            enabled,
+                                           System.currentTimeMillis(),
                                            new ArrayList<String>(),
                                            folderName,
                                            2,