Updating reminders to use new stuff...

pull/14/head
Tim Su 14 years ago
parent acccf78cd0
commit 3cb2ed563e

@ -108,20 +108,13 @@
<!-- ======================================================= Receivers = -->
<receiver android:name=".utilities.Notifications" />
<receiver android:name="com.todoroo.astrid.reminders.Notifications" />
<receiver android:name=".utilities.LocaleReceiver">
<intent-filter>
<action android:name="com.timsu.astrid.action.LOCALE_ALERT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.service.StartupService">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".appwidget.AstridAppWidgetProvider" >
<intent-filter>
@ -175,7 +168,7 @@
</intent-filter>
</receiver>
<!-- tags filters -->
<!-- tags -->
<receiver android:name="com.todoroo.astrid.tags.TagsPlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_PLUGINS" />
@ -194,7 +187,14 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- reminders -->
<receiver android:name="com.todoroo.astrid.reminders.ReminderStartupService">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>

@ -99,6 +99,18 @@ public abstract class AbstractModel implements Parcelable {
setValues = null;
}
/**
* Transfers all set values into values. This occurs when a task is
* saved - future saves will not need to write all the data as before.
*/
public void markSaved() {
if(values == null)
values = setValues;
else if(setValues != null)
values.putAll(setValues);
setValues = null;
}
/**
* Use merged values to compare two models to each other. Must be of
* exactly the same class.

@ -79,8 +79,11 @@ public class DateUtilities {
return System.currentTimeMillis();
}
/** Represents a single hour */
public static long ONE_HOUR = 3600000L;
/** Represents a single day */
public static long ONE_DAY = 24 * 3600000L;
public static long ONE_DAY = 24 * ONE_HOUR;
/** Represents a single week */
public static long ONE_WEEK = 7 * ONE_DAY;

@ -63,8 +63,8 @@ public final class CoreFilterExposer extends BroadcastReceiver {
new QueryTemplate().where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible(DateUtilities.now()))).orderBy(
Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0),
String.format("(%d + 1000 * %s)", DateUtilities.now(), Task.IMPORTANCE),
String.format("(%s + 1000 * %s)", Task.DUE_DATE, Task.IMPORTANCE)))),
String.format("(%d + 1000000 * %s)", DateUtilities.now(), Task.IMPORTANCE),
String.format("(%s + 1000000 * %s)", Task.DUE_DATE, Task.IMPORTANCE)))),
null);
inbox.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_inbox)).getBitmap();
return inbox;

@ -1,12 +1,9 @@
package com.timsu.astrid.utilities;
package com.todoroo.astrid.reminders;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Set;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -22,17 +19,16 @@ import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.activities.TaskListNotify;
import com.timsu.astrid.activities.TaskListSubActivity;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForList;
import com.timsu.astrid.data.task.TaskModelForNotify;
import com.timsu.astrid.data.task.TaskModelForReminder;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.Preferences;
public class Notifications extends BroadcastReceiver {
private static final String ID_KEY = "id";
private static final String FLAGS_KEY = "flags";
static final String ID_KEY = "id";
static final String TYPE_KEY = "flags";
private static final String REPEAT_KEY = "repeat";
private static final int TAG_ID_OFFSET = 100000;
@ -97,232 +93,7 @@ public class Notifications extends BroadcastReceiver {
// --- alarm manager stuff
private static boolean shouldDeleteAlarm(Notifiable task) {
if(task.isTaskCompleted())
return true;
return false;
}
public static void scheduleAllAlarms(Context context) {
try {
TaskController taskController = new TaskController(context);
taskController.open();
AlertController alertController = new AlertController(context);
alertController.open();
Set<TaskModelForNotify> tasks = taskController.getTasksWithNotifications();
Set<TaskIdentifier> tasksWithAlerts = alertController.getTasksWithActiveAlerts();
for(TaskIdentifier taskId : tasksWithAlerts) {
try {
tasks.add(taskController.fetchTaskForNotify(taskId));
} catch (Exception e) {
// task was deleted or something
}
}
for(TaskModelForNotify task : tasks)
updateAlarm(context, taskController, alertController, task);
alertController.close();
taskController.close();
} catch (Exception e) {
Log.e("astrid", "Error scheduling alarms", e);
}
}
/** Schedules the next notification for this task */
public static void updateAlarm(Context context, TaskController taskController,
AlertController alertController, Notifiable task) {
if(task.getTaskIdentifier() == null)
return;
// return if we don't need to go any further
if(shouldDeleteAlarm(task)) {
deleteAlarm(context, null, task.getTaskIdentifier().getId());
return;
}
// periodic reminders
if(task.getNotificationIntervalSeconds() > 0) {
long interval = task.getNotificationIntervalSeconds() * 1000;
long when;
// get or make up a last notification time
if(task.getLastNotificationDate() == null) {
when = System.currentTimeMillis() -
(long)(interval * (0.7f * random.nextFloat()));
taskController.setLastNotificationTime(task.getTaskIdentifier(),
new Date(when));
} else {
when = task.getLastNotificationDate().getTime();
}
if(when < System.currentTimeMillis())
when += ((System.currentTimeMillis() - when)/interval + 1) * interval;
scheduleRepeatingAlarm(context, task.getTaskIdentifier().getId(),
when, FLAG_PERIODIC, interval);
}
// notifications at deadlines
int estimatedDuration = DEADLINE_NOTIFY_SECS;
if(task.getEstimatedSeconds() != null && task.getEstimatedSeconds() > DEADLINE_NOTIFY_SECS)
estimatedDuration = (int)(task.getEstimatedSeconds() * 1.5f);
// we need to clear all alarms in case users removed a deadline
clearAlarm(context, task.getTaskIdentifier().getId(), FLAG_DEFINITE_DEADLINE);
clearAlarm(context, task.getTaskIdentifier().getId(), FLAG_PREFERRED_DEADLINE);
clearAlarm(context, task.getTaskIdentifier().getId(), FLAG_DEFINITE_DEADLINE | FLAG_OVERDUE);
clearAlarm(context, task.getTaskIdentifier().getId(), FLAG_PREFERRED_DEADLINE | FLAG_OVERDUE);
// before, during, and after deadlines
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_BEFORE_DEADLINE) > 0) {
scheduleDeadline(context, task.getDefiniteDueDate(), -estimatedDuration,
0, FLAG_DEFINITE_DEADLINE, task);
scheduleDeadline(context, task.getPreferredDueDate(), -estimatedDuration,
0, FLAG_PREFERRED_DEADLINE, task);
}
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_AT_DEADLINE) > 0) {
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_AFTER_DEADLINE) == 0)
scheduleDeadline(context, task.getDefiniteDueDate(), 0,
0, FLAG_DEFINITE_DEADLINE | FLAG_OVERDUE, task);
scheduleDeadline(context, task.getPreferredDueDate(), 0,
0, FLAG_PREFERRED_DEADLINE | FLAG_OVERDUE, task);
}
if((task.getNotificationFlags() & TaskModelForList.NOTIFY_AFTER_DEADLINE) > 0) {
scheduleDeadline(context, task.getDefiniteDueDate(), 0,
DEADLINE_REPEAT, FLAG_DEFINITE_DEADLINE | FLAG_OVERDUE, task);
}
// fixed alerts
List<Date> alerts = alertController.getTaskAlerts(task.getTaskIdentifier());
scheduleFixedAlerts(context, task.getTaskIdentifier(), alerts);
}
/** Schedule a list of alerts for a task */
public static void scheduleFixedAlerts(Context context, TaskIdentifier taskId,
List<Date> alerts) {
int alertId = 0;
Date currentDate = new Date();
for(Date alert : alerts) {
if(alert.before(currentDate))
continue;
scheduleAlarm(context, taskId.getId(),
alert.getTime(), FLAG_FIXED | (alertId++ << FIXED_ID_SHIFT));
}
}
/** Schedule an alert around a deadline
*
* @param context
* @param deadline The deadline date. If null, does nothing.
* @param offsetSeconds Offset from deadline to schedule
* @param intervalSeconds How often to repeat, or zero
* @param flags Flags for the alarm
* @param task
*/
private static void scheduleDeadline(Context context, Date deadline, int
offsetSeconds, int intervalSeconds, int flags, Notifiable task) {
long id = task.getTaskIdentifier().getId();
if(deadline == null)
return;
long when = deadline.getTime() + offsetSeconds * 1000;
if(when < System.currentTimeMillis() && intervalSeconds == 0)
return;
if (intervalSeconds == 0)
scheduleAlarm(context, id, when,
flags);
else
scheduleRepeatingAlarm(context, id,
when, flags, intervalSeconds * 1000);
}
/** Create a 'snooze' reminder for this task */
public static void createSnoozeAlarm(Context context, TaskIdentifier id,
int secondsToSnooze, int flags, long repeatInterval) {
// if this is a one-off alarm, just schedule a snooze-type alarm
if(repeatInterval == 0)
scheduleAlarm(context, id.getId(), System.currentTimeMillis() +
secondsToSnooze * 1000, FLAG_SNOOZE);
// else, reschedule our normal alarm
else
scheduleRepeatingAlarm(context, id.getId(), System.currentTimeMillis() +
secondsToSnooze * 1000, flags, repeatInterval);
}
/** Helper method to create a Intent for alarm from an ID & flags */
private static Intent createAlarmIntent(Context context, long id, int flags) {
Intent intent = new Intent(context, Notifications.class);
intent.setType(Long.toString(id));
intent.setAction(Integer.toString(flags));
intent.putExtra(ID_KEY, id);
intent.putExtra(FLAGS_KEY, flags);
return intent;
}
/** Delete the given alarm */
public static void deleteAlarm(Context context, Intent trigger, long id) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
if(trigger != null) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
trigger, 0);
am.cancel(pendingIntent);
}
// clear current notifications too
clearAllNotifications(context, new TaskIdentifier(id));
}
/** Clear the alarm given by the id and flags */
public static void clearAlarm(Context context, long id, int flags) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
createAlarmIntent(context, id, flags), 0);
am.cancel(pendingIntent);
}
/** Schedules a single alarm for a single task */
public static void scheduleAlarm(Context context, long id, long when,
int flags) {
// if alarm occurs in the past, don't trigger it
if(when < System.currentTimeMillis())
return;
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
createAlarmIntent(context, id, flags), 0);
if(Constants.DEBUG)
Log.e("Astrid", "Alarm (" + id + ", " + flags + ") set for " + new Date(when));
am.set(AlarmManager.RTC_WAKEUP, when, pendingIntent);
}
/** Schedules a recurring alarm for a single task */
public static void scheduleRepeatingAlarm(Context context, long id, long when,
int flags, long interval) {
// if alarm occurs in the past, trigger it in the future
if(when < System.currentTimeMillis())
when = (long)(System.currentTimeMillis() + when * (0.8 + 0.3 * random.nextDouble()));
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = createAlarmIntent(context, id, flags);
alarmIntent.putExtra(REPEAT_KEY, interval);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
alarmIntent, 0);
if(Constants.DEBUG)
Log.e("Astrid", "Alarm (" + id + ", " + flags + ") set for " +
new Date(when) + " every " + interval/1000 + " s");
am.setRepeating(AlarmManager.RTC_WAKEUP, when, interval, pendingIntent);
}
// --- notification manager stuff

@ -0,0 +1,249 @@
package com.todoroo.astrid.reminders;
import java.util.Date;
import java.util.Random;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.Constants;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.utility.Preferences;
/**
* Data service for reminders
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class ReminderService {
// --- constants
private static final Property<?>[] PROPERTIES = new Property<?>[] {
Task.DUE_DATE,
Task.REMINDER_FLAGS,
Task.REMINDER_PERIOD,
Task.REMINDER_LAST
};
/** flag for due date reminder */
static final byte TYPE_DUE = 0;
/** flag for overdue reminder */
static final byte TYPE_OVERDUE = 1;
/** flag for random reminder */
static final byte TYPE_RANDOM = 2;
/** flag for a snoozed reminder */
static final byte TYPE_SNOOZE = 3;
// --- instance variables
@Autowired
private TaskDao taskDao;
private static final Random random = new Random();
public ReminderService() {
DependencyInjectionService.getInstance().inject(this);
}
// --- reminder scheduling logic
/**
* Schedules all alarms
*/
public void scheduleAllAlarms() {
TodorooCursor<Task> cursor = getTasksWithReminders(PROPERTIES);
try {
Task task = new Task();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
task.readFromCursor(cursor);
scheduleAlarm(task, false);
}
} finally {
cursor.close();
}
}
private static final long NO_ALARM = Long.MAX_VALUE;
/**
* Schedules alarms for a single task
* @param task
*/
public void scheduleAlarm(Task task) {
scheduleAlarm(task, true);
}
/**
* Schedules alarms for a single task
*
* @param shouldPerformPropertyCheck
* whether to check if task has requisite properties
*/
private void scheduleAlarm(Task task, boolean shouldPerformPropertyCheck) {
if(!task.isSaved())
return;
// read data if necessary
if(shouldPerformPropertyCheck) {
for(Property<?> property : PROPERTIES) {
if(!task.containsValue(property)) {
task = taskDao.fetch(task.getId(), PROPERTIES);
break;
}
}
}
// random reminders
long whenRandom = calculateNextRandomReminder(task);
// notifications at due date
long whenDueDate = calculateNextDueDateReminder(task);
// notifications after due date
long whenOverdue = calculateNextOverdueReminder(task);
if(whenRandom < whenDueDate && whenRandom < whenOverdue)
createAlarm(task, whenRandom, TYPE_RANDOM);
else if(whenDueDate < whenOverdue)
createAlarm(task, whenDueDate, TYPE_DUE);
else if(whenOverdue != NO_ALARM)
createAlarm(task, whenOverdue, TYPE_OVERDUE);
}
/**
* Calculate the next alarm time for overdue reminders. If the due date
* has passed, we schedule a reminder some time in the next 4 - 24 hours.
*
* @param task
* @return
*/
private long calculateNextOverdueReminder(Task task) {
if(task.hasDueDate() && task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_AFTER_DEADLINE)) {
long dueDate = task.getValue(Task.DUE_DATE);
if(dueDate > DateUtilities.now())
return NO_ALARM;
return DateUtilities.now() + (long)((4 + 20 * random.nextFloat()) * DateUtilities.ONE_HOUR);
}
return NO_ALARM;
}
/**
* Calculate the next alarm time for due date reminders. If the due date
* has not already passed, we return the due date, altering the time
* if the date was indicated to not have a due time
*
* @param task
* @return
*/
private long calculateNextDueDateReminder(Task task) {
if(task.hasDueDate() && task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_AT_DEADLINE)) {
long dueDate = task.getValue(Task.DUE_DATE);
if(dueDate < DateUtilities.now())
return NO_ALARM;
else if(task.hasDueTime())
// return due date straight up
return dueDate;
else {
// return notification time on this day
Date date = new Date(dueDate);
date.setHours(Preferences.getIntegerFromString(R.string.p_reminder_time));
date.setMinutes(0);
return date.getTime();
}
}
return NO_ALARM;
}
/**
* Calculate the next alarm time for random reminders. We take the last
* random reminder time and add approximately the reminder period, until
* we get a time that's in the future.
*
* @param task
* @return
*/
private long calculateNextRandomReminder(Task task) {
long reminderPeriod = task.getValue(Task.REMINDER_PERIOD);
if((reminderPeriod) > 0) {
long when = task.getValue(Task.REMINDER_LAST);
// get or make up a last notification time
if(when == 0) {
when = DateUtilities.now();
task.setValue(Task.REMINDER_LAST, when);
taskDao.save(task, false);
}
when += (long)(reminderPeriod * (0.85f + 0.3f * random.nextFloat()));
return when;
}
return NO_ALARM;
}
// --- alarm manager alarm creation
/**
* Create an alarm for the given task at the given type
*
* @param task
* @param time
* @param type
* @param flags
*/
@SuppressWarnings("nls")
static void createAlarm(Task task, long time, byte type) {
if(time == 0 || time == NO_ALARM)
return;
if(time < DateUtilities.now()) {
time = DateUtilities.now() + (long)((0.5f +
4 * random.nextFloat()) * DateUtilities.ONE_HOUR);
}
Context context = ContextManager.getContext();
Intent intent = new Intent(context, Notifications.class);
intent.setType(Long.toString(task.getId()));
intent.setAction(Integer.toString(type));
intent.putExtra(Notifications.ID_KEY, task.getId());
intent.putExtra(Notifications.TYPE_KEY, type);
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intent, 0);
if(Constants.DEBUG)
Log.e("Astrid", "Alarm (" + task.getId() + ", " + type + ") set for " + new Date(time));
am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
// --- data fetching classes
/**
* Gets a listing of all tasks that are active &
* @param properties
* @return todoroo cursor. PLEASE CLOSE THIS CURSOR!
*/
public TodorooCursor<Task> getTasksWithReminders(Property<?>... properties) {
return taskDao.query(Query.select(properties).where(Criterion.and(TaskCriteria.isActive(),
Task.REMINDER_FLAGS.gt(0))));
}
}

@ -0,0 +1,30 @@
package com.todoroo.astrid.reminders;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.astrid.service.AstridDependencyInjector;
/**
* Service which handles jobs that need to be run when phone boots
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class ReminderStartupService extends BroadcastReceiver {
static {
AstridDependencyInjector.initialize();
}
// --- system startup
@Override
/** Called when the system is started up */
public void onReceive(Context context, Intent intent) {
ContextManager.setContext(context);
new ReminderService().scheduleAllAlarms();
}
}

@ -118,16 +118,6 @@
<item>Next Month</item>
</string-array>
<string-array name="EPr_default_urgency_values">
<!-- urgency: labels that map EPr_default_urgency items to index in TEA_urgency. -->
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</string-array>
<string-array name="notif_icon_entries">
<!-- Icons for notification tray -->
<item>Pink</item>

@ -1,168 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ASTRID: Android's Simple Task Recording Dashboard
Copyright (c) 2009 Tim Su
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
<!--
This file contains preference keys and preference list values.
These should not be translated
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- This file contains preference keys and prefereyce list values.
These should not be translated -->
<string name="p_sync_rtm">sync_rtm</string>
<string name="p_sync_every_old">sync_every</string> <!-- old sync key -->
<string name="p_sync_interval">sync_freq</string>
<string name="p_sync_button">sync_button</string>
<string name="p_sync_quiet">sync_dialogs</string>
<string name="p_sync_bgwifi">sync_bgwifi</string>
<string name="p_notif_quietStart">notif_qstart</string>
<string name="p_notif_quietEnd">notif_qend</string>
<string name="p_notif_defaultRemind">notif_default_reminder</string>
<string name="p_notif_annoy">notif_annoy</string>
<string name="p_notif_vibrate">notif_vibrate</string>
<string name="p_notification_ringtone">notification_ringtone</string>
<string name="p_notif_icon">notif_theme</string>
<string name="p_colorize">colorize</string>
<string name="p_fontSize">font_size</string>
<string name="p_nagging">nagging</string>
<string name="p_deadlineTime">deadline_time</string>
<string name="p_backup">backup</string>
<string name="prefs_defaultCalendar">default_calendar_id</string>
<string name="prefs_defaultCalendar_default">1</string>
<string name="prefs_titleVisible">titleVisible</string>
<string name="prefs_titleVisible_default">true</string>
<string name="prefs_deadlineVisible">deadlineVisible</string>
<string name="prefs_deadlineVisible_default">true</string>
<string name="prefs_timeVisible">timeVisible</string>
<string name="prefs_timeVisible_default">true</string>
<string name="prefs_importanceVisible">importanceVisible</string>
<string name="prefs_importanceVisible_default">true</string>
<string name="prefs_tagsVisible">tagsVisible</string>
<string name="prefs_tagsVisible_default">true</string>
<string name="prefs_repeatVisible">repeatVisible</string>
<string name="prefs_repeatVisible_default">true</string>
<string name="prefs_reminderVisible">reminderVisible</string>
<string name="prefs_reminderVisible_default">false</string>
<string name="prefs_notesVisible">notesVisible</string>
<string name="prefs_notesVisible_default">false</string>
<string-array name="notif_icon_values">
<!-- Corresponding to the constants in Preferences.java (do not edit) -->
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array name="sync_interval_values">
<!-- sync_interval_values: interval in seconds for sync entries (do not edit) -->
<item>0</item>
<item>1800</item>
<item>3600</item>
<item>43200</item>
<item>86400</item>
<item>302400</item>
<item>604800</item>
</string-array>
<string-array name="EPr_quiet_hours_start_values">
<!-- quiet_hours_start_values: 24-hour representation of quiet_hour_start -->
<item></item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>00</item>
<item>01</item>
<item>02</item>
<item>03</item>
<item>04</item>
<item>05</item>
<item>06</item>
<item>07</item>
<item>08</item>
<item>09</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
</string-array>
<string-array name="EPr_quiet_hours_end_values">
<!-- quiet_hours_end_values: 24-hour representation of quiet_hours_end -->
<item>09</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>00</item>
<item>01</item>
<item>02</item>
<item>03</item>
<item>04</item>
<item>05</item>
<item>06</item>
<item>07</item>
<item>08</item>
</string-array>
<string-array name="EPr_font_size">
<!-- font_size: options for preference menu -->
<item>14</item>
<item>16</item>
<item>18</item>
<item>20</item>
<item>22</item>
<item>24</item>
<item>26</item>
<item>28</item>
<item>30</item>
<item>32</item>
<item>36</item>
<item>48</item>
</string-array>
<!-- ============================================================= SYNC == -->
<!-- sync -->
<string name="p_sync_rtm">sync_rtm</string>
<string name="p_sync_interval">sync_freq</string>
<string name="p_sync_button">sync_button</string>
<string name="p_sync_quiet">sync_dialogs</string>
<string name="p_sync_bgwifi">sync_bgwifi</string>
<string-array name="sync_interval_values">
<!-- sync_interval_values: interval in seconds for sync entries (do not edit) -->
<item>0</item>
<item>1800</item>
<item>3600</item>
<item>43200</item>
<item>86400</item>
<item>302400</item>
<item>604800</item>
</string-array>
<!-- ======================================================== REMINDERS == -->
<!-- hour to start quiet hours (inclusive) -->
<string name="p_notif_quietStart">notif_qstart</string>
<!-- hour to end quiet hours (non-inclusive) -->
<string name="p_notif_quietEnd">notif_qend</string>
<!-- whether "clear all notifications" clears astrid notifications -->
<string name="p_notif_annoy">notif_annoy</string>
<!-- whether to vibrate phone when reminder fires -->
<string name="p_notif_vibrate">notif_vibrate</string>
<!-- ringtone to use for notifications -->
<string name="p_notification_ringtone">notification_ringtone</string>
<!-- icon theme for notifications -->
<string name="p_notif_icon">notif_theme</string>
<!-- whether astrid nag messages are used -->
<string name="p_nagging">nagging</string>
<!-- reminder time when task doesn't have a due time -->
<string name="p_reminder_time">reminder_time</string>
<!-- default random reminder setting -->
<string name="p_default_reminder_random">notif_default_reminder</string>
<string-array name="notif_icon_values">
<!-- Corresponding to the constants in Preferences.java (do not edit) -->
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array name="EPr_quiet_hours_start_values">
<!-- quiet_hours_start_values: 24-hour representation of quiet_hour_start -->
<item></item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>00</item>
<item>01</item>
<item>02</item>
<item>03</item>
<item>04</item>
<item>05</item>
<item>06</item>
<item>07</item>
<item>08</item>
<item>09</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
</string-array>
<string-array name="EPr_quiet_hours_end_values">
<!-- quiet_hours_end_values: 24-hour representation of quiet_hours_end -->
<item>09</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>00</item>
<item>01</item>
<item>02</item>
<item>03</item>
<item>04</item>
<item>05</item>
<item>06</item>
<item>07</item>
<item>08</item>
</string-array>
<!-- ======================================================= APPEARANCE == -->
<string name="p_colorize">colorize</string>
<string name="p_fontSize">font_size</string>
<string-array name="EPr_font_size">
<!-- font_size: options for preference menu -->
<item>14</item>
<item>16</item>
<item>18</item>
<item>20</item>
<item>22</item>
<item>24</item>
<item>26</item>
<item>28</item>
<item>30</item>
<item>32</item>
<item>36</item>
<item>48</item>
</string-array>
<!-- ========================================================= DEFAULTS == -->
<!-- default urgency setting (corresponds to entry in TEA_urgency) -->
<string name="p_default_urgency_key">p_def_urg</string>
<!-- urgency: labels that map EPr_default_urgency items to index in TEA_urgency. -->
<string-array name="p_default_urgency_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</string-array>
<!-- default importance setting (corresponds to task setting) -->
<string name="p_default_importance_key">p_def_imp</string>
<!-- ============================================================ OTHER == -->
<string name="p_backup">backup</string>
<string name="prefs_defaultCalendar">default_calendar_id</string>
<string name="prefs_defaultCalendar_default">1</string>
</resources>

@ -398,14 +398,10 @@ If you don\'t want to see the new task right after you complete the old one, you
<string name="EPr_default_urgency_title">Default Urgency</string>
<!-- Default Urgency Description (%s => setting) -->
<string name="EPr_default_urgency_desc">Currently Set To: %s</string>
<!-- Preference Key (do not translate) -->
<string name="EPr_default_urgency_key">p_durg</string>
<!-- Default Importance Title -->
<string name="EPr_default_importance_title">Default Importance</string>
<!-- Default Importance Description (%s => setting) -->
<string name="EPr_default_importance_desc">Currently Set To: %s</string>
<!-- Preference Key (do not translate) -->
<string name="EPr_default_importance_key">p_dimp</string>
</resources>

@ -2,48 +2,6 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/prefs_category_alerts">
<ListPreference
android:key="@string/p_notif_quietStart"
android:entries="@array/EPr_quiet_hours_start"
android:entryValues="@array/EPr_quiet_hours_start_values"
android:title="@string/prefs_quietStart_title"
android:summary="@string/prefs_quietStart_desc" />
<ListPreference
android:key="@string/p_notif_quietEnd"
android:entries="@array/EPr_quiet_hours_end"
android:entryValues="@array/EPr_quiet_hours_end_values"
android:title="@string/prefs_quietEnd_title"
android:summary="@string/prefs_quietEnd_desc" />
<CheckBoxPreference
android:key="@string/p_notif_annoy"
android:title="@string/prefs_annoy_title"
android:summary="@string/prefs_annoy_desc" />
<CheckBoxPreference
android:key="@string/p_notif_vibrate"
android:title="@string/prefs_vibrate_title"
android:summary="@string/prefs_vibrate_desc" />
<EditTextPreference
android:key="@string/p_notif_defaultRemind"
android:title="@string/prefs_defaultRemind_title"
android:summary="@string/prefs_defaultRemind_desc" />
<RingtonePreference
android:key="@string/p_notification_ringtone"
android:title="@string/prefs_notification_title"
android:summary="@string/prefs_notification_desc"
android:ringtoneType="notification"
android:showDefault="true"
android:showSilent="true" />
<ListPreference
android:key="@string/p_notif_icon"
android:entries="@array/notif_icon_entries"
android:entryValues="@array/notif_icon_values"
android:title="@string/prefs_notificon_title"
android:summary="@string/prefs_notificon_desc" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/prefs_category_appearance">
<CheckBoxPreference
@ -56,45 +14,6 @@
android:entryValues="@array/EPr_font_size"
android:title="@string/prefs_fontSize_title"
android:summary="@string/prefs_fontSize_desc" />
<PreferenceScreen
android:title="@string/displayedFields_PrefScreen_Title"
android:summary="@string/displayedFields_PrefScreen_Desc">
<CheckBoxPreference
android:key="@string/prefs_deadlineVisible"
android:title="@string/prefs_deadlineVisible_title"
android:summary="@string/prefs_deadlineVisible_desc"
android:defaultValue="@string/prefs_deadlineVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_tagsVisible"
android:title="@string/prefs_tagsVisible_title"
android:summary="@string/prefs_tagsVisible_desc"
android:defaultValue="@string/prefs_tagsVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_importanceVisible"
android:title="@string/prefs_importanceVisible_title"
android:summary="@string/prefs_importanceVisible_desc"
android:defaultValue="@string/prefs_importanceVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_timeVisible"
android:title="@string/prefs_timeVisible_title"
android:summary="@string/prefs_timeVisible_desc"
android:defaultValue="@string/prefs_timeVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_reminderVisible"
android:title="@string/prefs_reminderVisible_title"
android:summary="@string/prefs_reminderVisible_desc"
android:defaultValue="@string/prefs_reminderVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_repeatVisible"
android:title="@string/prefs_repeatVisible_title"
android:summary="@string/prefs_repeatVisible_desc"
android:defaultValue="@string/prefs_repeatVisible_default" />
<CheckBoxPreference
android:key="@string/prefs_notesVisible"
android:title="@string/prefs_notesVisible_title"
android:summary="@string/prefs_notesVisible_desc"
android:defaultValue="@string/prefs_notesVisible_default" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory
@ -104,10 +23,6 @@
android:title="@string/prefs_nagging_title"
android:summary="@string/prefs_nagging_desc"
android:defaultValue="true" />
<EditTextPreference
android:key="@string/p_deadlineTime"
android:title="@string/prefs_deadlineTime_title"
android:summary="@string/prefs_deadlineTime_desc" />
<CheckBoxPreference
android:key="@string/p_backup"
android:title="@string/prefs_backup_title"

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/prefs_category_alerts">
<ListPreference
android:key="@string/p_notif_quietStart"
android:entries="@array/EPr_quiet_hours_start"
android:entryValues="@array/EPr_quiet_hours_start_values"
android:title="@string/prefs_quietStart_title"
android:summary="@string/prefs_quietStart_desc" />
<ListPreference
android:key="@string/p_notif_quietEnd"
android:entries="@array/EPr_quiet_hours_end"
android:entryValues="@array/EPr_quiet_hours_end_values"
android:title="@string/prefs_quietEnd_title"
android:summary="@string/prefs_quietEnd_desc" />
<CheckBoxPreference
android:key="@string/p_notif_annoy"
android:title="@string/prefs_annoy_title"
android:summary="@string/prefs_annoy_desc" />
<CheckBoxPreference
android:key="@string/p_notif_vibrate"
android:title="@string/prefs_vibrate_title"
android:summary="@string/prefs_vibrate_desc" />
<EditTextPreference
android:key="@string/p_default_reminder_random"
android:title="@string/prefs_defaultRemind_title"
android:summary="@string/prefs_defaultRemind_desc" />
<RingtonePreference
android:key="@string/p_notification_ringtone"
android:title="@string/prefs_notification_title"
android:summary="@string/prefs_notification_desc"
android:ringtoneType="notification"
android:showDefault="true"
android:showSilent="true" />
<ListPreference
android:key="@string/p_notif_icon"
android:entries="@array/notif_icon_entries"
android:entryValues="@array/notif_icon_values"
android:title="@string/prefs_notificon_title"
android:summary="@string/prefs_notificon_desc" />
</PreferenceScreen>

@ -44,8 +44,8 @@ import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.sync.Synchronizer;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.StartupReceiver;
import com.timsu.astrid.utilities.AstridUtilities.AstridUncaughtExceptionHandler;
import com.todoroo.astrid.reminders.StartupReceiver;
/**
* TaskList is the main launched activity for Astrid. It uses a ViewFlipper

@ -74,7 +74,6 @@ import com.timsu.astrid.sync.Synchronizer.SynchronizerListener;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Notifications;
import com.timsu.astrid.utilities.Preferences;
import com.timsu.astrid.utilities.TasksXmlExporter;
import com.timsu.astrid.utilities.TasksXmlImporter;
@ -84,6 +83,7 @@ import com.timsu.astrid.widget.NumberPickerDialog;
import com.timsu.astrid.widget.NNumberPickerDialog.OnNNumberPickedListener;
import com.timsu.astrid.widget.NumberPickerDialog.OnNumberPickedListener;
import com.todoroo.astrid.activity.TaskEditActivity;
import com.todoroo.astrid.reminders.ReminderService;
/**
* Primary view for the Astrid Application. Lists all of the tasks in the
@ -463,7 +463,7 @@ public class TaskListSubActivity extends SubActivity {
Resources r = getResources();
// clear notifications
Notifications.clearAllNotifications(getParent(), task
ReminderService.clearAllNotifications(getParent(), task
.getTaskIdentifier());
String[] strings = new String[] {
@ -541,7 +541,7 @@ public class TaskListSubActivity extends SubActivity {
R.string.notify_snooze_title), new OnNNumberPickedListener() {
public void onNumbersPicked(int[] values) {
int snoozeSeconds = values[0] * 3600 + values[1] * 60;
Notifications.createSnoozeAlarm(getParent(), task
ReminderService.createSnoozeAlarm(getParent(), task
.getTaskIdentifier(), snoozeSeconds, flags,
repeatInterval);

@ -46,7 +46,7 @@ import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.provider.TasksProvider;
import com.timsu.astrid.sync.Synchronizer;
import com.timsu.astrid.sync.Synchronizer.SynchronizerListener;
import com.timsu.astrid.utilities.Notifications;
import com.todoroo.astrid.reminders.ReminderService;
/**
* Controller for task-related operations
@ -308,10 +308,10 @@ public class TaskController extends AbstractController {
if(values.containsKey(AbstractTaskModel.TIMER_START)) {
// show notification bar if timer was started
if(values.getAsLong(AbstractTaskModel.TIMER_START) != 0) {
Notifications.showTimingNotification(context,
ReminderService.showTimingNotification(context,
task.getTaskIdentifier(), task.getName());
} else {
Notifications.clearAllNotifications(context, task.getTaskIdentifier());
ReminderService.clearAllNotifications(context, task.getTaskIdentifier());
}
}
@ -390,7 +390,7 @@ public class TaskController extends AbstractController {
/** Clean up state from a task. Called when deleting or completing it */
private void cleanupTask(TaskIdentifier taskId, boolean isRepeating) {
// delete notifications & alarms
Notifications.deleteAlarm(context, null, taskId.getId());
ReminderService.deleteAlarm(context, null, taskId.getId());
// delete calendar event if not repeating
if(!isRepeating) {
@ -578,7 +578,7 @@ public class TaskController extends AbstractController {
TaskModelForNotify task = fetchTaskForNotify(taskId);
AlertController alertController = new AlertController(context);
alertController.open();
Notifications.updateAlarm(context, this, alertController, task);
ReminderService.updateAlarm(context, this, alertController, task);
alertController.close();
}

@ -24,7 +24,7 @@ import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.utilities.Notifications.Notifiable;
import com.todoroo.astrid.reminders.ReminderService.Notifiable;

@ -28,8 +28,8 @@ import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.AlertController;
import com.timsu.astrid.utilities.Notifications;
import com.timsu.astrid.utilities.Notifications.Notifiable;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.reminders.ReminderService.Notifiable;
@ -92,7 +92,7 @@ public class TaskModelForHandlers extends AbstractTaskModel implements Notifiabl
// reset periodic alerts
setLastNotificationTime(null);
Notifications.updateAlarm(context, taskController, alertController, this);
ReminderService.updateAlarm(context, taskController, alertController, this);
alertController.close();
}

@ -24,7 +24,7 @@ import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.utilities.Notifications.Notifiable;
import com.todoroo.astrid.reminders.ReminderService.Notifiable;

@ -25,7 +25,7 @@ import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.enums.Importance;
import com.timsu.astrid.utilities.Notifications.Notifiable;
import com.todoroo.astrid.reminders.ReminderService.Notifiable;

@ -47,8 +47,8 @@ import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForSync;
import com.timsu.astrid.utilities.AstridUtilities;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Notifications;
import com.timsu.astrid.utilities.Preferences;
import com.todoroo.astrid.reminders.ReminderService;
/** A service that synchronizes with Astrid
*
@ -478,7 +478,7 @@ public abstract class SynchronizationProvider {
stats.localCreatedTasks++;
}
Notifications.updateAlarm(context, taskController, alertController,
ReminderService.updateAlarm(context, taskController, alertController,
task);
postUpdate(new ProgressUpdater(stats.localUpdatedTasks,
remoteTasks.size()));

@ -16,6 +16,7 @@ import com.timsu.astrid.data.tag.TagController;
import com.timsu.astrid.data.tag.TagIdentifier;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.todoroo.astrid.reminders.ReminderService;
/**
* Receiver is activated when Locale conditions are triggered
@ -63,7 +64,7 @@ public class LocaleReceiver extends BroadcastReceiver {
String reminder = r.getString(R.string.notif_tagNotification).
replace("$NUM", r.getQuantityString(R.plurals.Ntasks, count, count)).
replace("$TAG", tagName);
Notifications.showTagNotification(context, tagId, reminder);
ReminderService.showTagNotification(context, tagId, reminder);
Preferences.setLocaleLastAlertTime(context, tagId,
System.currentTimeMillis());

@ -1,154 +0,0 @@
package com.timsu.astrid.utilities;
import java.util.List;
import android.Manifest;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.timsu.astrid.R;
import com.timsu.astrid.activities.SyncPreferences;
import com.timsu.astrid.appwidget.AstridAppWidgetProvider.UpdateService;
import com.timsu.astrid.sync.SynchronizationService;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.UpgradeService;
public class StartupReceiver extends BroadcastReceiver {
private static boolean hasStartedUp = false;
static {
AstridDependencyInjector.initialize();
}
@Override
/** Called when the system is started up */
public void onReceive(Context context, Intent intent) {
ContextManager.setContext(context);
Notifications.scheduleAllAlarms(context);
}
/** Called when this application is started up */
public static void onStartupApplication(final Context context) {
if(hasStartedUp)
return;
ContextManager.setContext(context);
int latestSetVersion = Preferences.getCurrentVersion(context);
int version = 0;
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo("com.timsu.astrid", 0);
version = pi.versionCode;
} catch (Exception e) {
Log.e("StartupAstrid", "Error getting version!", e);
}
// if we just got upgraded, set the alarms
boolean justUpgraded = latestSetVersion != version;
final int finalVersion = version;
if(justUpgraded) {
// perform version-specific processing
if(latestSetVersion <= 99) {
if(Preferences.getSyncOldAutoSyncFrequency(context) != null) {
float value = Preferences.getSyncOldAutoSyncFrequency(context);
Preferences.setSyncAutoSyncFrequency(context,
Math.round(value * 3600));
DialogUtilities.okDialog(context, context.getResources().getString(
R.string.sync_upgrade_v99), new OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
context.startActivity(new Intent(context, SyncPreferences.class));
}
});
}
}
Preferences.setCurrentVersion(context, finalVersion);
new UpgradeService().performUpgrade(latestSetVersion);
}
// perform startup activities in a background thread
new Thread(new Runnable() {
public void run() {
// schedule alarms
Notifications.scheduleAllAlarms(context);
// start widget updating alarm
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, UpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setInexactRepeating(AlarmManager.RTC, 0,
Constants.WIDGET_UPDATE_INTERVAL, pendingIntent);
// start synchronization service
if(Constants.SYNCHRONIZE)
SynchronizationService.scheduleService(context);
// start backup service
BackupService.scheduleService(context);
}
}).start();
Preferences.setPreferenceDefaults(context);
// check for task killers
if(!Constants.OEM)
showTaskKillerHelp(context);
hasStartedUp = true;
}
private static void showTaskKillerHelp(final Context context) {
if(!Preferences.shouldShowTaskKillerHelp(context))
return;
// search for task killers. if they exist, show the help!
PackageManager pm = context.getPackageManager();
List<PackageInfo> apps = pm
.getInstalledPackages(PackageManager.GET_PERMISSIONS);
outer: for (PackageInfo app : apps) {
if(app == null || app.requestedPermissions == null)
continue;
if(app.packageName.startsWith("com.android"))
continue;
for (String permission : app.requestedPermissions) {
if (Manifest.permission.RESTART_PACKAGES.equals(permission)) {
CharSequence appName = app.applicationInfo.loadLabel(pm);
Log.e("astrid", "found task killer: " + app.packageName);
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(DialogInterface arg0,
int arg1) {
Preferences.disableTaskKillerHelp(context);
}
};
new AlertDialog.Builder(context)
.setTitle(R.string.information_title)
.setMessage(context.getString(R.string.task_killer_help,
appName))
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.task_killer_help_ok, listener)
.show();
break outer;
}
}
}
}
}

@ -1023,8 +1023,8 @@ public final class TaskEditActivity extends TabActivity {
@Override
public void readFromModel() {
setValue(model.getValue(Task.NOTIFICATION_FLAGS));
periodic = model.getValue(Task.NOTIFICATIONS);
setValue(model.getValue(Task.REMINDER_FLAGS));
periodic = model.getValue(Task.REMINDER_PERIOD);
if(periodic > 0) {
random.setChecked(true);
updatePeriodicString();
@ -1033,7 +1033,7 @@ public final class TaskEditActivity extends TabActivity {
@Override
public void writeToModel() {
model.setValue(Task.NOTIFICATION_FLAGS, getValue());
model.setValue(Task.REMINDER_FLAGS, getValue());
}
}

@ -47,48 +47,48 @@ public class TaskDao extends GenericDao<Task> {
*/
public static class TaskCriteria {
/** Returns tasks by id */
/** @returns tasks by id */
public static Criterion byId(long id) {
return Task.ID.eq(id);
}
/** Return tasks that were deleted */
/** @return tasks that were deleted */
public static Criterion isDeleted() {
return Task.DELETION_DATE.neq(0);
}
/** Return tasks that have not yet been completed */
/** @return tasks that have not yet been completed or deleted */
public static Criterion isActive() {
return Criterion.and(Task.COMPLETION_DATE.eq(0),
Task.DELETION_DATE.eq(0));
}
/** Return tasks that are not hidden at given unixtime */
/** @return tasks that are not hidden at given unixtime */
public static Criterion isVisible(long time) {
return Task.HIDE_UNTIL.lt(time);
}
/** Returns tasks that have a due date */
/** @return tasks that have a due date */
public static Criterion hasDeadlines() {
return Task.DUE_DATE.neq(0);
}
/** Returns tasks that are due before a certain unixtime */
/** @return tasks that are due before a certain unixtime */
public static Criterion dueBefore(long time) {
return Criterion.and(Task.DUE_DATE.gt(0), Task.DUE_DATE.lt(time));
}
/** Returns tasks that are due after a certain unixtime */
/** @return tasks that are due after a certain unixtime */
public static Criterion dueAfter(long time) {
return Task.DUE_DATE.gt(time);
}
/** Returns tasks completed before a given unixtime */
/** @return tasks completed before a given unixtime */
public static Criterion completedBefore(long time) {
return Criterion.and(Task.COMPLETION_DATE.gt(0), Task.COMPLETION_DATE.lt(time));
}
/** Returns tasks that have a blank or null title */
/** @return tasks that have a blank or null title */
@SuppressWarnings("nls")
public static Criterion hasNoTitle() {
return Criterion.or(Task.TITLE.isNull(), Task.TITLE.eq(""));
@ -142,6 +142,9 @@ public class TaskDao extends GenericDao<Task> {
afterSave(task, values, duringSync);
}
if(saveSuccessful)
task.markSaved();
return saveSuccessful;
}

@ -52,7 +52,7 @@ public final class Task extends AbstractModel {
public static final LongProperty DUE_DATE = new LongProperty(
TABLE, "dueDate");
/** Unixtime Task should be hidden until */
/** Unixtime Task should be hidden until, 0 if not set */
public static final LongProperty HIDE_UNTIL = new LongProperty(
TABLE, "hideUntil");
@ -90,14 +90,17 @@ public final class Task extends AbstractModel {
public static final IntegerProperty POSTPONE_COUNT = new IntegerProperty(
TABLE, "postponeCount");
public static final IntegerProperty NOTIFICATIONS = new IntegerProperty(
TABLE, "notifications");
/** Flags for when to send reminders */
public static final IntegerProperty REMINDER_FLAGS = new IntegerProperty(
TABLE, "reminderFlags");
public static final IntegerProperty NOTIFICATION_FLAGS = new IntegerProperty(
TABLE, "notificationFlags");
/** Reminder period, in milliseconds. 0 means disabled */
public static final LongProperty REMINDER_PERIOD = new LongProperty(
TABLE, "reminderPeriod");
public static final IntegerProperty LAST_NOTIFIED = new IntegerProperty(
TABLE, "lastNotified");
/** Unixtime the last reminder was triggered */
public static final LongProperty REMINDER_LAST = new LongProperty(
TABLE, "reminderLast");
public static final IntegerProperty REPEAT = new IntegerProperty(
TABLE, "repeat");
@ -116,13 +119,13 @@ public final class Task extends AbstractModel {
// --- notification flags
/** whether to send a reminder at deadline */
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
/** whether to send reminders while task is overdue */
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
/** reminder mode nonstop */
public static final int NOTIFY_NONSTOP = 1 << 3;
/** reminder mode non-stop */
public static final int NOTIFY_NONSTOP = 1 << 3;
// --- importance settings
@ -132,7 +135,7 @@ public final class Task extends AbstractModel {
public static final int IMPORTANCE_NONE = 3;
/**
* Get colors that correspond to importance values
* @return colors that correspond to importance values
*/
public static int[] getImportanceColors(Resources r) {
return new int[] {
@ -161,8 +164,8 @@ public final class Task extends AbstractModel {
defaultValues.put(CALENDAR_URI.name, "");
defaultValues.put(REPEAT.name, 0);
defaultValues.put(NOTIFICATIONS.name, 0);
defaultValues.put(NOTIFICATION_FLAGS.name, 0);
defaultValues.put(REMINDER_PERIOD.name, 0);
defaultValues.put(REMINDER_FLAGS.name, 0);
defaultValues.put(ESTIMATED_SECONDS.name, 0);
defaultValues.put(ELAPSED_SECONDS.name, 0);
defaultValues.put(POSTPONE_COUNT.name, 0);
@ -255,7 +258,7 @@ public final class Task extends AbstractModel {
/**
* @return true if hours, minutes, and seconds indicate end of day
*/
private boolean isEndOfDay(Date date) {
private static boolean isEndOfDay(Date date) {
return date.getHours() == 23 && date.getMinutes() == 59 &&
date.getSeconds() == 59;
}
@ -284,4 +287,14 @@ public final class Task extends AbstractModel {
public boolean hasDueTime() {
return isEndOfDay(new Date(getValue(DUE_DATE)));
}
}
/**
* Returns the set state of the given flag on the given property
* @param property
* @param flag
* @return
*/
public boolean getFlag(IntegerProperty property, int flag) {
return (getValue(property) & flag) > 0;
}
}

@ -127,9 +127,9 @@ public class Astrid2To3UpgradeHelper {
propertyMap.put(AbstractTaskModel.DEFINITE_DUE_DATE, Task.DUE_DATE);
propertyMap.put(AbstractTaskModel.HIDDEN_UNTIL, Task.HIDE_UNTIL);
propertyMap.put(AbstractTaskModel.POSTPONE_COUNT, Task.POSTPONE_COUNT);
propertyMap.put(AbstractTaskModel.NOTIFICATIONS, Task.NOTIFICATIONS);
propertyMap.put(AbstractTaskModel.NOTIFICATION_FLAGS, Task.NOTIFICATION_FLAGS);
propertyMap.put(AbstractTaskModel.LAST_NOTIFIED, Task.LAST_NOTIFIED);
propertyMap.put(AbstractTaskModel.NOTIFICATIONS, Task.REMINDER_PERIOD);
propertyMap.put(AbstractTaskModel.NOTIFICATION_FLAGS, Task.REMINDER_FLAGS);
propertyMap.put(AbstractTaskModel.LAST_NOTIFIED, Task.REMINDER_LAST);
propertyMap.put(AbstractTaskModel.REPEAT, Task.REPEAT);
propertyMap.put(AbstractTaskModel.CREATION_DATE, Task.CREATION_DATE);
propertyMap.put(AbstractTaskModel.COMPLETION_DATE, Task.COMPLETION_DATE);
@ -212,6 +212,9 @@ public class Astrid2To3UpgradeHelper {
DateUtilities.getFormattedDate(ContextManager.getContext(),
new Date(preferredDueDate)));
}
} else if(property == Task.REMINDER_PERIOD) {
// old period was stored in seconds
value *= 1000L;
}
data.model.setValue(property, value);

@ -6,7 +6,6 @@ import android.Manifest;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -18,24 +17,23 @@ import com.timsu.astrid.R;
import com.timsu.astrid.appwidget.AstridAppWidgetProvider.UpdateService;
import com.timsu.astrid.sync.SynchronizationService;
import com.timsu.astrid.utilities.BackupService;
import com.timsu.astrid.utilities.Notifications;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.service.ExceptionService.TodorooUncaughtExceptionHandler;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.utility.Preferences;
/**
* Service which handles jobs that need to be run when user's phone or Astrid
* starts up.
* Service which handles jobs that need to be run when Astrid starts up.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class StartupService extends BroadcastReceiver {
public class StartupService {
static {
AstridDependencyInjector.initialize();
@ -45,15 +43,6 @@ public class StartupService extends BroadcastReceiver {
DependencyInjectionService.getInstance().inject(this);
}
// --- system startup
@Override
/** Called when the system is started up */
public void onReceive(Context context, Intent intent) {
ContextManager.setContext(context);
Notifications.scheduleAllAlarms(context);
}
// --- application startup
@Autowired
@ -106,7 +95,7 @@ public class StartupService extends BroadcastReceiver {
new Thread(new Runnable() {
public void run() {
// schedule alarms
Notifications.scheduleAllAlarms(context);
new ReminderService().scheduleAllAlarms();
// start widget updating alarm
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

@ -21,14 +21,18 @@ public class Preferences {
Editor editor = prefs.edit();
Resources r = context.getResources();
if(getIntegerFromString(R.string.EPr_default_urgency_key) == null) {
editor.putString(r.getString(R.string.EPr_default_urgency_key),
if(getIntegerFromString(R.string.p_default_urgency_key) == null) {
editor.putString(r.getString(R.string.p_default_urgency_key),
Integer.toString(4));
}
if(getIntegerFromString(R.string.EPr_default_importance_key) == null) {
editor.putString(r.getString(R.string.EPr_default_importance_key),
if(getIntegerFromString(R.string.p_default_importance_key) == null) {
editor.putString(r.getString(R.string.p_default_importance_key),
Integer.toString(Task.IMPORTANCE_SHOULD_DO));
}
if(getIntegerFromString(R.string.p_reminder_time) == null) {
editor.putString(r.getString(R.string.p_reminder_time),
Integer.toString(12));
}
editor.commit();
}

@ -99,7 +99,7 @@ public class Astrid2To3UpgradeTests extends DatabaseTestCase {
assertEquals((Integer)Task.IMPORTANCE_NONE, task.getValue(Task.IMPORTANCE));
assertEquals(griffey.getEstimatedSeconds(), task.getValue(Task.ESTIMATED_SECONDS));
assertEquals(griffey.getNotes(), task.getValue(Task.NOTES));
assertEquals((Integer)0, task.getValue(Task.LAST_NOTIFIED));
assertEquals((Integer)0, task.getValue(Task.REMINDER_LAST));
assertEquals((Integer)0, task.getValue(Task.HIDE_UNTIL));
tasks.moveToNext();

Loading…
Cancel
Save