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;