mirror of https://github.com/tasks/tasks
Convert workers to Kotlin
parent
cde5bcfb87
commit
641b60be9b
@ -1,152 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import static com.todoroo.astrid.dao.TaskDao.TRANS_SUPPRESS_REFRESH;
|
|
||||||
import static org.tasks.Strings.isNullOrEmpty;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.CalendarContract;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.Data;
|
|
||||||
import androidx.work.Data.Builder;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import com.todoroo.astrid.dao.TaskDao;
|
|
||||||
import com.todoroo.astrid.data.SyncFlags;
|
|
||||||
import com.todoroo.astrid.data.Task;
|
|
||||||
import com.todoroo.astrid.reminders.ReminderService;
|
|
||||||
import com.todoroo.astrid.repeats.RepeatTaskHelper;
|
|
||||||
import com.todoroo.astrid.timers.TimerPlugin;
|
|
||||||
import java.util.Objects;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.data.CaldavAccount;
|
|
||||||
import org.tasks.data.CaldavDao;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.injection.ApplicationContext;
|
|
||||||
import org.tasks.injection.InjectingWorker;
|
|
||||||
import org.tasks.location.GeofenceApi;
|
|
||||||
import org.tasks.notifications.NotificationManager;
|
|
||||||
import org.tasks.scheduling.RefreshScheduler;
|
|
||||||
import org.tasks.sync.SyncAdapters;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class AfterSaveWork extends InjectingWorker {
|
|
||||||
|
|
||||||
private static final String EXTRA_ID = "extra_id";
|
|
||||||
private static final String EXTRA_ORIG_COMPLETED = "extra_was_completed";
|
|
||||||
private static final String EXTRA_ORIG_DELETED = "extra_was_deleted";
|
|
||||||
private static final String EXTRA_PUSH_GTASKS = "extra_push_gtasks";
|
|
||||||
private static final String EXTRA_PUSH_CALDAV = "extra_push_caldav";
|
|
||||||
private static final String EXTRA_SUPPRESS_REFRESH = "extra_suppress_refresh";
|
|
||||||
|
|
||||||
@Inject RepeatTaskHelper repeatTaskHelper;
|
|
||||||
@Inject @ApplicationContext Context context;
|
|
||||||
@Inject NotificationManager notificationManager;
|
|
||||||
@Inject GeofenceApi geofenceApi;
|
|
||||||
@Inject TimerPlugin timerPlugin;
|
|
||||||
@Inject ReminderService reminderService;
|
|
||||||
@Inject RefreshScheduler refreshScheduler;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
@Inject TaskDao taskDao;
|
|
||||||
@Inject SyncAdapters syncAdapters;
|
|
||||||
@Inject WorkManager workManager;
|
|
||||||
@Inject CaldavDao caldavDao;
|
|
||||||
|
|
||||||
public AfterSaveWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Data getInputData(Task current, Task original) {
|
|
||||||
boolean suppress = current.checkTransitory(SyncFlags.SUPPRESS_SYNC);
|
|
||||||
boolean forceCaldav = current.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC);
|
|
||||||
Builder builder =
|
|
||||||
new Builder()
|
|
||||||
.putLong(EXTRA_ID, current.getId())
|
|
||||||
.putBoolean(EXTRA_PUSH_GTASKS, !suppress && !current.googleTaskUpToDate(original))
|
|
||||||
.putBoolean(
|
|
||||||
EXTRA_PUSH_CALDAV, !suppress && (!current.caldavUpToDate(original) || forceCaldav))
|
|
||||||
.putBoolean(EXTRA_SUPPRESS_REFRESH, current.checkTransitory(TRANS_SUPPRESS_REFRESH));
|
|
||||||
if (original != null) {
|
|
||||||
builder
|
|
||||||
.putLong(EXTRA_ORIG_COMPLETED, original.getCompletionDate())
|
|
||||||
.putLong(EXTRA_ORIG_DELETED, original.getDeletionDate());
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Result run() {
|
|
||||||
Data data = getInputData();
|
|
||||||
long taskId = data.getLong(EXTRA_ID, -1);
|
|
||||||
Task task = taskDao.fetch(taskId);
|
|
||||||
if (task == null) {
|
|
||||||
Timber.e("Missing saved task");
|
|
||||||
return Result.failure();
|
|
||||||
}
|
|
||||||
|
|
||||||
reminderService.scheduleAlarm(task);
|
|
||||||
|
|
||||||
boolean completionDateModified =
|
|
||||||
!Objects.equals(task.getCompletionDate(), data.getLong(EXTRA_ORIG_COMPLETED, 0));
|
|
||||||
boolean deletionDateModified =
|
|
||||||
!Objects.equals(task.getDeletionDate(), data.getLong(EXTRA_ORIG_DELETED, 0));
|
|
||||||
|
|
||||||
boolean justCompleted = completionDateModified && task.isCompleted();
|
|
||||||
boolean justDeleted = deletionDateModified && task.isDeleted();
|
|
||||||
|
|
||||||
if (justCompleted || justDeleted) {
|
|
||||||
notificationManager.cancel(taskId);
|
|
||||||
}
|
|
||||||
if (completionDateModified || deletionDateModified) {
|
|
||||||
geofenceApi.update(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (justCompleted) {
|
|
||||||
updateCalendarTitle(task);
|
|
||||||
CaldavAccount account = caldavDao.getAccountForTask(taskId);
|
|
||||||
if (account == null || !account.isSuppressRepeatingTasks()) {
|
|
||||||
repeatTaskHelper.handleRepeat(task);
|
|
||||||
}
|
|
||||||
if (task.getTimerStart() > 0) {
|
|
||||||
timerPlugin.stopTimer(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((data.getBoolean(EXTRA_PUSH_GTASKS, false) && syncAdapters.isGoogleTaskSyncEnabled())
|
|
||||||
|| (data.getBoolean(EXTRA_PUSH_CALDAV, false) && syncAdapters.isCaldavSyncEnabled())) {
|
|
||||||
workManager.sync(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshScheduler.scheduleRefresh(task);
|
|
||||||
if (!data.getBoolean(EXTRA_SUPPRESS_REFRESH, false)) {
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCalendarTitle(Task task) {
|
|
||||||
String calendarUri = task.getCalendarURI();
|
|
||||||
if (!isNullOrEmpty(calendarUri)) {
|
|
||||||
try {
|
|
||||||
// change title of calendar event
|
|
||||||
ContentResolver cr = context.getContentResolver();
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(
|
|
||||||
CalendarContract.Events.TITLE,
|
|
||||||
context.getString(R.string.gcal_completed_title, task.getTitle()));
|
|
||||||
cr.update(Uri.parse(calendarUri), values, null, null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,128 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.CalendarContract
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.todoroo.astrid.dao.TaskDao
|
||||||
|
import com.todoroo.astrid.data.SyncFlags
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import com.todoroo.astrid.reminders.ReminderService
|
||||||
|
import com.todoroo.astrid.repeats.RepeatTaskHelper
|
||||||
|
import com.todoroo.astrid.timers.TimerPlugin
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.Strings.isNullOrEmpty
|
||||||
|
import org.tasks.data.CaldavDao
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.injection.ApplicationContext
|
||||||
|
import org.tasks.injection.InjectingWorker
|
||||||
|
import org.tasks.location.GeofenceApi
|
||||||
|
import org.tasks.notifications.NotificationManager
|
||||||
|
import org.tasks.scheduling.RefreshScheduler
|
||||||
|
import org.tasks.sync.SyncAdapters
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AfterSaveWork(context: Context, workerParams: WorkerParameters) : InjectingWorker(context, workerParams) {
|
||||||
|
@Inject lateinit var repeatTaskHelper: RepeatTaskHelper
|
||||||
|
@Inject @ApplicationContext lateinit var context: Context
|
||||||
|
@Inject lateinit var notificationManager: NotificationManager
|
||||||
|
@Inject lateinit var geofenceApi: GeofenceApi
|
||||||
|
@Inject lateinit var timerPlugin: TimerPlugin
|
||||||
|
@Inject lateinit var reminderService: ReminderService
|
||||||
|
@Inject lateinit var refreshScheduler: RefreshScheduler
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
@Inject lateinit var taskDao: TaskDao
|
||||||
|
@Inject lateinit var syncAdapters: SyncAdapters
|
||||||
|
@Inject lateinit var workManager: WorkManager
|
||||||
|
@Inject lateinit var caldavDao: CaldavDao
|
||||||
|
|
||||||
|
override fun run(): Result {
|
||||||
|
val data = inputData
|
||||||
|
val taskId = data.getLong(EXTRA_ID, -1)
|
||||||
|
val task = taskDao.fetch(taskId)
|
||||||
|
if (task == null) {
|
||||||
|
Timber.e("Missing saved task")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
reminderService.scheduleAlarm(task)
|
||||||
|
val completionDateModified = task.completionDate != data.getLong(EXTRA_ORIG_COMPLETED, 0)
|
||||||
|
val deletionDateModified = task.deletionDate != data.getLong(EXTRA_ORIG_DELETED, 0)
|
||||||
|
val justCompleted = completionDateModified && task.isCompleted
|
||||||
|
val justDeleted = deletionDateModified && task.isDeleted
|
||||||
|
if (justCompleted || justDeleted) {
|
||||||
|
notificationManager.cancel(taskId)
|
||||||
|
}
|
||||||
|
if (completionDateModified || deletionDateModified) {
|
||||||
|
geofenceApi.update(taskId)
|
||||||
|
}
|
||||||
|
if (justCompleted) {
|
||||||
|
updateCalendarTitle(task)
|
||||||
|
val account = caldavDao.getAccountForTask(taskId)
|
||||||
|
if (account == null || !account.isSuppressRepeatingTasks) {
|
||||||
|
repeatTaskHelper.handleRepeat(task)
|
||||||
|
}
|
||||||
|
if (task.timerStart > 0) {
|
||||||
|
timerPlugin.stopTimer(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.getBoolean(EXTRA_PUSH_GTASKS, false) && syncAdapters.isGoogleTaskSyncEnabled
|
||||||
|
|| data.getBoolean(EXTRA_PUSH_CALDAV, false) && syncAdapters.isCaldavSyncEnabled) {
|
||||||
|
workManager.sync(false)
|
||||||
|
}
|
||||||
|
refreshScheduler.scheduleRefresh(task)
|
||||||
|
if (!data.getBoolean(EXTRA_SUPPRESS_REFRESH, false)) {
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCalendarTitle(task: Task) {
|
||||||
|
val calendarUri = task.calendarURI
|
||||||
|
if (!isNullOrEmpty(calendarUri)) {
|
||||||
|
try {
|
||||||
|
// change title of calendar event
|
||||||
|
val cr = context.contentResolver
|
||||||
|
val values = ContentValues()
|
||||||
|
values.put(
|
||||||
|
CalendarContract.Events.TITLE,
|
||||||
|
context.getString(R.string.gcal_completed_title, task.title))
|
||||||
|
cr.update(Uri.parse(calendarUri), values, null, null)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) {
|
||||||
|
component.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val EXTRA_ID = "extra_id"
|
||||||
|
private const val EXTRA_ORIG_COMPLETED = "extra_was_completed"
|
||||||
|
private const val EXTRA_ORIG_DELETED = "extra_was_deleted"
|
||||||
|
private const val EXTRA_PUSH_GTASKS = "extra_push_gtasks"
|
||||||
|
private const val EXTRA_PUSH_CALDAV = "extra_push_caldav"
|
||||||
|
private const val EXTRA_SUPPRESS_REFRESH = "extra_suppress_refresh"
|
||||||
|
fun getInputData(current: Task, original: Task?): Data {
|
||||||
|
val suppress = current.checkTransitory(SyncFlags.SUPPRESS_SYNC)
|
||||||
|
val forceCaldav = current.checkTransitory(SyncFlags.FORCE_CALDAV_SYNC)
|
||||||
|
val builder = Data.Builder()
|
||||||
|
.putLong(EXTRA_ID, current.id)
|
||||||
|
.putBoolean(EXTRA_PUSH_GTASKS, !suppress && !current.googleTaskUpToDate(original))
|
||||||
|
.putBoolean(
|
||||||
|
EXTRA_PUSH_CALDAV, !suppress && (!current.caldavUpToDate(original) || forceCaldav))
|
||||||
|
.putBoolean(EXTRA_SUPPRESS_REFRESH, current.checkTransitory(TaskDao.TRANS_SUPPRESS_REFRESH))
|
||||||
|
if (original != null) {
|
||||||
|
builder
|
||||||
|
.putLong(EXTRA_ORIG_COMPLETED, original.completionDate)
|
||||||
|
.putLong(EXTRA_ORIG_DELETED, original.deletionDate)
|
||||||
|
}
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,127 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.filter;
|
|
||||||
import static com.google.common.collect.Iterables.skip;
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
|
||||||
import static com.todoroo.andlib.utility.DateUtilities.now;
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.backup.TasksJsonExporter;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.injection.ApplicationContext;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class BackupWork extends RepeatingWorker {
|
|
||||||
|
|
||||||
static final int DAYS_TO_KEEP_BACKUP = 7;
|
|
||||||
static final String BACKUP_FILE_NAME_REGEX = "auto\\.[-\\d]+\\.json";
|
|
||||||
private static final Predicate<String> FILENAME_FILTER = f -> f.matches(BACKUP_FILE_NAME_REGEX);
|
|
||||||
static final FileFilter FILE_FILTER = f -> FILENAME_FILTER.apply(f.getName());
|
|
||||||
private static final Comparator<File> BY_LAST_MODIFIED =
|
|
||||||
(f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified());
|
|
||||||
private static final Comparator<DocumentFile> DOCUMENT_FILE_COMPARATOR =
|
|
||||||
(d1, d2) -> Long.compare(d2.lastModified(), d1.lastModified());
|
|
||||||
@Inject @ApplicationContext Context context;
|
|
||||||
@Inject TasksJsonExporter tasksJsonExporter;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject WorkManager workManager;
|
|
||||||
|
|
||||||
public BackupWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<File> getDeleteList(File[] fileArray, int keepNewest) {
|
|
||||||
if (fileArray == null) {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<File> files = Arrays.asList(fileArray);
|
|
||||||
Collections.sort(files, BY_LAST_MODIFIED);
|
|
||||||
return newArrayList(skip(files, keepNewest));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<DocumentFile> getDeleteList(DocumentFile[] fileArray) {
|
|
||||||
if (fileArray == null) {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DocumentFile> files = Arrays.asList(fileArray);
|
|
||||||
files = newArrayList(filter(files, file -> FILENAME_FILTER.apply(file.getName())));
|
|
||||||
Collections.sort(files, DOCUMENT_FILE_COMPARATOR);
|
|
||||||
return newArrayList(skip(files, DAYS_TO_KEEP_BACKUP));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Result run() {
|
|
||||||
preferences.setLong(R.string.p_last_backup, now());
|
|
||||||
startBackup(context);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void scheduleNext() {
|
|
||||||
workManager.scheduleBackup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startBackup(Context context) {
|
|
||||||
try {
|
|
||||||
deleteOldLocalBackups();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
tasksJsonExporter.exportTasks(
|
|
||||||
context, TasksJsonExporter.ExportType.EXPORT_TYPE_SERVICE, null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteOldLocalBackups() {
|
|
||||||
Uri uri = preferences.getBackupDirectory();
|
|
||||||
if (uri == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (uri.getScheme()) {
|
|
||||||
case ContentResolver.SCHEME_CONTENT:
|
|
||||||
DocumentFile dir = DocumentFile.fromTreeUri(context, uri);
|
|
||||||
for (DocumentFile file : getDeleteList(dir.listFiles())) {
|
|
||||||
if (!file.delete()) {
|
|
||||||
Timber.e("Unable to delete: %s", file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ContentResolver.SCHEME_FILE:
|
|
||||||
File astridDir = new File(uri.getPath());
|
|
||||||
File[] fileArray = astridDir.listFiles(FILE_FILTER);
|
|
||||||
for (File file : getDeleteList(fileArray, DAYS_TO_KEEP_BACKUP)) {
|
|
||||||
if (!file.delete()) {
|
|
||||||
Timber.e("Unable to delete: %s", file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,90 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.todoroo.andlib.utility.DateUtilities
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.backup.TasksJsonExporter
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.injection.ApplicationContext
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileFilter
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class BackupWork(context: Context, workerParams: WorkerParameters) : RepeatingWorker(context, workerParams) {
|
||||||
|
@Inject @ApplicationContext lateinit var context: Context
|
||||||
|
@Inject lateinit var tasksJsonExporter: TasksJsonExporter
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var workManager: WorkManager
|
||||||
|
|
||||||
|
override fun run(): Result {
|
||||||
|
preferences.setLong(R.string.p_last_backup, DateUtilities.now())
|
||||||
|
startBackup(context)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scheduleNext() = workManager.scheduleBackup()
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
|
||||||
|
private fun startBackup(context: Context?) {
|
||||||
|
try {
|
||||||
|
deleteOldLocalBackups()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
tasksJsonExporter.exportTasks(
|
||||||
|
context, TasksJsonExporter.ExportType.EXPORT_TYPE_SERVICE, null)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteOldLocalBackups() {
|
||||||
|
val uri = preferences.backupDirectory
|
||||||
|
when (uri?.scheme) {
|
||||||
|
ContentResolver.SCHEME_CONTENT -> {
|
||||||
|
val dir = DocumentFile.fromTreeUri(context, uri)
|
||||||
|
for (file in getDeleteList(dir?.listFiles())) {
|
||||||
|
if (!file.delete()) {
|
||||||
|
Timber.e("Unable to delete: %s", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ContentResolver.SCHEME_FILE -> {
|
||||||
|
val astridDir = File(uri.path)
|
||||||
|
val fileArray = astridDir.listFiles(FILE_FILTER)
|
||||||
|
for (file in getDeleteList(fileArray, DAYS_TO_KEEP_BACKUP)) {
|
||||||
|
if (!file.delete()) {
|
||||||
|
Timber.e("Unable to delete: %s", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DAYS_TO_KEEP_BACKUP = 7
|
||||||
|
val BACKUP_FILE_NAME_REGEX = Regex("auto\\.[-\\d]+\\.json")
|
||||||
|
private val FILENAME_FILTER = { f: String -> f.matches(BACKUP_FILE_NAME_REGEX) }
|
||||||
|
val FILE_FILTER = FileFilter { f: File -> FILENAME_FILTER.invoke(f.name) }
|
||||||
|
private val BY_LAST_MODIFIED = Comparator { f1: File, f2: File -> f2.lastModified().compareTo(f1.lastModified()) }
|
||||||
|
private val DOCUMENT_FILE_COMPARATOR = Comparator { d1: DocumentFile, d2: DocumentFile -> d2.lastModified().compareTo(d1.lastModified()) }
|
||||||
|
|
||||||
|
fun getDeleteList(fileArray: Array<File>?, keepNewest: Int) =
|
||||||
|
fileArray?.sortedWith(BY_LAST_MODIFIED)?.drop(keepNewest) ?: emptyList()
|
||||||
|
|
||||||
|
private fun getDeleteList(fileArray: Array<DocumentFile>?) =
|
||||||
|
fileArray
|
||||||
|
?.filter { FILENAME_FILTER.invoke(it.name!!) }
|
||||||
|
?.sortedWith(DOCUMENT_FILE_COMPARATOR)
|
||||||
|
?.drop(DAYS_TO_KEEP_BACKUP)
|
||||||
|
?: emptyList()
|
||||||
|
}
|
||||||
|
}
|
@ -1,77 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import com.todoroo.astrid.alarms.AlarmService;
|
|
||||||
import com.todoroo.astrid.reminders.ReminderService;
|
|
||||||
import com.todoroo.astrid.timers.TimerPlugin;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.data.DeletionDao;
|
|
||||||
import org.tasks.data.Geofence;
|
|
||||||
import org.tasks.data.LocationDao;
|
|
||||||
import org.tasks.data.TaskAttachment;
|
|
||||||
import org.tasks.data.TaskAttachmentDao;
|
|
||||||
import org.tasks.data.UserActivity;
|
|
||||||
import org.tasks.data.UserActivityDao;
|
|
||||||
import org.tasks.files.FileHelper;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.injection.InjectingWorker;
|
|
||||||
import org.tasks.location.GeofenceApi;
|
|
||||||
import org.tasks.notifications.NotificationManager;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class CleanupWork extends InjectingWorker {
|
|
||||||
|
|
||||||
static final String EXTRA_TASK_IDS = "extra_task_ids";
|
|
||||||
private final Context context;
|
|
||||||
@Inject NotificationManager notificationManager;
|
|
||||||
@Inject GeofenceApi geofenceApi;
|
|
||||||
@Inject TimerPlugin timerPlugin;
|
|
||||||
@Inject ReminderService reminderService;
|
|
||||||
@Inject AlarmService alarmService;
|
|
||||||
@Inject TaskAttachmentDao taskAttachmentDao;
|
|
||||||
@Inject UserActivityDao userActivityDao;
|
|
||||||
@Inject LocationDao locationDao;
|
|
||||||
@Inject DeletionDao deletionDao;
|
|
||||||
|
|
||||||
public CleanupWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Result run() {
|
|
||||||
long[] tasks = getInputData().getLongArray(EXTRA_TASK_IDS);
|
|
||||||
if (tasks == null) {
|
|
||||||
Timber.e("No task ids provided");
|
|
||||||
return Result.failure();
|
|
||||||
}
|
|
||||||
for (long task : tasks) {
|
|
||||||
alarmService.cancelAlarms(task);
|
|
||||||
reminderService.cancelReminder(task);
|
|
||||||
notificationManager.cancel(task);
|
|
||||||
for (Geofence geofence : locationDao.getGeofencesForTask(task)) {
|
|
||||||
locationDao.delete(geofence);
|
|
||||||
geofenceApi.update(geofence.getPlace());
|
|
||||||
}
|
|
||||||
for (TaskAttachment attachment : taskAttachmentDao.getAttachments(task)) {
|
|
||||||
FileHelper.delete(context, attachment.parseUri());
|
|
||||||
taskAttachmentDao.delete(attachment);
|
|
||||||
}
|
|
||||||
for (UserActivity comment : userActivityDao.getComments(task)) {
|
|
||||||
FileHelper.delete(context, comment.getPictureUri());
|
|
||||||
userActivityDao.delete(comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
timerPlugin.updateNotifications();
|
|
||||||
deletionDao.purgeDeleted();
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,65 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.todoroo.astrid.alarms.AlarmService
|
||||||
|
import com.todoroo.astrid.reminders.ReminderService
|
||||||
|
import com.todoroo.astrid.timers.TimerPlugin
|
||||||
|
import org.tasks.data.DeletionDao
|
||||||
|
import org.tasks.data.LocationDao
|
||||||
|
import org.tasks.data.TaskAttachmentDao
|
||||||
|
import org.tasks.data.UserActivityDao
|
||||||
|
import org.tasks.files.FileHelper
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.injection.InjectingWorker
|
||||||
|
import org.tasks.location.GeofenceApi
|
||||||
|
import org.tasks.notifications.NotificationManager
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CleanupWork(private val context: Context, workerParams: WorkerParameters) : InjectingWorker(context, workerParams) {
|
||||||
|
|
||||||
|
@Inject lateinit var notificationManager: NotificationManager
|
||||||
|
@Inject lateinit var geofenceApi: GeofenceApi
|
||||||
|
@Inject lateinit var timerPlugin: TimerPlugin
|
||||||
|
@Inject lateinit var reminderService: ReminderService
|
||||||
|
@Inject lateinit var alarmService: AlarmService
|
||||||
|
@Inject lateinit var taskAttachmentDao: TaskAttachmentDao
|
||||||
|
@Inject lateinit var userActivityDao: UserActivityDao
|
||||||
|
@Inject lateinit var locationDao: LocationDao
|
||||||
|
@Inject lateinit var deletionDao: DeletionDao
|
||||||
|
|
||||||
|
public override fun run(): Result {
|
||||||
|
val tasks = inputData.getLongArray(EXTRA_TASK_IDS)
|
||||||
|
if (tasks == null) {
|
||||||
|
Timber.e("No task ids provided")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
tasks.forEach { task ->
|
||||||
|
alarmService.cancelAlarms(task)
|
||||||
|
reminderService.cancelReminder(task)
|
||||||
|
notificationManager.cancel(task)
|
||||||
|
locationDao.getGeofencesForTask(task).forEach {
|
||||||
|
locationDao.delete(it)
|
||||||
|
geofenceApi.update(it.place!!)
|
||||||
|
}
|
||||||
|
taskAttachmentDao.getAttachments(task).forEach {
|
||||||
|
FileHelper.delete(context, it.parseUri())
|
||||||
|
taskAttachmentDao.delete(it)
|
||||||
|
}
|
||||||
|
userActivityDao.getComments(task).forEach {
|
||||||
|
FileHelper.delete(context, it.pictureUri)
|
||||||
|
userActivityDao.delete(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timerPlugin.updateNotifications()
|
||||||
|
deletionDao.purgeDeleted()
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXTRA_TASK_IDS = "extra_task_ids"
|
||||||
|
}
|
||||||
|
}
|
@ -1,113 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.skip;
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
|
||||||
import static org.tasks.Strings.isNullOrEmpty;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.Data;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
|
||||||
import com.google.api.services.drive.model.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.drive.DriveInvoker;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.injection.ApplicationContext;
|
|
||||||
import org.tasks.injection.InjectingWorker;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public class DriveUploader extends InjectingWorker {
|
|
||||||
|
|
||||||
private static final String FOLDER_NAME = "Tasks Backups";
|
|
||||||
private static final String EXTRA_URI = "extra_uri";
|
|
||||||
private static final String EXTRA_PURGE = "extra_purge";
|
|
||||||
private static final Comparator<File> DRIVE_FILE_COMPARATOR =
|
|
||||||
(f1, f2) -> Long.compare(f2.getModifiedTime().getValue(), f1.getModifiedTime().getValue());
|
|
||||||
|
|
||||||
@Inject @ApplicationContext Context context;
|
|
||||||
@Inject DriveInvoker drive;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
|
|
||||||
public DriveUploader(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Data getInputData(Uri uri, boolean purge) {
|
|
||||||
return new Data.Builder()
|
|
||||||
.putString(EXTRA_URI, uri.toString())
|
|
||||||
.putBoolean(EXTRA_PURGE, purge)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<File> getDeleteList(List<File> files) {
|
|
||||||
Collections.sort(files, DRIVE_FILE_COMPARATOR);
|
|
||||||
return newArrayList(skip(files, BackupWork.DAYS_TO_KEEP_BACKUP));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Result run() {
|
|
||||||
Data inputData = getInputData();
|
|
||||||
Uri uri = Uri.parse(inputData.getString(EXTRA_URI));
|
|
||||||
try {
|
|
||||||
File folder = getFolder();
|
|
||||||
preferences.setString(R.string.p_google_drive_backup_folder, folder.getId());
|
|
||||||
drive.createFile(folder.getId(), uri);
|
|
||||||
|
|
||||||
if (inputData.getBoolean(EXTRA_PURGE, false)) {
|
|
||||||
List<File> files = drive.getFilesByPrefix(folder.getId(), "auto.");
|
|
||||||
for (File file : getDeleteList(files)) {
|
|
||||||
try {
|
|
||||||
drive.delete(file);
|
|
||||||
} catch (GoogleJsonResponseException e) {
|
|
||||||
if (e.getStatusCode() == 404) {
|
|
||||||
Timber.e(e);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.success();
|
|
||||||
} catch (SocketTimeoutException | SSLException | ConnectException | UnknownHostException e) {
|
|
||||||
Timber.e(e);
|
|
||||||
return Result.retry();
|
|
||||||
} catch (IOException e) {
|
|
||||||
firebase.reportException(e);
|
|
||||||
return Result.failure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getFolder() throws IOException {
|
|
||||||
String folderId = preferences.getStringValue(R.string.p_google_drive_backup_folder);
|
|
||||||
File file = null;
|
|
||||||
if (!isNullOrEmpty(folderId)) {
|
|
||||||
try {
|
|
||||||
file = drive.getFile(folderId);
|
|
||||||
} catch (GoogleJsonResponseException e) {
|
|
||||||
if (e.getStatusCode() != 404) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return file == null || file.getTrashed() ? drive.createFolder(FOLDER_NAME) : file;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,106 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.google.api.client.googleapis.json.GoogleJsonResponseException
|
||||||
|
import com.google.api.services.drive.model.File
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.Strings.isNullOrEmpty
|
||||||
|
import org.tasks.drive.DriveInvoker
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.injection.ApplicationContext
|
||||||
|
import org.tasks.injection.InjectingWorker
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.ConnectException
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.net.ssl.SSLException
|
||||||
|
|
||||||
|
class DriveUploader(context: Context, workerParams: WorkerParameters) : InjectingWorker(context, workerParams) {
|
||||||
|
@Inject @ApplicationContext lateinit var context: Context
|
||||||
|
@Inject lateinit var drive: DriveInvoker
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
|
||||||
|
override fun run(): Result {
|
||||||
|
val inputData = inputData
|
||||||
|
val uri = Uri.parse(inputData.getString(EXTRA_URI))
|
||||||
|
return try {
|
||||||
|
val folder = folder
|
||||||
|
preferences.setString(R.string.p_google_drive_backup_folder, folder.id)
|
||||||
|
drive.createFile(folder.id, uri)
|
||||||
|
if (inputData.getBoolean(EXTRA_PURGE, false)) {
|
||||||
|
val files = drive.getFilesByPrefix(folder.id, "auto.")
|
||||||
|
for (file in getDeleteList(files)) {
|
||||||
|
try {
|
||||||
|
drive.delete(file)
|
||||||
|
} catch (e: GoogleJsonResponseException) {
|
||||||
|
if (e.statusCode == 404) {
|
||||||
|
Timber.e(e)
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result.success()
|
||||||
|
} catch (e: SocketTimeoutException) {
|
||||||
|
Timber.e(e)
|
||||||
|
Result.retry()
|
||||||
|
} catch (e: SSLException) {
|
||||||
|
Timber.e(e)
|
||||||
|
Result.retry()
|
||||||
|
} catch (e: ConnectException) {
|
||||||
|
Timber.e(e)
|
||||||
|
Result.retry()
|
||||||
|
} catch (e: UnknownHostException) {
|
||||||
|
Timber.e(e)
|
||||||
|
Result.retry()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
firebase.reportException(e)
|
||||||
|
Result.failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:Throws(IOException::class)
|
||||||
|
private val folder: File
|
||||||
|
get() {
|
||||||
|
val folderId = preferences.getStringValue(R.string.p_google_drive_backup_folder)
|
||||||
|
var file: File? = null
|
||||||
|
if (!isNullOrEmpty(folderId)) {
|
||||||
|
try {
|
||||||
|
file = drive.getFile(folderId)
|
||||||
|
} catch (e: GoogleJsonResponseException) {
|
||||||
|
if (e.statusCode != 404) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (file == null || file.trashed) drive.createFolder(FOLDER_NAME) else file
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val FOLDER_NAME = "Tasks Backups"
|
||||||
|
private const val EXTRA_URI = "extra_uri"
|
||||||
|
private const val EXTRA_PURGE = "extra_purge"
|
||||||
|
private val DRIVE_FILE_COMPARATOR = Comparator<File> { f1, f2 ->
|
||||||
|
f2.modifiedTime.value.compareTo(f1.modifiedTime.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInputData(uri: Uri, purge: Boolean) =
|
||||||
|
Data.Builder()
|
||||||
|
.putString(EXTRA_URI, uri.toString())
|
||||||
|
.putBoolean(EXTRA_PURGE, purge)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private fun getDeleteList(files: List<File>) =
|
||||||
|
files.sortedWith(DRIVE_FILE_COMPARATOR).drop(BackupWork.DAYS_TO_KEEP_BACKUP)
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
|
|
||||||
public class MidnightRefreshWork extends RepeatingWorker {
|
|
||||||
|
|
||||||
@Inject WorkManager workManager;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
|
|
||||||
public MidnightRefreshWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Result run() {
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void scheduleNext() {
|
|
||||||
workManager.scheduleMidnightRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MidnightRefreshWork(context: Context, workerParams: WorkerParameters) : RepeatingWorker(context, workerParams) {
|
||||||
|
@Inject lateinit var workManager: WorkManager
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
|
||||||
|
override fun run(): Result {
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scheduleNext() = workManager.scheduleMidnightRefresh()
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.scheduling.RefreshScheduler;
|
|
||||||
|
|
||||||
public class RefreshWork extends RepeatingWorker {
|
|
||||||
|
|
||||||
@Inject RefreshScheduler refreshScheduler;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
|
|
||||||
public RefreshWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Result run() {
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void scheduleNext() {
|
|
||||||
refreshScheduler.scheduleNext();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,22 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.scheduling.RefreshScheduler
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RefreshWork(context: Context, workerParams: WorkerParameters) : RepeatingWorker(context, workerParams) {
|
||||||
|
@Inject lateinit var refreshScheduler: RefreshScheduler
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
|
||||||
|
public override fun run(): Result {
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
|
||||||
|
override fun scheduleNext() = refreshScheduler.scheduleNext()
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import org.tasks.injection.InjectingWorker;
|
|
||||||
|
|
||||||
public abstract class RepeatingWorker extends InjectingWorker {
|
|
||||||
|
|
||||||
RepeatingWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public final Result doWork() {
|
|
||||||
Result result = super.doWork();
|
|
||||||
scheduleNext();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void scheduleNext();
|
|
||||||
}
|
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import org.tasks.injection.InjectingWorker
|
||||||
|
|
||||||
|
abstract class RepeatingWorker internal constructor(context: Context, workerParams: WorkerParameters) : InjectingWorker(context, workerParams) {
|
||||||
|
override fun doWork(): Result {
|
||||||
|
val result = super.doWork()
|
||||||
|
scheduleNext()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun scheduleNext()
|
||||||
|
}
|
@ -1,94 +0,0 @@
|
|||||||
package org.tasks.jobs;
|
|
||||||
|
|
||||||
import static java.util.concurrent.Executors.newFixedThreadPool;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.caldav.CaldavSynchronizer;
|
|
||||||
import org.tasks.data.CaldavAccount;
|
|
||||||
import org.tasks.data.CaldavDao;
|
|
||||||
import org.tasks.data.GoogleTaskAccount;
|
|
||||||
import org.tasks.data.GoogleTaskListDao;
|
|
||||||
import org.tasks.etesync.EteSynchronizer;
|
|
||||||
import org.tasks.gtasks.GoogleTaskSynchronizer;
|
|
||||||
import org.tasks.injection.ApplicationComponent;
|
|
||||||
import org.tasks.injection.InjectingWorker;
|
|
||||||
import org.tasks.preferences.Preferences;
|
|
||||||
import org.tasks.sync.SyncAdapters;
|
|
||||||
|
|
||||||
public class SyncWork extends InjectingWorker {
|
|
||||||
|
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
|
|
||||||
@Inject CaldavSynchronizer caldavSynchronizer;
|
|
||||||
@Inject EteSynchronizer eteSynchronizer;
|
|
||||||
@Inject GoogleTaskSynchronizer googleTaskSynchronizer;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
@Inject Preferences preferences;
|
|
||||||
@Inject CaldavDao caldavDao;
|
|
||||||
@Inject GoogleTaskListDao googleTaskListDao;
|
|
||||||
@Inject SyncAdapters syncAdapters;
|
|
||||||
|
|
||||||
public SyncWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Result run() {
|
|
||||||
if (!syncAdapters.isSyncEnabled()) {
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
synchronized (LOCK) {
|
|
||||||
if (preferences.isSyncOngoing()) {
|
|
||||||
return Result.retry();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preferences.setSyncOngoing(true);
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
try {
|
|
||||||
sync();
|
|
||||||
} catch (Exception e) {
|
|
||||||
firebase.reportException(e);
|
|
||||||
} finally {
|
|
||||||
preferences.setSyncOngoing(false);
|
|
||||||
localBroadcastManager.broadcastRefresh();
|
|
||||||
}
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sync() throws InterruptedException {
|
|
||||||
int numThreads = Runtime.getRuntime().availableProcessors();
|
|
||||||
ExecutorService executor = newFixedThreadPool(numThreads);
|
|
||||||
|
|
||||||
for (CaldavAccount account : caldavDao.getAccounts()) {
|
|
||||||
executor.execute(
|
|
||||||
() -> {
|
|
||||||
if (account.isCaldavAccount()) {
|
|
||||||
caldavSynchronizer.sync(account);
|
|
||||||
} else if (account.isEteSyncAccount()) {
|
|
||||||
eteSynchronizer.sync(account);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
List<GoogleTaskAccount> accounts = googleTaskListDao.getAccounts();
|
|
||||||
for (int i = 0; i < accounts.size(); i++) {
|
|
||||||
int count = i;
|
|
||||||
executor.execute(() -> googleTaskSynchronizer.sync(accounts.get(count), count));
|
|
||||||
}
|
|
||||||
|
|
||||||
executor.shutdown();
|
|
||||||
executor.awaitTermination(15, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(ApplicationComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,77 @@
|
|||||||
|
package org.tasks.jobs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.caldav.CaldavSynchronizer
|
||||||
|
import org.tasks.data.CaldavDao
|
||||||
|
import org.tasks.data.GoogleTaskListDao
|
||||||
|
import org.tasks.etesync.EteSynchronizer
|
||||||
|
import org.tasks.gtasks.GoogleTaskSynchronizer
|
||||||
|
import org.tasks.injection.ApplicationComponent
|
||||||
|
import org.tasks.injection.InjectingWorker
|
||||||
|
import org.tasks.preferences.Preferences
|
||||||
|
import org.tasks.sync.SyncAdapters
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SyncWork(context: Context, workerParams: WorkerParameters) : InjectingWorker(context, workerParams) {
|
||||||
|
@Inject lateinit var caldavSynchronizer: CaldavSynchronizer
|
||||||
|
@Inject lateinit var eteSynchronizer: EteSynchronizer
|
||||||
|
@Inject lateinit var googleTaskSynchronizer: GoogleTaskSynchronizer
|
||||||
|
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||||
|
@Inject lateinit var preferences: Preferences
|
||||||
|
@Inject lateinit var caldavDao: CaldavDao
|
||||||
|
@Inject lateinit var googleTaskListDao: GoogleTaskListDao
|
||||||
|
@Inject lateinit var syncAdapters: SyncAdapters
|
||||||
|
|
||||||
|
public override fun run(): Result {
|
||||||
|
if (!syncAdapters.isSyncEnabled) {
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
synchronized(LOCK) {
|
||||||
|
if (preferences.isSyncOngoing) {
|
||||||
|
return Result.retry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferences.isSyncOngoing = true
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
try {
|
||||||
|
sync()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
firebase.reportException(e)
|
||||||
|
} finally {
|
||||||
|
preferences.isSyncOngoing = false
|
||||||
|
localBroadcastManager.broadcastRefresh()
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
private fun sync() {
|
||||||
|
val numThreads = Runtime.getRuntime().availableProcessors()
|
||||||
|
val executor = Executors.newFixedThreadPool(numThreads)
|
||||||
|
for (account in caldavDao.getAccounts()) {
|
||||||
|
executor.execute {
|
||||||
|
if (account.isCaldavAccount) {
|
||||||
|
caldavSynchronizer.sync(account)
|
||||||
|
} else if (account.isEteSyncAccount) {
|
||||||
|
eteSynchronizer.sync(account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val accounts = googleTaskListDao.getAccounts()
|
||||||
|
for (i in accounts.indices) {
|
||||||
|
executor.execute { googleTaskSynchronizer.sync(accounts[i], i) }
|
||||||
|
}
|
||||||
|
executor.shutdown()
|
||||||
|
executor.awaitTermination(15, TimeUnit.MINUTES)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ApplicationComponent) = component.inject(this)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOCK = Any()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue