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

Make synced folder init/enable date persistent
This commit is contained in:
Tobias Kaminsky 2019-11-19 13:21:43 +01:00 committed by GitHub
commit 94502f66b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 211 additions and 155 deletions

View File

@ -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();

View File

@ -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(

View File

@ -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<>();

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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";

View File

@ -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());

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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,
@ -435,6 +438,7 @@ public class SyncedFoldersActivity extends FileActivity implements SyncedFolderA
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;
}

View File

@ -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));
});

View File

@ -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
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,
} 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 {
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.e(TAG, "Something went wrong while indexing files for auto upload " + e.getLocalizedMessage());
Log_OC.e(TAG, "Something went wrong while indexing files for auto upload", e);
}
}
}
}
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,8 +160,7 @@ 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);
@ -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();

View File

@ -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

View File

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