From 50db04ffd69a2b5fcf51d267a5df18437babeeb5 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Wed, 28 Mar 2012 14:58:56 -0700 Subject: [PATCH 1/4] Migrate handling of due times, take two --- api/src/com/todoroo/andlib/sql/Functions.java | 14 ++++ api/src/com/todoroo/astrid/data/Task.java | 24 ++---- .../astrid/helper/DueDateTimeMigrator.java | 80 +++++++++++++++++++ .../astrid/service/UpgradeService.java | 7 ++ .../com/todoroo/astrid/ui/CalendarView.java | 6 +- .../todoroo/astrid/ui/DateAndTimePicker.java | 6 +- 6 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java diff --git a/api/src/com/todoroo/andlib/sql/Functions.java b/api/src/com/todoroo/andlib/sql/Functions.java index 9770fcfdc..a4cfc78ed 100644 --- a/api/src/com/todoroo/andlib/sql/Functions.java +++ b/api/src/com/todoroo/andlib/sql/Functions.java @@ -1,6 +1,7 @@ package com.todoroo.andlib.sql; import com.todoroo.andlib.data.Property.IntegerProperty; +import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.StringProperty; @@ -34,6 +35,18 @@ public final class Functions { return new Field("(strftime('%s','now')*1000 + " + millis + ")"); } + public static Field strftime(LongProperty field) { + return strftimeWithFormat(field, "%H:%M:%S"); + } + + public static Field strftimeWithFormat(LongProperty field, String format) { + return new Field("(strftime('" + format + "', datetime(" + field.toString() + "/1000, 'unixepoch', 'localtime')))"); + } + + public static Field strftimeSeconds(LongProperty field) { + return cast(strftimeWithFormat(field, "%S"), "LONG"); + } + public static Field cast(Field field, String newType) { return new Field("CAST(" + field.toString() + " AS " + newType + ")"); @@ -55,4 +68,5 @@ public final class Functions { return new Field(field.toString() + " & " + value); } + } diff --git a/api/src/com/todoroo/astrid/data/Task.java b/api/src/com/todoroo/astrid/data/Task.java index 777a3eafc..a677bd757 100644 --- a/api/src/com/todoroo/astrid/data/Task.java +++ b/api/src/com/todoroo/astrid/data/Task.java @@ -387,11 +387,11 @@ public final class Task extends RemoteModel { Date dueDate = new Date(date / 1000L * 1000L); // get rid of millis if(setting != URGENCY_SPECIFIC_DAY_TIME) { - dueDate.setHours(23); - dueDate.setMinutes(59); - dueDate.setSeconds(59); - } else if(isEndOfDay(dueDate)) { - dueDate.setSeconds(58); + dueDate.setHours(12); + dueDate.setMinutes(0); + dueDate.setSeconds(0); // Seconds == 0 means no due time + } else { + dueDate.setSeconds(1); // Seconds > 0 means due time exists } return dueDate.getTime(); } @@ -436,20 +436,12 @@ public final class Task extends RemoteModel { hideUntil.setHours(0); hideUntil.setMinutes(0); hideUntil.setSeconds(0); + } else { + hideUntil.setSeconds(1); } return hideUntil.getTime(); } - /** - * @return true if hours, minutes, and seconds indicate end of day - */ - private static boolean isEndOfDay(Date date) { - int hours = date.getHours(); - int minutes = date.getMinutes(); - int seconds = date.getSeconds(); - return hours == 23 && minutes == 59 && seconds == 59; - } - /** * Checks whether this due date has a due time or only a date */ @@ -463,7 +455,7 @@ public final class Task extends RemoteModel { * Checks whether provided due date has a due time or only a date */ public static boolean hasDueTime(long dueDate) { - return dueDate > 0 && !isEndOfDay(new Date(dueDate)); + return dueDate > 0 && (dueDate % 60000 > 0); } } diff --git a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java new file mode 100644 index 000000000..e4173cffe --- /dev/null +++ b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java @@ -0,0 +1,80 @@ +package com.todoroo.astrid.helper; + +import java.util.Date; + +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Functions; +import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.dao.TaskDao; +import com.todoroo.astrid.data.Task; + +public class DueDateTimeMigrator { + + @Autowired TaskDao taskDao; + + private static final String PREF_MIGRATED_DUE_TIMES = "migrated_due_times"; //$NON-NLS-1$ + private static final String LEGACY_NO_TIME_STRING = "23:59:59"; //$NON-NLS-1$ + + public DueDateTimeMigrator() { + DependencyInjectionService.getInstance().inject(this); + } + + private interface TaskDateAdjuster { + public void adjust(Date date); + } + + public void migrateDueTimes() { + if (!Preferences.getBoolean(PREF_MIGRATED_DUE_TIMES, false)) { + // Get tasks with due time (i.e. due date != 23:59:59) + TodorooCursor tasksWithSeconds = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + Criterion.and(Task.DUE_DATE.gt(0), + Criterion.not(Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING))))); + + // Set those tassk to have time HH:MM:00 + processCursor(tasksWithSeconds, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setSeconds(1); + } + }); + + // Get tasks with no due time (i.e. due date = 23:59:59) + TodorooCursor tasksWithoutDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + Criterion.and(Task.DUE_DATE.gt(0), + Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING)))); + + // Set those tasks to have time 12:00:00 + processCursor(tasksWithoutDueTime, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setHours(12); + date.setMinutes(0); + date.setSeconds(0); + } + }); + Preferences.setBoolean(PREF_MIGRATED_DUE_TIMES, true); + } + } + + private void processCursor(TodorooCursor cursor, TaskDateAdjuster adjuster) { + Task curr = new Task(); + try { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + curr.readFromCursor(cursor); + System.err.println("Processing task: " + curr.getValue(Task.TITLE) + ", ID: " + curr.getId()); + long time = curr.getValue(Task.DUE_DATE) / 1000L * 1000L; + Date date = new Date(time); + adjuster.adjust(date); + curr.setValue(Task.DUE_DATE, date.getTime()); + taskDao.save(curr); + } + } finally { + cursor.close(); + } + } + +} diff --git a/astrid/src/com/todoroo/astrid/service/UpgradeService.java b/astrid/src/com/todoroo/astrid/service/UpgradeService.java index 4c0423a04..3f1b091c5 100644 --- a/astrid/src/com/todoroo/astrid/service/UpgradeService.java +++ b/astrid/src/com/todoroo/astrid/service/UpgradeService.java @@ -31,6 +31,7 @@ import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.gtasks.GtasksPreferenceService; +import com.todoroo.astrid.helper.DueDateTimeMigrator; import com.todoroo.astrid.notes.NoteMetadata; import com.todoroo.astrid.producteev.sync.ProducteevDataService; import com.todoroo.astrid.service.abtesting.ABChooser; @@ -40,6 +41,7 @@ import com.todoroo.astrid.utility.AstridPreferences; public final class UpgradeService { + public static final int V4_0_6 = 262; public static final int V4_0_5_1 = 261; public static final int V4_0_5 = 260; public static final int V4_0_4_3 = 259; @@ -143,6 +145,10 @@ public final class UpgradeService { Preferences.setInt(AstridPreferences.P_UPGRADE_FROM, from); + // This needs to happen synchronously otherwise the tasklist will look wrong on first launch. + if (from < V4_0_6) + new DueDateTimeMigrator().migrateDueTimes(); + new Thread(new Runnable() { @Override public void run() { @@ -158,6 +164,7 @@ public final class UpgradeService { if(from < V3_8_4 && Preferences.getBoolean(R.string.p_showNotes, false)) taskService.clearDetails(Task.NOTES.neq("")); //$NON-NLS-1$ + } finally { DialogUtilities.dismissDialog((Activity)context, dialog); } diff --git a/astrid/src/com/todoroo/astrid/ui/CalendarView.java b/astrid/src/com/todoroo/astrid/ui/CalendarView.java index 190e0f0c5..e4645d5b2 100644 --- a/astrid/src/com/todoroo/astrid/ui/CalendarView.java +++ b/astrid/src/com/todoroo/astrid/ui/CalendarView.java @@ -455,9 +455,9 @@ public class CalendarView extends View { private Date getToday(Calendar calendar) { Date today = calendar.getTime(); today.setTime(today.getTime() / 1000L * 1000L); - today.setHours(23); - today.setMinutes(59); - today.setSeconds(59); + today.setHours(12); + today.setMinutes(0); + today.setSeconds(0); return today; } diff --git a/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java b/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java index 26e3999dd..fb554fdb4 100644 --- a/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java +++ b/astrid/src/com/todoroo/astrid/ui/DateAndTimePicker.java @@ -87,9 +87,9 @@ public class DateAndTimePicker extends LinearLayout { private Date getDateForCalendar(Date date) { Date forCalendar = new Date(date.getTime() / 1000L * 1000L); - forCalendar.setHours(23); - forCalendar.setMinutes(59); - forCalendar.setSeconds(59); + forCalendar.setHours(12); + forCalendar.setMinutes(0); + forCalendar.setSeconds(0); return forCalendar; } From 87971abe9c6f888e86a90a08bf0f922cfcc060de Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Wed, 28 Mar 2012 15:52:31 -0700 Subject: [PATCH 2/4] Version bump, progress dialog --- astrid/AndroidManifest.xml | 4 ++-- astrid/res/values/strings-core.xml | 3 +++ .../astrid/helper/DueDateTimeMigrator.java | 23 ++++++++++--------- .../astrid/service/UpgradeService.java | 12 ++++++---- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index b7c59eba0..b063b245f 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionName="4.0.6" + android:versionCode="262"> diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index 2ec17c321..f655864f7 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -659,6 +659,9 @@ you get stuff done. It features reminders, tags, sync, Locale plug-in, a widget Corrupted Database + + Upgrading... + Uh oh! It looks like you may have a corrupted database. If you see this error regularly, we suggest you clear all diff --git a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java index e4173cffe..28d85b8f6 100644 --- a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java +++ b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java @@ -2,6 +2,8 @@ package com.todoroo.astrid.helper; import java.util.Date; +import android.content.Context; + import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; @@ -27,27 +29,27 @@ public class DueDateTimeMigrator { public void adjust(Date date); } - public void migrateDueTimes() { + public void migrateDueTimes(Context c) { if (!Preferences.getBoolean(PREF_MIGRATED_DUE_TIMES, false)) { // Get tasks with due time (i.e. due date != 23:59:59) - TodorooCursor tasksWithSeconds = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + TodorooCursor tasksWithDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( Criterion.and(Task.DUE_DATE.gt(0), Criterion.not(Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING))))); - // Set those tassk to have time HH:MM:00 - processCursor(tasksWithSeconds, new TaskDateAdjuster() { + // Get tasks with no due time (i.e. due date = 23:59:59) + TodorooCursor tasksWithoutDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( + Criterion.and(Task.DUE_DATE.gt(0), + Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING)))); + + // Set tasks with time to have time HH:MM:01 + processCursor(tasksWithDueTime, new TaskDateAdjuster() { @Override public void adjust(Date date) { date.setSeconds(1); } }); - // Get tasks with no due time (i.e. due date = 23:59:59) - TodorooCursor tasksWithoutDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( - Criterion.and(Task.DUE_DATE.gt(0), - Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING)))); - - // Set those tasks to have time 12:00:00 + // Set tasks without time to 12:00:00 processCursor(tasksWithoutDueTime, new TaskDateAdjuster() { @Override public void adjust(Date date) { @@ -65,7 +67,6 @@ public class DueDateTimeMigrator { try { for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { curr.readFromCursor(cursor); - System.err.println("Processing task: " + curr.getValue(Task.TITLE) + ", ID: " + curr.getId()); long time = curr.getValue(Task.DUE_DATE) / 1000L * 1000L; Date date = new Date(time); adjuster.adjust(date); diff --git a/astrid/src/com/todoroo/astrid/service/UpgradeService.java b/astrid/src/com/todoroo/astrid/service/UpgradeService.java index 3f1b091c5..a6915d11a 100644 --- a/astrid/src/com/todoroo/astrid/service/UpgradeService.java +++ b/astrid/src/com/todoroo/astrid/service/UpgradeService.java @@ -9,6 +9,7 @@ import org.weloveastrid.rmilk.data.MilkNoteHelper; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -26,6 +27,7 @@ import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.activity.Eula; +import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.data.Metadata; @@ -137,7 +139,7 @@ public final class UpgradeService { // long running tasks: pop up a progress dialog final ProgressDialog dialog; - if(from < V3_0_0 && context instanceof Activity) + if(from < V4_0_6 && context instanceof Activity) dialog = DialogUtilities.progressDialog(context, context.getString(R.string.DLG_upgrading)); else @@ -145,10 +147,6 @@ public final class UpgradeService { Preferences.setInt(AstridPreferences.P_UPGRADE_FROM, from); - // This needs to happen synchronously otherwise the tasklist will look wrong on first launch. - if (from < V4_0_6) - new DueDateTimeMigrator().migrateDueTimes(); - new Thread(new Runnable() { @Override public void run() { @@ -165,8 +163,12 @@ public final class UpgradeService { if(from < V3_8_4 && Preferences.getBoolean(R.string.p_showNotes, false)) taskService.clearDetails(Task.NOTES.neq("")); //$NON-NLS-1$ + if (from < V4_0_6) + new DueDateTimeMigrator().migrateDueTimes(context); + } finally { DialogUtilities.dismissDialog((Activity)context, dialog); + context.sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); } } From 4dfc56d258c238fa1a2c50fd85470bb37bb262d4 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Wed, 28 Mar 2012 16:10:26 -0700 Subject: [PATCH 3/4] Cleanup and upgrade message started: --- astrid/res/values/strings-core.xml | 3 --- astrid/src/com/todoroo/astrid/service/UpgradeService.java | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index f655864f7..2ec17c321 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -659,9 +659,6 @@ you get stuff done. It features reminders, tags, sync, Locale plug-in, a widget Corrupted Database - - Upgrading... - Uh oh! It looks like you may have a corrupted database. If you see this error regularly, we suggest you clear all diff --git a/astrid/src/com/todoroo/astrid/service/UpgradeService.java b/astrid/src/com/todoroo/astrid/service/UpgradeService.java index a6915d11a..f27c8f56a 100644 --- a/astrid/src/com/todoroo/astrid/service/UpgradeService.java +++ b/astrid/src/com/todoroo/astrid/service/UpgradeService.java @@ -194,6 +194,10 @@ public final class UpgradeService { Preferences.clear(AstridPreferences.P_UPGRADE_FROM); StringBuilder changeLog = new StringBuilder(); + newVersionString(changeLog, "4.0.6 (3/29/12)", new String[] { + "Fixed a bug that could put duetimes on tasks when changing timezones" + }); + if (from >= V4_0_5 && from < V4_0_5_1) { newVersionString(changeLog, "4.0.5.1 (3/23/12)", new String[] { "Fixed a bug that would prevent widgets from displaying on Android 2.1" From 5d87de12d93daf6c3c329181aa2a86751fa1330c Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Wed, 28 Mar 2012 17:35:59 -0700 Subject: [PATCH 4/4] Cleanup and better code --- api/src/com/todoroo/andlib/sql/Functions.java | 10 +--- .../astrid/helper/DueDateTimeMigrator.java | 48 ++++++++++--------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/api/src/com/todoroo/andlib/sql/Functions.java b/api/src/com/todoroo/andlib/sql/Functions.java index a4cfc78ed..7a9ace07f 100644 --- a/api/src/com/todoroo/andlib/sql/Functions.java +++ b/api/src/com/todoroo/andlib/sql/Functions.java @@ -35,18 +35,10 @@ public final class Functions { return new Field("(strftime('%s','now')*1000 + " + millis + ")"); } - public static Field strftime(LongProperty field) { - return strftimeWithFormat(field, "%H:%M:%S"); - } - - public static Field strftimeWithFormat(LongProperty field, String format) { + public static Field strftime(LongProperty field, String format) { return new Field("(strftime('" + format + "', datetime(" + field.toString() + "/1000, 'unixepoch', 'localtime')))"); } - public static Field strftimeSeconds(LongProperty field) { - return cast(strftimeWithFormat(field, "%S"), "LONG"); - } - public static Field cast(Field field, String newType) { return new Field("CAST(" + field.toString() + " AS " + newType + ")"); diff --git a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java index 28d85b8f6..df1d694e1 100644 --- a/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java +++ b/astrid/src/com/todoroo/astrid/helper/DueDateTimeMigrator.java @@ -19,6 +19,7 @@ public class DueDateTimeMigrator { @Autowired TaskDao taskDao; private static final String PREF_MIGRATED_DUE_TIMES = "migrated_due_times"; //$NON-NLS-1$ + private static final String STRFTIME_FORMAT = "%H:%M%S"; //$NON-NLS-1$ private static final String LEGACY_NO_TIME_STRING = "23:59:59"; //$NON-NLS-1$ public DueDateTimeMigrator() { @@ -34,47 +35,48 @@ public class DueDateTimeMigrator { // Get tasks with due time (i.e. due date != 23:59:59) TodorooCursor tasksWithDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( Criterion.and(Task.DUE_DATE.gt(0), - Criterion.not(Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING))))); + Criterion.not(Functions.strftime(Task.DUE_DATE, STRFTIME_FORMAT).eq(LEGACY_NO_TIME_STRING))))); // Get tasks with no due time (i.e. due date = 23:59:59) TodorooCursor tasksWithoutDueTime = taskDao.query(Query.select(Task.ID, Task.TITLE, Task.DUE_DATE).where( Criterion.and(Task.DUE_DATE.gt(0), - Functions.strftime(Task.DUE_DATE).eq(LEGACY_NO_TIME_STRING)))); + Functions.strftime(Task.DUE_DATE, STRFTIME_FORMAT).eq(LEGACY_NO_TIME_STRING)))); - // Set tasks with time to have time HH:MM:01 - processCursor(tasksWithDueTime, new TaskDateAdjuster() { - @Override - public void adjust(Date date) { - date.setSeconds(1); - } - }); + try { + // Set tasks with time to have time HH:MM:01 + processCursor(tasksWithDueTime, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setSeconds(1); + } + }); - // Set tasks without time to 12:00:00 - processCursor(tasksWithoutDueTime, new TaskDateAdjuster() { - @Override - public void adjust(Date date) { - date.setHours(12); - date.setMinutes(0); - date.setSeconds(0); - } - }); + // Set tasks without time to 12:00:00 + processCursor(tasksWithoutDueTime, new TaskDateAdjuster() { + @Override + public void adjust(Date date) { + date.setHours(12); + date.setMinutes(0); + date.setSeconds(0); + } + }); + } finally { + tasksWithDueTime.close(); + tasksWithoutDueTime.close(); + } Preferences.setBoolean(PREF_MIGRATED_DUE_TIMES, true); } } private void processCursor(TodorooCursor cursor, TaskDateAdjuster adjuster) { Task curr = new Task(); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { curr.readFromCursor(cursor); long time = curr.getValue(Task.DUE_DATE) / 1000L * 1000L; Date date = new Date(time); adjuster.adjust(date); curr.setValue(Task.DUE_DATE, date.getTime()); taskDao.save(curr); - } - } finally { - cursor.close(); } }