From 50eedbfe03bd23efbfdda3285062957336487183 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Thu, 7 Sep 2017 14:32:52 -0500 Subject: [PATCH] Move post-save activity to intent service --- .../astrid/repeats/AdvancedRepeatTest.java | 6 +- .../astrid/repeats/NewRepeatTests.java | 2 +- ...nerTest.java => RepeatTaskHelperTest.java} | 4 +- .../java/org/tasks/injection/TestModule.java | 6 + .../tasks/injection/BroadcastComponent.java | 50 ------- app/src/googleplay/AndroidManifest.xml | 7 - .../tasks/injection/BroadcastComponent.java | 53 ------- .../receivers/GoogleTaskPushReceiver.java | 74 ---------- .../org/tasks/receivers/GoogleTaskPusher.java | 50 +++++++ .../org/tasks/receivers/PushReceiver.java | 7 +- app/src/main/AndroidManifest.xml | 16 +-- .../alarms/AlarmTaskRepeatListener.java | 62 -------- .../java/com/todoroo/astrid/dao/TaskDao.java | 94 +----------- .../astrid/gcal/GCalTaskCompleteListener.java | 72 ---------- ...eteListener.java => RepeatTaskHelper.java} | 74 +++++----- .../timers/TimerTaskCompleteListener.java | 53 ------- .../tasks/injection/BroadcastComponent.java | 12 -- .../injection/IntentServiceComponent.java | 3 + .../tasks/jobs/AfterSaveIntentService.java | 135 ++++++++++++++++++ .../main/java/org/tasks/jobs/JobManager.java | 1 + 20 files changed, 250 insertions(+), 531 deletions(-) rename app/src/androidTest/java/com/todoroo/astrid/repeats/{RepeatTaskCompleteListenerTest.java => RepeatTaskHelperTest.java} (96%) delete mode 100644 app/src/generic/java/org/tasks/injection/BroadcastComponent.java delete mode 100644 app/src/googleplay/java/org/tasks/injection/BroadcastComponent.java delete mode 100644 app/src/googleplay/java/org/tasks/receivers/GoogleTaskPushReceiver.java create mode 100644 app/src/googleplay/java/org/tasks/receivers/GoogleTaskPusher.java delete mode 100644 app/src/main/java/com/todoroo/astrid/alarms/AlarmTaskRepeatListener.java delete mode 100644 app/src/main/java/com/todoroo/astrid/gcal/GCalTaskCompleteListener.java rename app/src/main/java/com/todoroo/astrid/repeats/{RepeatTaskCompleteListener.java => RepeatTaskHelper.java} (85%) delete mode 100644 app/src/main/java/com/todoroo/astrid/timers/TimerTaskCompleteListener.java rename app/src/{amazon => main}/java/org/tasks/injection/BroadcastComponent.java (70%) create mode 100644 app/src/main/java/org/tasks/jobs/AfterSaveIntentService.java diff --git a/app/src/androidTest/java/com/todoroo/astrid/repeats/AdvancedRepeatTest.java b/app/src/androidTest/java/com/todoroo/astrid/repeats/AdvancedRepeatTest.java index 717d590a8..d3d7af909 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/repeats/AdvancedRepeatTest.java +++ b/app/src/androidTest/java/com/todoroo/astrid/repeats/AdvancedRepeatTest.java @@ -56,7 +56,7 @@ public class AdvancedRepeatTest { task.setDueDate(dayWithTime); long nextDayWithTime = dayWithTime + DateUtilities.ONE_DAY; - nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), false); + nextDueDate = RepeatTaskHelper.computeNextDueDate(task, rrule.toIcal(), false); assertDateTimeEquals(nextDayWithTime, nextDueDate); } @@ -76,7 +76,7 @@ public class AdvancedRepeatTest { nextDayWithTimeLong += DateUtilities.ONE_DAY; nextDayWithTimeLong = nextDayWithTimeLong / 1000L * 1000; - nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), true); + nextDueDate = RepeatTaskHelper.computeNextDueDate(task, rrule.toIcal(), true); assertDateTimeEquals(nextDayWithTimeLong, nextDueDate); } @@ -224,7 +224,7 @@ public class AdvancedRepeatTest { // --- helpers private void computeNextDueDate(boolean fromComplete) throws ParseException{ - nextDueDate = RepeatTaskCompleteListener.computeNextDueDate(task, rrule.toIcal(), fromComplete); + nextDueDate = RepeatTaskHelper.computeNextDueDate(task, rrule.toIcal(), fromComplete); } private void buildRRule(int interval, Frequency freq, Weekday... weekdays) { diff --git a/app/src/androidTest/java/com/todoroo/astrid/repeats/NewRepeatTests.java b/app/src/androidTest/java/com/todoroo/astrid/repeats/NewRepeatTests.java index d732342d1..d28cd028f 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/repeats/NewRepeatTests.java +++ b/app/src/androidTest/java/com/todoroo/astrid/repeats/NewRepeatTests.java @@ -14,7 +14,7 @@ import org.tasks.time.DateTime; import java.text.ParseException; -import static com.todoroo.astrid.repeats.RepeatTaskCompleteListener.computeNextDueDate; +import static com.todoroo.astrid.repeats.RepeatTaskHelper.computeNextDueDate; import static java.util.Arrays.asList; import static junit.framework.Assert.assertEquals; diff --git a/app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListenerTest.java b/app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskHelperTest.java similarity index 96% rename from app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListenerTest.java rename to app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskHelperTest.java index 6e5283be5..7b42f3e91 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListenerTest.java +++ b/app/src/androidTest/java/com/todoroo/astrid/repeats/RepeatTaskHelperTest.java @@ -19,7 +19,7 @@ import static com.google.ical.values.Frequency.MINUTELY; import static com.google.ical.values.Frequency.WEEKLY; import static com.google.ical.values.Frequency.YEARLY; import static com.todoroo.andlib.utility.DateUtilities.addCalendarMonthsToUnixtime; -import static com.todoroo.astrid.repeats.RepeatTaskCompleteListener.computeNextDueDate; +import static com.todoroo.astrid.repeats.RepeatTaskHelper.computeNextDueDate; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.MINUTES; @@ -27,7 +27,7 @@ import static junit.framework.Assert.assertEquals; @SuppressLint("NewApi") @RunWith(AndroidJUnit4.class) -public class RepeatTaskCompleteListenerTest { +public class RepeatTaskHelperTest { private final Task task = new Task(); private final long dueDate; diff --git a/app/src/androidTest/java/org/tasks/injection/TestModule.java b/app/src/androidTest/java/org/tasks/injection/TestModule.java index 55e267ef6..e3d1bf802 100644 --- a/app/src/androidTest/java/org/tasks/injection/TestModule.java +++ b/app/src/androidTest/java/org/tasks/injection/TestModule.java @@ -7,6 +7,7 @@ import com.todoroo.astrid.dao.Database; import org.tasks.analytics.Tracker; import org.tasks.db.AppDatabase; +import org.tasks.notifications.NotificationDao; import org.tasks.preferences.PermissionChecker; import org.tasks.preferences.PermissivePermissionChecker; @@ -40,6 +41,11 @@ public class TestModule { return Room.databaseBuilder(context, AppDatabase.class, "test-app-database").build(); } + @Provides + public NotificationDao getNotificationDao(AppDatabase appDatabase) { + return appDatabase.notificationDao(); + } + @ApplicationScope @Provides @ForApplication diff --git a/app/src/generic/java/org/tasks/injection/BroadcastComponent.java b/app/src/generic/java/org/tasks/injection/BroadcastComponent.java deleted file mode 100644 index 40ddffd8a..000000000 --- a/app/src/generic/java/org/tasks/injection/BroadcastComponent.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.tasks.injection; - -import com.todoroo.astrid.alarms.AlarmTaskRepeatListener; -import com.todoroo.astrid.calls.PhoneStateChangedReceiver; -import com.todoroo.astrid.gcal.CalendarAlarmReceiver; -import com.todoroo.astrid.gcal.GCalTaskCompleteListener; -import com.todoroo.astrid.repeats.RepeatTaskCompleteListener; -import com.todoroo.astrid.timers.TimerTaskCompleteListener; - -import org.tasks.locale.receiver.FireReceiver; -import org.tasks.notifications.NotificationClearedReceiver; -import org.tasks.receivers.BootCompletedReceiver; -import org.tasks.receivers.CompleteTaskReceiver; -import org.tasks.receivers.MyPackageReplacedReceiver; -import org.tasks.receivers.PushReceiver; -import org.tasks.receivers.TeslaUnreadReceiver; -import org.tasks.widget.TasksWidget; - -import dagger.Subcomponent; - -@Subcomponent(modules = BroadcastModule.class) -public interface BroadcastComponent { - void inject(FireReceiver fireReceiver); - - void inject(TimerTaskCompleteListener timerTaskCompleteListener); - - void inject(PhoneStateChangedReceiver phoneStateChangedReceiver); - - void inject(AlarmTaskRepeatListener alarmTaskRepeatListener); - - void inject(GCalTaskCompleteListener gCalTaskCompleteListener); - - void inject(CalendarAlarmReceiver calendarAlarmReceiver); - - void inject(RepeatTaskCompleteListener repeatTaskCompleteListener); - - void inject(MyPackageReplacedReceiver myPackageReplacedReceiver); - - void inject(CompleteTaskReceiver completeTaskReceiver); - - void inject(BootCompletedReceiver bootCompletedReceiver); - - void inject(TasksWidget tasksWidget); - - void inject(TeslaUnreadReceiver teslaUnreadReceiver); - - void inject(PushReceiver pushReceiver); - - void inject(NotificationClearedReceiver notificationClearedReceiver); -} diff --git a/app/src/googleplay/AndroidManifest.xml b/app/src/googleplay/AndroidManifest.xml index eece8f1d8..57af1cc1e 100644 --- a/app/src/googleplay/AndroidManifest.xml +++ b/app/src/googleplay/AndroidManifest.xml @@ -57,13 +57,6 @@ android:label="@string/synchronization" android:theme="@style/Tasks" /> - - - - - - - [] TASK_PROPERTIES = { Task.ID, Task.TITLE, - Task.NOTES, Task.DUE_DATE, Task.COMPLETION_DATE, Task.DELETION_DATE }; - - @Inject SyncAdapterHelper syncAdapterHelper; - - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); - - if(!syncAdapterHelper.isEnabled()) { - return; - } - - Task model = intent.getParcelableExtra(AstridApiConstants.EXTRAS_TASK); - ContentValues setValues = intent.getParcelableExtra(AstridApiConstants.EXTRAS_VALUES); - if (model == null) { - return; - } - if(model.checkTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC)) { - return; - } - if (checkValuesForProperties(setValues, TASK_PROPERTIES) || model.checkTransitory(SyncFlags.FORCE_SYNC)) { - syncAdapterHelper.requestSynchronization(); - } - } - - @Override - protected void inject(BroadcastComponent component) { - component.inject(this); - } - - /** - * Checks to see if any of the values changed are among the properties we sync - * @return false if none of the properties we sync were changed, true otherwise - */ - private boolean checkValuesForProperties(ContentValues values, Property[] properties) { - if (values == null) { - return false; - } - for (Property property : properties) { - if (property != Task.ID && values.containsKey(property.name)) { - return true; - } - } - return false; - } -} diff --git a/app/src/googleplay/java/org/tasks/receivers/GoogleTaskPusher.java b/app/src/googleplay/java/org/tasks/receivers/GoogleTaskPusher.java new file mode 100644 index 000000000..5c3c0e25d --- /dev/null +++ b/app/src/googleplay/java/org/tasks/receivers/GoogleTaskPusher.java @@ -0,0 +1,50 @@ +package org.tasks.receivers; + +import android.content.ContentValues; + +import com.todoroo.andlib.data.Property; +import com.todoroo.astrid.data.SyncFlags; +import com.todoroo.astrid.data.Task; + +import org.tasks.gtasks.SyncAdapterHelper; + +import javax.inject.Inject; + +public class GoogleTaskPusher { + + private static final Property[] GOOGLE_TASK_PROPERTIES = { Task.ID, Task.TITLE, + Task.NOTES, Task.DUE_DATE, Task.COMPLETION_DATE, Task.DELETION_DATE }; + + private final SyncAdapterHelper syncAdapterHelper; + + @Inject + public GoogleTaskPusher(SyncAdapterHelper syncAdapterHelper) { + this.syncAdapterHelper = syncAdapterHelper; + } + + void push(Task task, ContentValues modifiedValues) { + if(!syncAdapterHelper.isEnabled()) { + return; + } + + if(task.checkTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC)) { + return; + } + + if (checkValuesForProperties(modifiedValues, GOOGLE_TASK_PROPERTIES) || task.checkTransitory(SyncFlags.FORCE_SYNC)) { + syncAdapterHelper.requestSynchronization(); + } + } + + private boolean checkValuesForProperties(ContentValues values, Property[] properties) { + if (values == null) { + return false; + } + for (Property property : properties) { + if (property != Task.ID && values.containsKey(property.name)) { + return true; + } + } + return false; + } +} diff --git a/app/src/googleplay/java/org/tasks/receivers/PushReceiver.java b/app/src/googleplay/java/org/tasks/receivers/PushReceiver.java index a6b1119b0..e77d96505 100644 --- a/app/src/googleplay/java/org/tasks/receivers/PushReceiver.java +++ b/app/src/googleplay/java/org/tasks/receivers/PushReceiver.java @@ -10,6 +10,8 @@ import com.todoroo.astrid.data.Task; import org.tasks.injection.BroadcastComponent; import org.tasks.injection.InjectingBroadcastReceiver; +import javax.inject.Inject; + public class PushReceiver extends InjectingBroadcastReceiver { public static void broadcast(Context context, Task task, ContentValues values) { @@ -19,12 +21,13 @@ public class PushReceiver extends InjectingBroadcastReceiver { context.sendBroadcast(intent); } + @Inject GoogleTaskPusher googleTaskPusher; + @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); - GoogleTaskPushReceiver.broadcast( - context, + googleTaskPusher.push( intent.getParcelableExtra(AstridApiConstants.EXTRAS_TASK), intent.getParcelableExtra(AstridApiConstants.EXTRAS_VALUES)); } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cdd7c0834..260fca23c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -328,22 +328,12 @@ android:name="com.todoroo.astrid.core.CustomFilterActivity" android:theme="@style/Tasks"/> - - - - - - - - - - @@ -381,8 +371,6 @@ android:name=".files.FileExplore" android:theme="@style/TranslucentDialog"/> - - + alarms = new LinkedHashSet<>(); - alarmService.getAlarms(taskId, metadata -> alarms.add(metadata.getValue(AlarmFields.TIME) + (newDueDate - oldDueDate))); - if (!alarms.isEmpty()) { - alarmService.synchronizeAlarms(taskId, alarms); - } - } - - @Override - protected void inject(BroadcastComponent component) { - component.inject(this); - } -} diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java index 673d2f6ae..2490346b3 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java @@ -24,20 +24,14 @@ import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.SyncFlags; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskApiDao; -import com.todoroo.astrid.gcal.GCalTaskCompleteListener; -import com.todoroo.astrid.reminders.ReminderService; -import com.todoroo.astrid.repeats.RepeatTaskCompleteListener; -import com.todoroo.astrid.timers.TimerTaskCompleteListener; import org.tasks.LocalBroadcastManager; import org.tasks.R; import org.tasks.injection.ApplicationScope; import org.tasks.injection.ForApplication; -import org.tasks.location.GeofenceService; -import org.tasks.notifications.NotificationManager; +import org.tasks.jobs.AfterSaveIntentService; import org.tasks.preferences.Preferences; import org.tasks.receivers.PushReceiver; -import org.tasks.scheduling.RefreshScheduler; import java.util.List; @@ -57,30 +51,20 @@ public class TaskDao { public static final String TRANS_SUPPRESS_REFRESH = "suppress-refresh"; private final RemoteModelDao dao; - private final RefreshScheduler refreshScheduler; private final LocalBroadcastManager localBroadcastManager; private final MetadataDao metadataDao; - private final ReminderService reminderService; - private final NotificationManager notificationManager; private final Preferences preferences; - private Context context; - private final GeofenceService geofenceService; + private final Context context; @Inject public TaskDao(@ForApplication Context context, Database database, MetadataDao metadataDao, - ReminderService reminderService, NotificationManager notificationManager, - Preferences preferences, GeofenceService geofenceService, - RefreshScheduler refreshScheduler, LocalBroadcastManager localBroadcastManager) { + Preferences preferences, LocalBroadcastManager localBroadcastManager) { this.context = context; - this.geofenceService = geofenceService; this.preferences = preferences; this.metadataDao = metadataDao; - this.reminderService = reminderService; - this.notificationManager = notificationManager; - dao = new RemoteModelDao<>(database, Task.class); - this.refreshScheduler = refreshScheduler; this.localBroadcastManager = localBroadcastManager; + dao = new RemoteModelDao<>(database, Task.class); } public TodorooCursor query(Query query) { @@ -234,7 +218,7 @@ public class TaskDao { public void save(Task task) { ContentValues modifiedValues = createOrUpdate(task); if (modifiedValues != null) { - afterSave(task, modifiedValues); + AfterSaveIntentService.enqueue(context, task.getId(), modifiedValues); } else if (task.checkTransitory(SyncFlags.FORCE_SYNC)) { PushReceiver.broadcast(context, task, null); } @@ -399,72 +383,6 @@ public class TaskDao { } } - /** - * Called after the task is saved. This differs from the call in - * TaskApiDao in that it runs hooks that need to be run from within - * Astrid. Order matters here! - */ - private void afterSave(Task task, ContentValues values) { - task.markSaved(); - boolean completionDateModified = values.containsKey(Task.COMPLETION_DATE.name); - boolean deletionDateModified = values.containsKey(Task.DELETION_DATE.name); - if(completionDateModified && task.isCompleted()) { - afterComplete(task); - } else if (deletionDateModified && task.isDeleted()) { - afterComplete(task); - } else { - if (completionDateModified || deletionDateModified) { - geofenceService.setupGeofences(task.getId()); - } - if(values.containsKey(Task.DUE_DATE.name) || - values.containsKey(Task.REMINDER_FLAGS.name) || - values.containsKey(Task.REMINDER_PERIOD.name) || - values.containsKey(Task.REMINDER_LAST.name) || - values.containsKey(Task.REMINDER_SNOOZE.name)) { - reminderService.scheduleAlarm(this, task); - } - } - - // run api save hooks - broadcastTaskSave(task, values); - } - - /** - * Send broadcasts on task change (triggers things like task repeats) - * @param task task that was saved - * @param values values that were updated - */ - private void broadcastTaskSave(Task task, ContentValues values) { - if(TaskApiDao.insignificantChange(values)) { - return; - } - - if(values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted()) { - RepeatTaskCompleteListener.broadcast(context, task.getId()); - GCalTaskCompleteListener.broadcast(context, task.getId()); - TimerTaskCompleteListener.broadcast(context, task.getId()); - } - - PushReceiver.broadcast(context, task, values); - refreshScheduler.scheduleRefresh(task); - broadcastRefresh(task); - } - - private void broadcastRefresh(Task task) { - if (!task.checkAndClearTransitory(TRANS_SUPPRESS_REFRESH)) { - localBroadcastManager.broadcastRefresh(); - } - } - - /** - * Called after the task was just completed - */ - private void afterComplete(Task task) { - long taskId = task.getId(); - notificationManager.cancel(taskId); - geofenceService.cancelGeofences(taskId); - } - /** * Mark the given task as completed and save it. */ @@ -482,7 +400,7 @@ public class TaskDao { return query(fetchFilteredQuery(queryTemplate, properties)); } - public Query fetchFilteredQuery(String queryTemplate, Property... properties) { + private Query fetchFilteredQuery(String queryTemplate, Property... properties) { if (queryTemplate == null) { return Query.selectDistinct(properties); } diff --git a/app/src/main/java/com/todoroo/astrid/gcal/GCalTaskCompleteListener.java b/app/src/main/java/com/todoroo/astrid/gcal/GCalTaskCompleteListener.java deleted file mode 100644 index f20e22746..000000000 --- a/app/src/main/java/com/todoroo/astrid/gcal/GCalTaskCompleteListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.gcal; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.provider.CalendarContract; -import android.text.TextUtils; - -import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.dao.TaskDao; -import com.todoroo.astrid.data.Task; - -import org.tasks.R; -import org.tasks.injection.BroadcastComponent; -import org.tasks.injection.InjectingBroadcastReceiver; - -import javax.inject.Inject; - -import timber.log.Timber; - -public class GCalTaskCompleteListener extends InjectingBroadcastReceiver { - - public static void broadcast(Context context, long taskId) { - Intent intent = new Intent(context, GCalTaskCompleteListener.class); - intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); - context.sendBroadcast(intent); - } - - @Inject TaskDao taskDao; - - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); - - long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); - if(taskId == -1) { - return; - } - - Task task = taskDao.fetch(taskId, Task.ID, Task.TITLE, Task.CALENDAR_URI); - if(task == null) { - return; - } - - String calendarUri = task.getCalendarURI(); - if(!TextUtils.isEmpty(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, e.getMessage()); - } - } - } - - @Override - protected void inject(BroadcastComponent component) { - component.inject(this); - } - -} diff --git a/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java b/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.java similarity index 85% rename from app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java rename to app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.java index f41be899c..5ecc0a4dd 100644 --- a/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskCompleteListener.java +++ b/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.java @@ -5,9 +5,6 @@ */ package com.todoroo.astrid.repeats; -import android.content.Context; -import android.content.Intent; - import com.google.ical.iter.RecurrenceIterator; import com.google.ical.iter.RecurrenceIteratorFactory; import com.google.ical.values.DateTimeValueImpl; @@ -17,21 +14,21 @@ import com.google.ical.values.Frequency; import com.google.ical.values.RRule; import com.google.ical.values.WeekdayNum; import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.alarms.AlarmTaskRepeatListener; -import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.alarms.AlarmFields; +import com.todoroo.astrid.alarms.AlarmService; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.gcal.GCalHelper; import org.tasks.LocalBroadcastManager; -import org.tasks.injection.BroadcastComponent; -import org.tasks.injection.InjectingBroadcastReceiver; import org.tasks.time.DateTime; import java.text.ParseException; import java.util.Collections; import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.TimeZone; import javax.inject.Inject; @@ -42,32 +39,23 @@ import static org.tasks.date.DateTimeUtils.newDate; import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateUtc; -public class RepeatTaskCompleteListener extends InjectingBroadcastReceiver { - - public static void broadcast(Context context, long taskId) { - Intent intent = new Intent(context, RepeatTaskCompleteListener.class); - intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); - context.sendBroadcast(intent); - } - - @Inject GCalHelper gcalHelper; - @Inject TaskDao taskDao; - @Inject LocalBroadcastManager localBroadcastManager; - - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); +public class RepeatTaskHelper { - long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); - if(taskId == -1) { - return; - } + private final GCalHelper gcalHelper; + private final TaskDao taskDao; + private final LocalBroadcastManager localBroadcastManager; + private final AlarmService alarmService; - Task task = taskDao.fetch(taskId, Task.PROPERTIES); - if(task == null || !task.isCompleted()) { - return; - } + @Inject + public RepeatTaskHelper(GCalHelper gcalHelper, AlarmService alarmService, + TaskDao taskDao, LocalBroadcastManager localBroadcastManager) { + this.gcalHelper = gcalHelper; + this.taskDao = taskDao; + this.localBroadcastManager = localBroadcastManager; + this.alarmService = alarmService; + } + public void handleRepeat(Task task) { String recurrence = task.sanitizedRecurrence(); boolean repeatAfterCompletion = task.repeatAfterCompletion(); @@ -90,24 +78,18 @@ public class RepeatTaskCompleteListener extends InjectingBroadcastReceiver { return; } - rescheduleTask(gcalHelper, taskDao, task, newDueDate); - - AlarmTaskRepeatListener.broadcast(context, taskId, oldDueDate, newDueDate); + rescheduleTask(task, newDueDate); + rescheduleAlarms(task.getId(), oldDueDate, newDueDate); localBroadcastManager.broadcastRepeat(task.getId(), oldDueDate, newDueDate); } } - @Override - protected void inject(BroadcastComponent component) { - component.inject(this); - } - private static boolean repeatFinished(long newDueDate, long repeatUntil) { return repeatUntil > 0 && newDateTime(newDueDate).startOfDay().isAfter(newDateTime(repeatUntil).startOfDay()); } - private static void rescheduleTask(GCalHelper gcalHelper, TaskDao taskDao, Task task, long newDueDate) { + private void rescheduleTask(Task task, long newDueDate) { task.setReminderSnooze(0L); task.setCompletionDate(0L); task.setDueDateAdjustingHideUntil(newDueDate); @@ -116,8 +98,20 @@ public class RepeatTaskCompleteListener extends InjectingBroadcastReceiver { taskDao.save(task); } + private void rescheduleAlarms(long taskId, long oldDueDate, long newDueDate) { + if(newDueDate <= 0 || newDueDate <= oldDueDate) { + return; + } + + final Set alarms = new LinkedHashSet<>(); + alarmService.getAlarms(taskId, metadata -> alarms.add(metadata.getValue(AlarmFields.TIME) + (newDueDate - oldDueDate))); + if (!alarms.isEmpty()) { + alarmService.synchronizeAlarms(taskId, alarms); + } + } + /** Compute next due date */ - public static long computeNextDueDate(Task task, String recurrence, boolean repeatAfterCompletion) throws ParseException { + static long computeNextDueDate(Task task, String recurrence, boolean repeatAfterCompletion) throws ParseException { RRule rrule = initRRule(recurrence); // initialize startDateAsDV diff --git a/app/src/main/java/com/todoroo/astrid/timers/TimerTaskCompleteListener.java b/app/src/main/java/com/todoroo/astrid/timers/TimerTaskCompleteListener.java deleted file mode 100644 index 9cf5b4b68..000000000 --- a/app/src/main/java/com/todoroo/astrid/timers/TimerTaskCompleteListener.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ -package com.todoroo.astrid.timers; - -import android.content.Context; -import android.content.Intent; - -import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.dao.TaskDao; -import com.todoroo.astrid.data.Task; - -import org.tasks.injection.BroadcastComponent; -import org.tasks.injection.InjectingBroadcastReceiver; - -import javax.inject.Inject; - -public class TimerTaskCompleteListener extends InjectingBroadcastReceiver { - - public static void broadcast(Context context, long taskId) { - Intent intent = new Intent(context, TimerTaskCompleteListener.class); - intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId); - context.sendBroadcast(intent); - } - - @Inject TaskDao taskDao; - @Inject TimerPlugin timerPlugin; - - @Override - public void onReceive(Context context, Intent intent) { - super.onReceive(context, intent); - - long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1); - if(taskId == -1) { - return; - } - - Task task = taskDao.fetch(taskId, Task.ID, Task.ELAPSED_SECONDS, - Task.TIMER_START); - if(task == null || task.getTimerStart() == 0) { - return; - } - - timerPlugin.stopTimer(task); - } - - @Override - protected void inject(BroadcastComponent component) { - component.inject(this); - } -} diff --git a/app/src/amazon/java/org/tasks/injection/BroadcastComponent.java b/app/src/main/java/org/tasks/injection/BroadcastComponent.java similarity index 70% rename from app/src/amazon/java/org/tasks/injection/BroadcastComponent.java rename to app/src/main/java/org/tasks/injection/BroadcastComponent.java index 40ddffd8a..04d05bd70 100644 --- a/app/src/amazon/java/org/tasks/injection/BroadcastComponent.java +++ b/app/src/main/java/org/tasks/injection/BroadcastComponent.java @@ -1,11 +1,7 @@ package org.tasks.injection; -import com.todoroo.astrid.alarms.AlarmTaskRepeatListener; import com.todoroo.astrid.calls.PhoneStateChangedReceiver; import com.todoroo.astrid.gcal.CalendarAlarmReceiver; -import com.todoroo.astrid.gcal.GCalTaskCompleteListener; -import com.todoroo.astrid.repeats.RepeatTaskCompleteListener; -import com.todoroo.astrid.timers.TimerTaskCompleteListener; import org.tasks.locale.receiver.FireReceiver; import org.tasks.notifications.NotificationClearedReceiver; @@ -22,18 +18,10 @@ import dagger.Subcomponent; public interface BroadcastComponent { void inject(FireReceiver fireReceiver); - void inject(TimerTaskCompleteListener timerTaskCompleteListener); - void inject(PhoneStateChangedReceiver phoneStateChangedReceiver); - void inject(AlarmTaskRepeatListener alarmTaskRepeatListener); - - void inject(GCalTaskCompleteListener gCalTaskCompleteListener); - void inject(CalendarAlarmReceiver calendarAlarmReceiver); - void inject(RepeatTaskCompleteListener repeatTaskCompleteListener); - void inject(MyPackageReplacedReceiver myPackageReplacedReceiver); void inject(CompleteTaskReceiver completeTaskReceiver); diff --git a/app/src/main/java/org/tasks/injection/IntentServiceComponent.java b/app/src/main/java/org/tasks/injection/IntentServiceComponent.java index 88ddf8df0..3a38b362b 100644 --- a/app/src/main/java/org/tasks/injection/IntentServiceComponent.java +++ b/app/src/main/java/org/tasks/injection/IntentServiceComponent.java @@ -4,6 +4,7 @@ import org.tasks.jobs.NotificationJob; import org.tasks.jobs.BackupJob; import org.tasks.jobs.MidnightRefreshJob; import org.tasks.jobs.RefreshJob; +import org.tasks.jobs.AfterSaveIntentService; import org.tasks.location.GeofenceTransitionsIntentService; import org.tasks.scheduling.BackgroundScheduler; import org.tasks.scheduling.CalendarNotificationIntentService; @@ -31,4 +32,6 @@ public interface IntentServiceComponent { void inject(RefreshJob refreshJob); void inject(BackgroundScheduler backgroundScheduler); + + void inject(AfterSaveIntentService afterSaveIntentService); } diff --git a/app/src/main/java/org/tasks/jobs/AfterSaveIntentService.java b/app/src/main/java/org/tasks/jobs/AfterSaveIntentService.java new file mode 100644 index 000000000..d2e051832 --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/AfterSaveIntentService.java @@ -0,0 +1,135 @@ +package org.tasks.jobs; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.CalendarContract; +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.TaskApiDao; +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.injection.ForApplication; +import org.tasks.injection.InjectingJobIntentService; +import org.tasks.injection.IntentServiceComponent; +import org.tasks.location.GeofenceService; +import org.tasks.notifications.NotificationManager; +import org.tasks.receivers.PushReceiver; +import org.tasks.scheduling.RefreshScheduler; + +import javax.inject.Inject; + +import timber.log.Timber; + +import static com.todoroo.astrid.dao.TaskDao.TRANS_SUPPRESS_REFRESH; + +public class AfterSaveIntentService extends InjectingJobIntentService { + + private static final String EXTRA_TASK_ID = "extra_task_id"; + private static final String EXTRA_MODIFIED_VALUES = "extra_modified_values"; + + public static void enqueue(Context context, long taskId, ContentValues modifiedValues) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_TASK_ID, taskId); + intent.putExtra(EXTRA_MODIFIED_VALUES, modifiedValues); + AfterSaveIntentService.enqueueWork(context, AfterSaveIntentService.class, JobManager.JOB_ID_TASK_STATUS_CHANGE, intent); + } + + @Inject RepeatTaskHelper repeatTaskHelper; + @Inject @ForApplication Context context; + @Inject TaskDao taskDao; + @Inject NotificationManager notificationManager; + @Inject GeofenceService geofenceService; + @Inject TimerPlugin timerPlugin; + @Inject ReminderService reminderService; + @Inject RefreshScheduler refreshScheduler; + @Inject LocalBroadcastManager localBroadcastManager; + + @Override + protected void onHandleWork(@NonNull Intent intent) { + super.onHandleWork(intent); + + long taskId = intent.getLongExtra(EXTRA_TASK_ID, -1); + ContentValues modifiedValues = intent.getParcelableExtra(EXTRA_MODIFIED_VALUES); + + if (taskId == -1 || modifiedValues == null) { + Timber.e("Invalid extras, taskId=%s modifiedValues=%s", taskId, modifiedValues); + return; + } + + Task task = taskDao.fetch(taskId); + if (task == null) { + Timber.e("Can't find task with id %s", taskId); + return; + } + + if(modifiedValues.containsKey(Task.DUE_DATE.name) || + modifiedValues.containsKey(Task.REMINDER_FLAGS.name) || + modifiedValues.containsKey(Task.REMINDER_PERIOD.name) || + modifiedValues.containsKey(Task.REMINDER_LAST.name) || + modifiedValues.containsKey(Task.REMINDER_SNOOZE.name)) { + reminderService.scheduleAlarm(taskDao, task); + } + + if(TaskApiDao.insignificantChange(modifiedValues)) { + return; + } + + boolean completionDateModified = modifiedValues.containsKey(Task.COMPLETION_DATE.name); + boolean deletionDateModified = modifiedValues.containsKey(Task.DELETION_DATE.name); + + boolean justCompleted = completionDateModified && task.isCompleted(); + boolean justDeleted = deletionDateModified && task.isDeleted(); + + if (justCompleted || justDeleted) { + notificationManager.cancel(taskId); + geofenceService.cancelGeofences(taskId); + } else if (completionDateModified || deletionDateModified) { + geofenceService.setupGeofences(taskId); + } + + if (justCompleted) { + repeatTaskHelper.handleRepeat(task); + updateCalendarTitle(task); + if (task.getTimerStart() > 0) { + timerPlugin.stopTimer(task); + } + } + + PushReceiver.broadcast(context, task, modifiedValues); + refreshScheduler.scheduleRefresh(task); + if (!task.checkAndClearTransitory(TRANS_SUPPRESS_REFRESH)) { + localBroadcastManager.broadcastRefresh(); + } + } + + private void updateCalendarTitle(Task task) { + String calendarUri = task.getCalendarURI(); + if(!TextUtils.isEmpty(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, e.getMessage()); + } + } + } + + @Override + protected void inject(IntentServiceComponent component) { + component.inject(this); + } +} diff --git a/app/src/main/java/org/tasks/jobs/JobManager.java b/app/src/main/java/org/tasks/jobs/JobManager.java index 48b7d1309..f322242bb 100644 --- a/app/src/main/java/org/tasks/jobs/JobManager.java +++ b/app/src/main/java/org/tasks/jobs/JobManager.java @@ -26,6 +26,7 @@ public class JobManager { public static final int JOB_ID_GEOFENCE_SCHEDULING = 5; static final int JOB_ID_MIDNIGHT_REFRESH = 6; static final int JOB_ID_BACKUP = 7; + public static final int JOB_ID_TASK_STATUS_CHANGE = 8; public static final int JOB_ID_NOTIFICATION_SCHEDULER = 9; public static final int JOB_ID_CALENDAR_NOTIFICATION = 10;