mirror of
https://github.com/nextcloud/android.git
synced 2024-11-26 15:15:51 +03:00
Merge pull request #4787 from ArisuOngaku/auto-upload-start-date-persistence
Make synced folder init/enable date persistent
This commit is contained in:
commit
94502f66b5
18 changed files with 211 additions and 155 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -177,6 +177,7 @@ public class SyncedFoldersActivityTest {
|
|||
"test@nextcloud.com",
|
||||
1,
|
||||
enabled,
|
||||
System.currentTimeMillis(),
|
||||
new ArrayList<String>(),
|
||||
folderName,
|
||||
2,
|
||||
|
|
Loading…
Reference in a new issue