More progress in the effort of getting notifications working.

pull/14/head
Tim Su 15 years ago
parent 3cb2ed563e
commit 1c9d4c1696

@ -195,6 +195,8 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity android:name="com.todoroo.astrid.reminders.NotificationActivity"
android:taskAffinity="reminders" />
</application> </application>
</manifest> </manifest>

@ -17,12 +17,15 @@
* with this program; if not, write to the Free Software Foundation, Inc., * with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
package com.timsu.astrid.activities; package com.todoroo.astrid.reminders;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import com.timsu.astrid.activities.TaskList;
import com.todoroo.astrid.activity.TaskListActivity;
/** /**
* This activity is launched when a user opens up a notification from the * This activity is launched when a user opens up a notification from the
* tray. It launches the appropriate activity based on the passed in parameters. * tray. It launches the appropriate activity based on the passed in parameters.
@ -30,7 +33,7 @@ import android.os.Bundle;
* @author timsu * @author timsu
* *
*/ */
public class TaskListNotify extends Activity { public class NotificationActivity extends Activity {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -47,7 +50,7 @@ public class TaskListNotify extends Activity {
} }
private void launchTaskList(Intent intent) { private void launchTaskList(Intent intent) {
Intent taskListIntent = new Intent(this, TaskList.class); Intent taskListIntent = new Intent(this, TaskListActivity.class);
taskListIntent.putExtra(TaskList.VARIABLES_TAG, intent.getExtras()); taskListIntent.putExtra(TaskList.VARIABLES_TAG, intent.getExtras());
startActivity(taskListIntent); startActivity(taskListIntent);

@ -1,7 +1,6 @@
package com.todoroo.astrid.reminders; package com.todoroo.astrid.reminders;
import java.util.Date; import java.util.Date;
import java.util.Random;
import android.app.Activity; import android.app.Activity;
import android.app.Notification; import android.app.Notification;
@ -17,85 +16,66 @@ import android.net.Uri;
import android.util.Log; import android.util.Log;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.timsu.astrid.activities.TaskListNotify;
import com.timsu.astrid.activities.TaskListSubActivity;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier; import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForReminder;
import com.timsu.astrid.utilities.Constants; import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.Preferences; import com.timsu.astrid.utilities.Preferences;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
public class Notifications extends BroadcastReceiver { public class Notifications extends BroadcastReceiver {
static final String ID_KEY = "id"; // --- constants
static final String TYPE_KEY = "flags";
private static final String REPEAT_KEY = "repeat"; /** task id extra */
private static final int TAG_ID_OFFSET = 100000; static final String ID_KEY = "id"; //$NON-NLS-1$
// stuff for scheduling /** notification type extra */
/** minimum # of seconds before a deadline to notify */ static final String TYPE_KEY = "flags"; //$NON-NLS-1$
private static final int DEADLINE_NOTIFY_SECS = 60 * 60;
/** # of seconds after deadline to repeat reminder*/ // --- instance variables
private static final int DEADLINE_REPEAT = 10 * 60;
@Autowired
// flags private TaskDao taskDao;
public static final int FLAG_DEFINITE_DEADLINE = 1 << 0;
public static final int FLAG_PREFERRED_DEADLINE = 1 << 1; @Autowired
public static final int FLAG_OVERDUE = 1 << 2; private ExceptionService exceptionService;
public static final int FLAG_PERIODIC = 1 << 3;
public static final int FLAG_FIXED = 1 << 4; // --- alarm handling
public static final int FLAG_SNOOZE = 1 << 5;
/** # of bits to shift the fixed alert ID */ static {
public static final int FIXED_ID_SHIFT = 6; AstridDependencyInjector.initialize();
private static Random random = new Random();
/** Something we can create a notification for */
public interface Notifiable {
public TaskIdentifier getTaskIdentifier();
public Integer getNotificationIntervalSeconds();
public boolean isTaskCompleted();
public Date getHiddenUntil();
public Date getDefiniteDueDate();
public Date getPreferredDueDate();
public Date getLastNotificationDate();
public int getNotificationFlags();
public Integer getEstimatedSeconds();
} }
@Override @Override
/** Alarm intent */ /** Alarm intent */
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
DependencyInjectionService.getInstance().inject(this);
long id = intent.getLongExtra(ID_KEY, 0); long id = intent.getLongExtra(ID_KEY, 0);
int flags = intent.getIntExtra(FLAGS_KEY, 0); int type = intent.getIntExtra(TYPE_KEY, 0);
Resources r = context.getResources(); Resources r = context.getResources();
String reminder; String reminder;
if((flags & FLAG_DEFINITE_DEADLINE) > 0) if(type == ReminderService.TYPE_DUE || type == ReminderService.TYPE_OVERDUE)
reminder = r.getString(R.string.notif_definiteDueDate); reminder = getRandomReminder(r.getStringArray(R.array.reminders_due));
else if((flags & FLAG_PREFERRED_DEADLINE) > 0) else if(type == ReminderService.TYPE_SNOOZE)
reminder = r.getString(R.string.notif_preferredDueDate); reminder = getRandomReminder(r.getStringArray(R.array.reminders_snooze));
else else
reminder = getRandomReminder(r); reminder = getRandomReminder(r.getStringArray(R.array.reminders));
long repeatInterval = intent.getLongExtra(REPEAT_KEY, 0);
if(Constants.DEBUG)
Log.e("ALARM", "Alarm triggered id " + id +", flags " + flags +
", repeat " + repeatInterval);
if(!showNotification(context, id, flags, repeatInterval, reminder)) { if(!showNotification(context, id, type, reminder)) {
deleteAlarm(context, intent, id);
NotificationManager nm = (NotificationManager) NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE); context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel((int)id); nm.cancel((int)id);
} }
} }
// --- alarm manager stuff // --- notification creation
// --- notification manager stuff
/** Clear notifications associated with this application */ /** Clear notifications associated with this application */
public static void clearAllNotifications(Context context, TaskIdentifier taskId) { public static void clearAllNotifications(Context context, TaskIdentifier taskId) {
@ -104,57 +84,46 @@ public class Notifications extends BroadcastReceiver {
nm.cancel((int)taskId.getId()); nm.cancel((int)taskId.getId());
} }
private static String getRandomReminder(Resources r) { /** @return a random reminder string */
String[] reminders = r.getStringArray(R.array.reminders); private static String getRandomReminder(String[] reminders) {
int next = random.nextInt(reminders.length); int next = ReminderService.random.nextInt(reminders.length);
String reminder = reminders[next]; String reminder = reminders[next];
return reminder; return reminder;
} }
/** Schedule a new notification about the given task. Returns false if there was /**
* some sort of error or the alarm should be disabled. */ * Schedule a new notification about the given task. Returns false if there was
public static boolean showNotification(Context context, long id, * some sort of error or the alarm should be disabled.
int flags, long repeatInterval, String reminder) { */
public boolean showNotification(Context context, long id,
int type, String reminder) {
String taskName; Task task;
TaskController controller = new TaskController(context);
boolean nonstopMode = false;
try { try {
controller.open(); task = taskDao.fetch(id, Task.TITLE, Task.HIDE_UNTIL, Task.COMPLETION_DATE,
TaskModelForReminder task = controller.fetchTaskForReminder(new TaskIdentifier(id)); Task.DELETION_DATE, Task.REMINDER_FLAGS);
} catch (Exception e) {
// you're working on it - don't sound, don't delete exceptionService.reportError("show-notif", e); //$NON-NLS-1$
if(task.getTimerStart() != null) return false;
return true; }
// you're done - don't sound, do delete // you're done - don't sound, do delete
if(task.isTaskCompleted()) if(task.isCompleted() || task.isDeleted())
return false; return false;
// it's hidden - don't sound, don't delete // it's hidden - don't sound, don't delete
if(task.getHiddenUntil() != null && if(task.isHidden() && type == ReminderService.TYPE_RANDOM)
task.getHiddenUntil().after(new Date()) &&
(flags & FLAG_PERIODIC) > 0)
return true; return true;
taskName = task.getName(); // read properties
if((flags & FLAG_PERIODIC) > 0) String taskTitle = task.getValue(Task.TITLE);
controller.setLastNotificationTime(task.getTaskIdentifier(), boolean nonstopMode = task.getFlag(Task.REMINDER_FLAGS, Task.NOTIFY_NONSTOP);
new Date());
if((task.getNotificationFlags() & TaskModelForReminder.NOTIFY_NONSTOP) > 0)
nonstopMode = true;
} catch (Exception e) { // update last reminder time
// task might have been deleted task.setValue(Task.REMINDER_LAST, DateUtilities.now());
Log.e(Notifications.class.getSimpleName(), taskDao.save(task, false);
"Error loading task for notification", e);
return false;
} finally {
controller.close();
}
// quiet hours? disabled if alarm clock // quiet hours? unless alarm clock
boolean quietHours = false; boolean quietHours = false;
Integer quietHoursStart = Preferences.getQuietHourStart(context); Integer quietHoursStart = Preferences.getQuietHourStart(context);
Integer quietHoursEnd = Preferences.getQuietHourEnd(context); Integer quietHoursEnd = Preferences.getQuietHourEnd(context);
@ -173,11 +142,11 @@ public class Notifications extends BroadcastReceiver {
.getSystemService(Context.NOTIFICATION_SERVICE); .getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources(); Resources r = context.getResources();
Intent notifyIntent = new Intent(context, TaskListNotify.class); Intent notifyIntent = new Intent(context, NotificationActivity.class);
notifyIntent.putExtra(TaskListSubActivity.LOAD_INSTANCE_TOKEN, id); /*notifyIntent.putExtra(TaskListSubActivity.LOAD_INSTANCE_TOKEN, id);
notifyIntent.putExtra(TaskListSubActivity.FROM_NOTIFICATION_TOKEN, true); notifyIntent.putExtra(TaskListSubActivity.FROM_NOTIFICATION_TOKEN, true);
notifyIntent.putExtra(TaskListSubActivity.NOTIF_FLAGS_TOKEN, flags); notifyIntent.putExtra(TaskListSubActivity.NOTIF_FLAGS_TOKEN, flags);
notifyIntent.putExtra(TaskListSubActivity.NOTIF_REPEAT_TOKEN, repeatInterval); notifyIntent.putExtra(TaskListSubActivity.NOTIF_REPEAT_TOKEN, repeatInterval); TODO */
PendingIntent pendingIntent = PendingIntent.getActivity(context, PendingIntent pendingIntent = PendingIntent.getActivity(context,
(int)id, notifyIntent, PendingIntent.FLAG_ONE_SHOT); (int)id, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
@ -200,7 +169,7 @@ public class Notifications extends BroadcastReceiver {
icon, reminder, System.currentTimeMillis()); icon, reminder, System.currentTimeMillis());
notification.setLatestEventInfo(context, notification.setLatestEventInfo(context,
appName, appName,
reminder + " " + taskName, reminder + " " + taskTitle, //$NON-NLS-1$
pendingIntent); pendingIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.flags |= Notification.FLAG_AUTO_CANCEL;
if(Preferences.isPersistenceMode(context)) { if(Preferences.isPersistenceMode(context)) {
@ -216,10 +185,10 @@ public class Notifications extends BroadcastReceiver {
AudioManager audioManager = (AudioManager)context.getSystemService( AudioManager audioManager = (AudioManager)context.getSystemService(
Context.AUDIO_SERVICE); Context.AUDIO_SERVICE);
// if nonstop mode is activated, set up the flags for insistent // if non-stop mode is activated, set up the flags for insistent
// notification, and increase the volume to full volume, so the user // notification, and increase the volume to full volume, so the user
// will actually pay attention to the alarm // will actually pay attention to the alarm
if(nonstopMode && (flags & FLAG_PERIODIC) == 0) { if(nonstopMode && (type != ReminderService.TYPE_RANDOM)) {
notification.flags |= Notification.FLAG_INSISTENT; notification.flags |= Notification.FLAG_INSISTENT;
notification.audioStreamType = AudioManager.STREAM_ALARM; notification.audioStreamType = AudioManager.STREAM_ALARM;
audioManager.setStreamVolume(AudioManager.STREAM_ALARM, audioManager.setStreamVolume(AudioManager.STREAM_ALARM,
@ -236,7 +205,7 @@ public class Notifications extends BroadcastReceiver {
if(audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) { if(audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) {
notification.sound = null; notification.sound = null;
} else if(notificationSound != null && } else if(notificationSound != null &&
!notificationSound.toString().equals("")) { !notificationSound.toString().equals("")) { //$NON-NLS-1$
notification.sound = notificationSound; notification.sound = notificationSound;
} else { } else {
notification.defaults |= Notification.DEFAULT_SOUND; notification.defaults |= Notification.DEFAULT_SOUND;
@ -244,7 +213,7 @@ public class Notifications extends BroadcastReceiver {
} }
// quiet hours + periodic = no vibrate // quiet hours + periodic = no vibrate
if(quietHours && (flags & FLAG_PERIODIC) > 0) { if(quietHours && (type == ReminderService.TYPE_RANDOM)) {
notification.vibrate = null; notification.vibrate = null;
} else { } else {
if (Preferences.shouldVibrate(context) if (Preferences.shouldVibrate(context)
@ -256,121 +225,10 @@ public class Notifications extends BroadcastReceiver {
} }
if(Constants.DEBUG) if(Constants.DEBUG)
Log.w("Astrid", "Logging notification: " + reminder); Log.w("Astrid", "Logging notification: " + reminder); //$NON-NLS-1$ //$NON-NLS-2$
nm.notify((int)id, notification); nm.notify((int)id, notification);
return true; return true;
} }
/** Show a notification when a user is "on-the-clock" for a given task */
public static boolean showTimingNotification(Context context,
TaskIdentifier taskId, String taskName) {
String text = context.getResources().getString(R.string.notif_timerStarted) +
" " + taskName;
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources();
Intent notifyIntent = new Intent(context, TaskListNotify.class);
notifyIntent.putExtra(TaskListSubActivity.LOAD_INSTANCE_TOKEN, taskId.getId());
notifyIntent.putExtra(TaskListSubActivity.FROM_NOTIFICATION_TOKEN, true);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
(int)taskId.getId(), notifyIntent, 0);
// create notification object
int icon;
switch(Preferences.getNotificationIconTheme(context)) {
case Preferences.ICON_SET_PINK:
icon = R.drawable.notif_pink_working;
break;
case Preferences.ICON_SET_BORING:
icon = R.drawable.notif_boring_working;
break;
default:
icon = R.drawable.notif_astrid;
}
String appName = r.getString(R.string.app_name);
Notification notification = new Notification(
icon, text, System.currentTimeMillis());
notification.setLatestEventInfo(context,
appName,
text,
pendingIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT |
Notification.FLAG_NO_CLEAR;
notification.flags &= ~Notification.FLAG_AUTO_CANCEL;
if(Constants.DEBUG)
Log.w("Astrid", "Logging timing notification: " + text);
nm.notify((int)taskId.getId(), notification);
return true;
}
/** Schedule a new notification about the given tag. */
public static boolean showTagNotification(Context context, long tagId,
String reminder) {
// quiet hours? only for periodic reminders
boolean quietHours = false;
Integer quietHoursStart = Preferences.getQuietHourStart(context);
Integer quietHoursEnd = Preferences.getQuietHourEnd(context);
if(quietHoursStart != null && quietHoursEnd != null) {
int hour = new Date().getHours();
if(quietHoursStart < quietHoursEnd) {
if(hour >= quietHoursStart && hour < quietHoursEnd)
quietHours = true;
} else { // wrap across 24/hour boundary
if(hour >= quietHoursStart || hour < quietHoursEnd)
quietHours = true;
}
}
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources();
Intent notifyIntent = new Intent(context, TaskListNotify.class);
notifyIntent.putExtra(TaskListSubActivity.TAG_TOKEN, tagId);
notifyIntent.putExtra(TaskListSubActivity.FROM_NOTIFICATION_TOKEN, true);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
TAG_ID_OFFSET + (int)tagId, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
// set up properties (name and icon) for the notification
String appName = r.getString(R.string.app_name);
int icon = R.drawable.notif_tag;
// create notification object
Notification notification = new Notification(
icon, reminder, System.currentTimeMillis());
notification.setLatestEventInfo(context,
appName,
reminder,
pendingIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.ledARGB = Color.BLUE;
notification.defaults = Notification.DEFAULT_LIGHTS;
if(quietHours) {
notification.vibrate = null;
notification.sound = null;
} else {
notification.defaults |= Notification.DEFAULT_VIBRATE;
Uri notificationSound = Preferences.getNotificationRingtone(context);
if(notificationSound != null &&
!notificationSound.toString().equals("")) {
notification.sound = notificationSound;
} else {
notification.defaults |= Notification.DEFAULT_SOUND;
}
}
if(Constants.DEBUG)
Log.w("Astrid", "Logging tag notification: " + reminder);
nm.notify(TAG_ID_OFFSET + (int)tagId, notification);
return true;
}
} }

@ -56,7 +56,7 @@ public final class ReminderService {
@Autowired @Autowired
private TaskDao taskDao; private TaskDao taskDao;
private static final Random random = new Random(); static final Random random = new Random();
public ReminderService() { public ReminderService() {
DependencyInjectionService.getInstance().inject(this); DependencyInjectionService.getInstance().inject(this);

@ -26,63 +26,6 @@
<resources> <resources>
<!-- ====================================================== reminders == -->
<string-array name="reminders">
<!-- reminders: Make these < 20 chars so the task name is displayed -->
<item>Hi there! Have a sec?</item>
<item>Can I see you for a sec?</item>
<item>Have a few minutes?</item>
<item>Did you forget?</item>
<item>Excuse me!</item>
<item>When you have a minute:</item>
<item>On your agenda:</item>
<item>Free for a moment?</item>
<item>Astrid here!</item>
<item>Hi! Can I bug you?</item>
<item>A minute of your time?</item>
<item>It\'s a great day to</item>
</string-array>
<string-array name="reminder_responses">
<!-- reminder_responses: Astrid says... (user should answer yes or no) -->
<item>I\'ve got something for you!</item>
<item>Ready to put this in the past?</item>
<item>Why don\'t you get this done?</item>
<item>How about it? Ready tiger?</item>
<item>Ready to do this?</item>
<item>Can you handle this?</item>
<item>You can be happy! Just finish this!</item>
<item>I promise you\'ll feel better if you finish this!</item>
<item>Won\'t you do this today?</item>
<item>Please finish this, I\'m sick of it!</item>
<item>Can you finish this? Yes you can!</item>
<item>Are you ever going to do this?</item>
<item>Feel good about yourself! Let\'s go!</item>
<item>I\'m so proud of you! Lets get it done!</item>
<item>A little snack after you finish this?</item>
<item>Just this one task? Please?</item>
<item>Time to shorten your todo list!</item>
</string-array>
<string-array name="postpone_nags">
<!-- Astrid's nagging when user clicks postpone -->
<item>Please tell me it isn\'t true that you\'re a procrastinator!</item>
<item>Doesn\'t being lazy get old sometimes?</item>
<item>Somewhere, someone is depending on you to finish this!</item>
<item>When you said postpone, you really meant \'I\'m doing this\', right?</item>
<item>This is the last time you postpone this, right?</item>
<item>Just finish this today, I won\'t tell anyone!</item>
<item>Why postpone when you can um... not postpone!</item>
<item>You\'ll finish this eventually, I presume?</item>
<item>I think you\'re really great! How about not putting this off?</item>
<item>Will you be able to achieve your goals if you do that?</item>
<item>Postpone, postpone, postpone. When will you change!</item>
<item>I\'ve had enough with your excuses! Just do it already!</item>
<item>Didn\'t you make that excuse last time?</item>
<item>I can\'t help you organize your life if you do that...</item>
</string-array>
<!-- ==================================================== task values == --> <!-- ==================================================== task values == -->
<string-array name="TEA_urgency"> <string-array name="TEA_urgency">

@ -399,15 +399,6 @@ Skipped %d tasks.\n
when you have uncompleted tasks with the following criteria:</string> when you have uncompleted tasks with the following criteria:</string>
<string name="locale_pick_tag">Tagged with:</string> <string name="locale_pick_tag">Tagged with:</string>
<!-- Notification -->
<skip />
<string name="notif_definiteDueDate">Absolute Deadline!</string>
<string name="notif_preferredDueDate">Goal Deadline!</string>
<string name="notif_timerStarted">Working on:</string>
<!-- $NUM is replaced with # of tasks + units, i.e. "1 task", $TAG is replaced with tag name -->
<string name="notif_tagNotification">You have $NUM tagged $TAG!</string>
<!-- Error Messages --> <!-- Error Messages -->
<skip /> <skip />

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<resources>
<!-- Resources for built-in reminders plug-in -->
<string name="notif_definiteDueDate">Absolute Deadline!</string>
<string name="notif_preferredDueDate">Goal Deadline!</string>
<string name="notif_timerStarted">Working on:</string>
<!-- $NUM is replaced with # of tasks + units, i.e. "1 task", $TAG is replaced with tag name -->
<string name="notif_tagNotification">You have $NUM tagged $TAG!</string>
<!-- =============================================== random reminders == -->
<string-array name="reminders">
<!-- reminders: Make these < 20 chars so the task name is displayed -->
<item>Hi there! Have a sec?</item>
<item>Can I see you for a sec?</item>
<item>Have a few minutes?</item>
<item>Did you forget?</item>
<item>Excuse me!</item>
<item>When you have a minute:</item>
<item>On your agenda:</item>
<item>Free for a moment?</item>
<item>Astrid here!</item>
<item>Hi! Can I bug you?</item>
<item>A minute of your time?</item>
<item>It\'s a great day to</item>
</string-array>
<string-array name="reminders_due">
<!-- reminders related to task due date -->
<item>Time to work!</item>
<item>Due date is here!</item>
<item>Ready to start?</item>
<item>You said you would do:</item>
<item>You\'re supposed to start:</item>
<item>Time to start:</item>
<item>It\'s time!</item>
<item>Excuse me! Time for</item>
<item>You free? Time to</item>
</string-array>
<string-array name="reminders_snooze">
<!-- reminders related to snooze -->
<item>Don\'t be lazy now!</item>
<item>Snooze time is up!</item>
<item>No more snoozing!</item>
<item>Now are you ready?</item>
<item>No more postponing!</item>
</string-array>
<string-array name="responses">
<!-- responses to reminder: Astrid says... (user should answer yes or no) -->
<item>I\'ve got something for you!</item>
<item>Ready to put this in the past?</item>
<item>Why don\'t you get this done?</item>
<item>How about it? Ready tiger?</item>
<item>Ready to do this?</item>
<item>Can you handle this?</item>
<item>You can be happy! Just finish this!</item>
<item>I promise you\'ll feel better if you finish this!</item>
<item>Won\'t you do this today?</item>
<item>Please finish this, I\'m sick of it!</item>
<item>Can you finish this? Yes you can!</item>
<item>Are you ever going to do this?</item>
<item>Feel good about yourself! Let\'s go!</item>
<item>I\'m so proud of you! Lets get it done!</item>
<item>A little snack after you finish this?</item>
<item>Just this one task? Please?</item>
<item>Time to shorten your todo list!</item>
</string-array>
<string-array name="postpone_nags">
<!-- Astrid's nagging when user clicks postpone -->
<item>Please tell me it isn\'t true that you\'re a procrastinator!</item>
<item>Doesn\'t being lazy get old sometimes?</item>
<item>Somewhere, someone is depending on you to finish this!</item>
<item>When you said postpone, you really meant \'I\'m doing this\', right?</item>
<item>This is the last time you postpone this, right?</item>
<item>Just finish this today, I won\'t tell anyone!</item>
<item>Why postpone when you can um... not postpone!</item>
<item>You\'ll finish this eventually, I presume?</item>
<item>I think you\'re really great! How about not putting this off?</item>
<item>Will you be able to achieve your goals if you do that?</item>
<item>Postpone, postpone, postpone. When will you change!</item>
<item>I\'ve had enough with your excuses! Just do it already!</item>
<item>Didn\'t you make that excuse last time?</item>
<item>I can\'t help you organize your life if you do that...</item>
</string-array>
</resources>

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

@ -795,7 +795,7 @@ public final class TaskEditActivity extends TabActivity {
this.urgency.setAdapter(urgencyAdapter); this.urgency.setAdapter(urgencyAdapter);
if(isNewTask()) { if(isNewTask()) {
urgency.setSelection(Preferences.getIntegerFromString(R.string.EPr_default_urgency_key)); urgency.setSelection(Preferences.getIntegerFromString(R.string.p_default_urgency_key));
} else { } else {
urgency.setSelection(0); urgency.setSelection(0);
} }
@ -979,7 +979,7 @@ public final class TaskEditActivity extends TabActivity {
random = (CheckBox)findViewById(randomId); random = (CheckBox)findViewById(randomId);
mode = (Spinner)findViewById(modeId); mode = (Spinner)findViewById(modeId);
periodic = Preferences.getIntegerFromString(R.string.p_notif_defaultRemind) periodic = Preferences.getIntegerFromString(R.string.p_default_reminder_random)
* DateUtilities.ONE_DAY; * DateUtilities.ONE_DAY;
updatePeriodicString(); updatePeriodicString();

@ -19,6 +19,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.model.Task; import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.reminders.ReminderService;
/** /**
* Data Access layer for {@link Task}-related operations. * Data Access layer for {@link Task}-related operations.
@ -34,6 +35,8 @@ public class TaskDao extends GenericDao<Task> {
@Autowired @Autowired
Database database; Database database;
ReminderService reminderService = new ReminderService();
public TaskDao() { public TaskDao() {
super(Task.class); super(Task.class);
DependencyInjectionService.getInstance().inject(this); DependencyInjectionService.getInstance().inject(this);
@ -192,18 +195,91 @@ public class TaskDao extends GenericDao<Task> {
* @param duringSync whether this save occurs as part of a sync * @param duringSync whether this save occurs as part of a sync
*/ */
private void afterSave(Task task, ContentValues values, boolean duringSync) { private void afterSave(Task task, ContentValues values, boolean duringSync) {
if(values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted())
afterComplete(task, values, duringSync);
else
reminderService.scheduleAlarm(task);
if(duringSync) if(duringSync)
return; return;
// if task was completed, fire task completed notification // due date was updated, update calendar event
if(values.containsKey(Task.COMPLETION_DATE.name) && /*if((values.containsKey(AbstractTaskModel.DEFINITE_DUE_DATE) ||
values.getAsInteger(Task.COMPLETION_DATE.name) > 0 && !duringSync) { values.containsKey(AbstractTaskModel.PREFERRED_DUE_DATE)) &&
!values.containsKey(AbstractTaskModel.CALENDAR_URI)) {
try {
Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
new String[] { AbstractTaskModel.CALENDAR_URI });
cursor.moveToFirst();
String uriAsString = cursor.getString(0);
cursor.close();
if(uriAsString != null && uriAsString.length() > 0) {
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.parse(uriAsString);
Integer estimated = null;
if(values.containsKey(AbstractTaskModel.ESTIMATED_SECONDS))
estimated = values.getAsInteger(AbstractTaskModel.ESTIMATED_SECONDS);
else { // read from event
Cursor event = cr.query(uri, new String[] {"dtstart", "dtend"},
null, null, null);
event.moveToFirst();
estimated = (event.getInt(1) - event.getInt(0))/1000;
}
// create new start and end date for this event
ContentValues newValues = new ContentValues();
TaskEditActivity.createCalendarStartEndTimes(task.getPreferredDueDate(),
task.getDefiniteDueDate(), estimated, newValues); TODO
cr.update(uri, newValues, null, null);
}
} catch (Exception e) {
// ignore calendar event - event could be deleted or whatever
Log.e("astrid", "Error moving calendar event", e);
}
}*/
}
/**
* Called after the task was just completed
*
* @param task
* @param values
* @param duringSync
*/
private void afterComplete(Task task, ContentValues values, boolean duringSync) {
/*Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(),
TaskModelForHandlers.FIELD_LIST);
TaskModelForHandlers model = new TaskModelForHandlers(cursor, values);
// handle repeat
RepeatInfo repeatInfo = model.getRepeat();
if(repeatInfo != null) {
model.repeatTaskBy(context, this, repeatInfo);
database.update(tasksTable, values, KEY_ROWID + "=" +
task.getTaskIdentifier().getId(), null);
}
// handle sync-on-complete
if((model.getFlags() & TaskModelForHandlers.FLAG_SYNC_ON_COMPLETE) > 0 &&
!duringSync) {
Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier());
synchronizer.synchronize(context, new SynchronizerListener() {
public void onSynchronizerFinished(int numServicesSynced) {
TaskListSubActivity.shouldRefreshTaskList = true;
}
});
}
cursor.close();
cleanupTask(task.getTaskIdentifier(), repeatInfo != null);*/
// send broadcast
if(!duringSync) {
Context context = ContextManager.getContext(); Context context = ContextManager.getContext();
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED); Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId()); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
context.sendOrderedBroadcast(broadcastIntent, null); context.sendOrderedBroadcast(broadcastIntent, null);
} }
} }

@ -1,3 +1,11 @@
reminders
<string name="notif_definiteDueDate">Absolute Deadline!</string>
<string name="notif_preferredDueDate">Goal Deadline!</string>
<string name="notif_timerStarted">Working on:</string>
<!-- $NUM is replaced with # of tasks + units, i.e. "1 task", $TAG is replaced with tag name -->
<string name="notif_tagNotification">You have $NUM tagged $TAG!</string>
task edit task edit
<!-- title bar --> <!-- title bar -->

Loading…
Cancel
Save