added reminder service tests, got many to pass

pull/14/head
Tim Su 14 years ago
parent 05234dde7f
commit a453628a8a

@ -76,7 +76,7 @@ public class GenericDao<TYPE extends AbstractModel> {
* properties to read
* @param id
* id of item
* @return
* @return null if no item found
*/
public TYPE fetch(long id, Property<?>... properties) {
TodorooCursor<TYPE> cursor = fetchItem(id, properties);

@ -28,7 +28,7 @@ public interface NotificationManager {
*
*/
public static class AndroidNotificationManager implements NotificationManager {
final android.app.NotificationManager nm;
private final android.app.NotificationManager nm;
public AndroidNotificationManager(Context context) {
nm = (android.app.NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);

@ -10,5 +10,5 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-8
target=android-7
apk-configurations=

@ -4,7 +4,6 @@ import java.util.Date;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -23,6 +22,8 @@ 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.NotificationManager;
import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.model.Task;
@ -36,7 +37,7 @@ public class Notifications extends BroadcastReceiver {
static final String ID_KEY = "id"; //$NON-NLS-1$
/** notification type extra */
static final String TYPE_KEY = "flags"; //$NON-NLS-1$
static final String TYPE_KEY = "type"; //$NON-NLS-1$
// --- instance variables
@ -46,6 +47,8 @@ public class Notifications extends BroadcastReceiver {
@Autowired
private ExceptionService exceptionService;
public static NotificationManager notificationManager = null;
// --- alarm handling
static {
@ -57,9 +60,11 @@ public class Notifications extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
DependencyInjectionService.getInstance().inject(this);
ContextManager.setContext(context);
if(notificationManager == null)
notificationManager = new AndroidNotificationManager(context);
long id = intent.getLongExtra(ID_KEY, 0);
int type = intent.getIntExtra(TYPE_KEY, 0);
int type = intent.getIntExtra(TYPE_KEY, (byte) 0);
Resources r = context.getResources();
String reminder;
@ -71,9 +76,7 @@ public class Notifications extends BroadcastReceiver {
reminder = getRandomReminder(r.getStringArray(R.array.reminders));
if(!showNotification(id, type, reminder)) {
NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel((int)id);
notificationManager.cancel((int)id);
}
}
@ -104,6 +107,9 @@ public class Notifications extends BroadcastReceiver {
try {
task = taskDao.fetch(id, Task.TITLE, Task.HIDE_UNTIL, Task.COMPLETION_DATE,
Task.DELETION_DATE, Task.REMINDER_FLAGS);
if(task == null)
throw new IllegalArgumentException("cound not find item with id"); //$NON-NLS-1$
} catch (Exception e) {
exceptionService.reportError("show-notif", e); //$NON-NLS-1$
return false;
@ -129,7 +135,7 @@ public class Notifications extends BroadcastReceiver {
boolean quietHours = false;
Integer quietHoursStart = Preferences.getQuietHourStart(context);
Integer quietHoursEnd = Preferences.getQuietHourEnd(context);
if(quietHoursStart != null && quietHoursEnd != null && nonstopMode) {
if(quietHoursStart != null && quietHoursEnd != null && !nonstopMode) {
int hour = new Date().getHours();
if(quietHoursStart < quietHoursEnd) {
if(hour >= quietHoursStart && hour < quietHoursEnd)
@ -140,8 +146,6 @@ public class Notifications extends BroadcastReceiver {
}
}
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources();
Intent notifyIntent = new Intent(context, NotificationActivity.class);
@ -228,9 +232,16 @@ public class Notifications extends BroadcastReceiver {
if(Constants.DEBUG)
Log.w("Astrid", "Logging notification: " + reminder); //$NON-NLS-1$ //$NON-NLS-2$
nm.notify((int)id, notification);
notificationManager.notify((int)id, notification);
return true;
}
// --- notification manager
public static void setNotificationManager(
NotificationManager notificationManager) {
Notifications.notificationManager = notificationManager;
}
}

@ -43,20 +43,22 @@ public final class ReminderService {
};
/** flag for due date reminder */
static final byte TYPE_DUE = 0;
static final int TYPE_DUE = 0;
/** flag for overdue reminder */
static final byte TYPE_OVERDUE = 1;
static final int TYPE_OVERDUE = 1;
/** flag for random reminder */
static final byte TYPE_RANDOM = 2;
static final int TYPE_RANDOM = 2;
/** flag for a snoozed reminder */
static final byte TYPE_SNOOZE = 3;
static final int TYPE_SNOOZE = 3;
static final Random random = new Random();
// --- instance variables
@Autowired
private TaskDao taskDao;
static final Random random = new Random();
private AlarmScheduler scheduler = new ReminderAlarmScheduler();
public ReminderService() {
DependencyInjectionService.getInstance().inject(this);
@ -98,7 +100,7 @@ public final class ReminderService {
* whether to check if task has requisite properties
*/
private void scheduleAlarm(Task task, boolean shouldPerformPropertyCheck) {
if(!task.isSaved())
if(task == null || !task.isSaved())
return;
// read data if necessary
@ -106,6 +108,8 @@ public final class ReminderService {
for(Property<?> property : PROPERTIES) {
if(!task.containsValue(property)) {
task = taskDao.fetch(task.getId(), PROPERTIES);
if(task == null)
return;
break;
}
}
@ -121,11 +125,11 @@ public final class ReminderService {
long whenOverdue = calculateNextOverdueReminder(task);
if(whenRandom < whenDueDate && whenRandom < whenOverdue)
createAlarm(task, whenRandom, TYPE_RANDOM);
scheduler.createAlarm(task, whenRandom, TYPE_RANDOM);
else if(whenDueDate < whenOverdue)
createAlarm(task, whenDueDate, TYPE_DUE);
scheduler.createAlarm(task, whenDueDate, TYPE_DUE);
else if(whenOverdue != NO_ALARM)
createAlarm(task, whenOverdue, TYPE_OVERDUE);
scheduler.createAlarm(task, whenOverdue, TYPE_OVERDUE);
}
/**
@ -201,37 +205,55 @@ public final class ReminderService {
// --- alarm manager alarm creation
/**
* Create an alarm for the given task at the given type
*
* @param task
* @param time
* @param type
* @param flags
* Interface for testing
*/
@SuppressWarnings("nls")
static void createAlarm(Task task, long time, byte type) {
if(time == 0 || time == NO_ALARM)
return;
interface AlarmScheduler {
public void createAlarm(Task task, long time, int type);
}
if(time < DateUtilities.now()) {
time = DateUtilities.now() + (long)((0.5f +
4 * random.nextFloat()) * DateUtilities.ONE_HOUR);
}
public void setScheduler(AlarmScheduler scheduler) {
this.scheduler = scheduler;
}
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);
public AlarmScheduler getScheduler() {
return scheduler;
}
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intent, 0);
private class ReminderAlarmScheduler implements AlarmScheduler {
/**
* Create an alarm for the given task at the given type
*
* @param task
* @param time
* @param type
* @param flags
*/
@SuppressWarnings("nls")
public void createAlarm(Task task, long time, int type) {
if(time == 0 || time == NO_ALARM)
return;
if(time < DateUtilities.now()) {
time = DateUtilities.now() + (long)((0.5f +
4 * random.nextFloat()) * DateUtilities.ONE_HOUR);
}
if(Constants.DEBUG)
Log.e("Astrid", "Alarm (" + task.getId() + ", " + type + ") set for " + new Date(time));
am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
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

@ -61,6 +61,14 @@
<item>Next Month</item>
</string-array>
<string-array name="TEA_default_hideUntil">
<!-- hideUntil: default labels for preferences. -->
<item>Don\'t hide</item>
<item>Task is due</item>
<item>Day before due</item>
<item>Week before due</item>
</string-array>
<string-array name="notif_icon_entries">
<!-- Icons for notification tray -->
<item>Pink</item>

@ -144,19 +144,30 @@
<!-- 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">
<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="EPr_default_hideUntil_values">
<!-- hideUntil: labels that map EPr_default_hideUntil items to index in TEA_hideUntil. -->
<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>
<!-- default hide until setting (corresponds to entry in TEA_hideUntil) -->
<string name="p_default_hideUntil_key">p_def_hide</string>
<!-- ============================================================ OTHER == -->
<string name="p_backup">backup</string>

@ -2,91 +2,88 @@
<!-- 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>
<!-- Resources for built-in reminders plug-in -->
<!-- Preference Screen Title -->
<string name="EPr_alerts_header">Reminder Settings</string>
<!-- =============================================== random reminders == -->
<!-- =============================================== 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">
<!-- 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_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="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>
<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>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/rmd_EPr_alerts_header">
android:title="@string/EPr_alerts_header">
<ListPreference
android:key="@string/p_notif_quietStart"

@ -17,19 +17,19 @@ import android.database.Cursor;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.AdapterContextMenuInfo;
import com.flurry.android.FlurryAgent;
import com.timsu.astrid.R;

@ -12,6 +12,7 @@ import android.content.ContentValues;
import android.content.res.Resources;
import com.timsu.astrid.R;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
@ -297,4 +298,11 @@ public final class Task extends AbstractModel {
public boolean getFlag(IntegerProperty property, int flag) {
return (getValue(property) & flag) > 0;
}
/**
* @return repeat data structure. Requires REPEAT
*/
public RepeatInfo getRepeatInfo() {
return RepeatInfo.fromSingleField(getValue(Task.REPEAT));
}
}

@ -4,6 +4,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map.Entry;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.database.Cursor;
@ -100,7 +101,9 @@ public class Astrid2To3UpgradeHelper {
Context context = ContextManager.getContext();
// pop up a progress dialog
ProgressDialog dialog = dialogUtilities.progressDialog(context, context.getString(R.string.DLG_wait));
ProgressDialog dialog = null;
if(context instanceof Activity)
dialog = dialogUtilities.progressDialog(context, context.getString(R.string.DLG_wait));
// initiate a backup
try {
@ -159,7 +162,8 @@ public class Astrid2To3UpgradeHelper {
database.close();
dialog.dismiss();
if(dialog != null)
dialog.dismiss();
}
// --- database upgrade helpers

@ -180,4 +180,14 @@ public class Preferences {
editor.putBoolean(key, value);
editor.commit();
}
/**
* Sets string preference from integer value
*/
public static void setStringFromInteger(int keyResource, int newValue) {
Context context = ContextManager.getContext();
Editor editor = getPrefs(context).edit();
editor.putString(context.getString(keyResource), Integer.toString(newValue));
editor.commit();
}
}

@ -12,9 +12,9 @@ public class TestDependencyInjector implements AbstractDependencyInjector {
* Dependencies this class knows how to handle
*/
private final HashMap<String, Object> injectables = new HashMap<String, Object>();
private String name;
public TestDependencyInjector(String name) {
this.name = name;
}
@ -22,26 +22,43 @@ public class TestDependencyInjector implements AbstractDependencyInjector {
public void addInjectable(String field, Object injection) {
injectables.put(field, injection);
}
public Object getInjection(Object object, Field field) {
if(injectables.containsKey(field.getName())) {
return injectables.get(field.getName());
}
return null;
}
// --- static stuff
/**
* Install TestDependencyInjector above other injectors
*/
public synchronized static TestDependencyInjector initialize(String name) {
ArrayList<AbstractDependencyInjector> list =
deinitialize(name);
ArrayList<AbstractDependencyInjector> list =
new ArrayList<AbstractDependencyInjector>(Arrays.asList(DependencyInjectionService.getInstance().getInjectors()));
TestDependencyInjector instance = new TestDependencyInjector(name);
list.add(0, instance);
DependencyInjectionService.getInstance().setInjectors(list.toArray(new AbstractDependencyInjector[list.size()]));
return instance;
}
/**
* Remove an installed TestDependencyInjector
* @param string
*/
public static void deinitialize(String name) {
ArrayList<AbstractDependencyInjector> list =
new ArrayList<AbstractDependencyInjector>(Arrays.asList(DependencyInjectionService.getInstance().getInjectors()));
for(Iterator<AbstractDependencyInjector> i = list.iterator(); i.hasNext(); ) {
AbstractDependencyInjector injector = i.next();
// if another one of these injectors already exists in the
// stack, remove it
if(injector instanceof TestDependencyInjector) {
@ -49,11 +66,6 @@ public class TestDependencyInjector implements AbstractDependencyInjector {
i.remove();
}
}
TestDependencyInjector instance = new TestDependencyInjector(name);
list.add(0, instance);
DependencyInjectionService.getInstance().setInjectors(list.toArray(new AbstractDependencyInjector[list.size()]));
return instance;
}
}

@ -203,14 +203,24 @@ abstract public class TranslationTests extends TodorooTestCase {
final Resources r = getContext().getResources();
final int[] arrays = getResourceIds(getArrayResources());
final int[] sizes = new int[arrays.length];
final StringBuilder failures = new StringBuilder();
for(int i = 0; i < arrays.length; i++) {
sizes[i] = r.getStringArray(arrays[i]).length;
try {
sizes[i] = r.getStringArray(arrays[i]).length;
} catch (Resources.NotFoundException e) {
String name = r.getResourceName(arrays[i]);
failures.append(String.format("error opening %s: %s\n",
name, e.getMessage()));
sizes[i] = -1;
}
}
final StringBuilder failures = new StringBuilder();
forEachLocale(new Runnable() {
public void run() {
for(int i = 0; i < arrays.length; i++) {
if(sizes[i] == -1)
continue;
int size = r.getStringArray(arrays[i]).length;
if(size != sizes[i]) {
String name = r.getResourceName(arrays[i]);

@ -28,6 +28,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo;
import com.todoroo.astrid.legacy.data.AbstractController;
import com.todoroo.astrid.legacy.data.AbstractModel;
import com.todoroo.astrid.legacy.data.enums.Importance;
@ -354,6 +355,26 @@ public abstract class AbstractTaskModel extends AbstractModel {
public int getValue() {
return value;
}
public static int toSingleField(RepeatInfo repeatInfo) {
int repeat;
if(repeatInfo == null)
repeat = 0;
else
repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) +
repeatInfo.interval.ordinal();
return repeat;
}
public static RepeatInfo fromSingleField(int repeat) {
if(repeat == 0)
return null;
int value = repeat >> REPEAT_VALUE_OFFSET;
RepeatInterval interval = RepeatInterval.values()
[repeat - (value << REPEAT_VALUE_OFFSET)];
return new RepeatInfo(interval, value);
}
}

@ -530,7 +530,6 @@ public class TaskController extends AbstractController {
*/
public TaskController(Context activity) {
super(activity);
Log.e("HEY", "task table is " + tasksTable);
}
/**
@ -547,7 +546,6 @@ public class TaskController extends AbstractController {
SQLiteOpenHelper databaseHelper = new TaskModelDatabaseHelper(
context, tasksTable, tasksTable);
database = databaseHelper.getWritableDatabase();
Log.e("HEY", "task table is " + tasksTable);
}
/** Closes database resource */

@ -22,20 +22,14 @@ public class TaskTests extends DatabaseTestCase {
assertTrue(Task.IMPORTANCE_MUST_DO < Task.IMPORTANCE_SHOULD_DO);
assertTrue(Task.IMPORTANCE_SHOULD_DO < Task.IMPORTANCE_NONE);
ArrayList<Integer> urgencies = new ArrayList<Integer>();
urgencies.add(Task.URGENCY_NONE);
urgencies.add(Task.URGENCY_SPECIFIC_DAY);
urgencies.add(Task.URGENCY_SPECIFIC_DAY_TIME);
urgencies.add(Task.URGENCY_THIS_MONTH);
urgencies.add(Task.URGENCY_THIS_WEEK);
urgencies.add(Task.URGENCY_TODAY);
urgencies.add(Task.URGENCY_WITHIN_A_YEAR);
urgencies.add(Task.URGENCY_WITHIN_SIX_MONTHS);
urgencies.add(Task.URGENCY_WITHIN_THREE_MONTHS);
ArrayList<Integer> reminderFlags = new ArrayList<Integer>();
reminderFlags.add(Task.NOTIFY_AFTER_DEADLINE);
reminderFlags.add(Task.NOTIFY_AT_DEADLINE);
reminderFlags.add(Task.NOTIFY_NONSTOP);
// assert no duplicates
assertEquals(new TreeSet<Integer>(urgencies).size(),
urgencies.size());
assertEquals(new TreeSet<Integer>(reminderFlags).size(),
reminderFlags.size());
}
/** Check defaults */
@ -46,7 +40,6 @@ public class TaskTests extends DatabaseTestCase {
assertTrue(defaults.containsKey(Task.DUE_DATE.name));
assertTrue(defaults.containsKey(Task.HIDE_UNTIL.name));
assertTrue(defaults.containsKey(Task.COMPLETION_DATE.name));
assertTrue(defaults.containsKey(Task.URGENCY.name));
assertTrue(defaults.containsKey(Task.IMPORTANCE.name));
}

@ -0,0 +1,179 @@
package com.todoroo.astrid.reminders;
import java.util.Date;
import android.app.Notification;
import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.NotificationManager;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.test.DatabaseTestCase;
import com.todoroo.astrid.utility.Preferences;
public class NotificationTests extends DatabaseTestCase {
@Autowired
TaskDao taskDao;
public class MutableBoolean {
boolean value = false;
}
/** test that a normal task gets a notification */
public void testAlarmToNotification() {
final Task task = new Task();
task.setValue(Task.TITLE, "rubberduck");
taskDao.persist(task);
final MutableBoolean triggered = new MutableBoolean();
Notifications.setNotificationManager(new TestNotificationManager() {
public void notify(int id, Notification notification) {
assertNotNull(notification.contentIntent);
triggered.value = true;
}
});
Intent intent = new Intent();
intent.putExtra(Notifications.ID_KEY, task.getId());
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_DUE);
new Notifications().onReceive(getContext(), intent);
assertTrue(triggered.value);
}
/** test that a deleted task doesn't get a notification */
public void testDeletedTask() {
final Task task = new Task();
task.setValue(Task.TITLE, "gooeyduck");
task.setValue(Task.DELETION_DATE, DateUtilities.now());
taskDao.persist(task);
Notifications.setNotificationManager(new NotificationManager() {
public void cancel(int id) {
// allowed
}
public void cancelAll() {
fail("wtf cancel all?");
}
public void notify(int id, Notification notification) {
fail("sent a notification, you shouldn't have...");
}
});
Intent intent = new Intent();
intent.putExtra(Notifications.ID_KEY, task.getId());
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_DUE);
new Notifications().onReceive(getContext(), intent);
}
/** test that a completed task doesn't get a notification */
public void testCompletedTask() {
final Task task = new Task();
task.setValue(Task.TITLE, "rubberduck");
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
taskDao.persist(task);
Notifications.setNotificationManager(new NotificationManager() {
public void cancel(int id) {
// allowed
}
public void cancelAll() {
fail("wtf cancel all?");
}
public void notify(int id, Notification notification) {
fail("sent a notification, you shouldn't have...");
}
});
Intent intent = new Intent();
intent.putExtra(Notifications.ID_KEY, task.getId());
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_DUE);
new Notifications().onReceive(getContext(), intent);
}
/** test of quiet hours */
public void testQuietHours() {
final Task task = new Task();
task.setValue(Task.TITLE, "rubberduck");
taskDao.persist(task);
Intent intent = new Intent();
intent.putExtra(Notifications.ID_KEY, task.getId());
int hour = new Date().getHours();
Preferences.setStringFromInteger(R.string.p_notif_quietStart, hour - 1);
Preferences.setStringFromInteger(R.string.p_notif_quietEnd, hour + 1);
// due date notification has vibrate
Notifications.setNotificationManager(new TestNotificationManager() {
public void notify(int id, Notification notification) {
assertNull(notification.sound);
assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
assertNotNull(notification.vibrate);
assertTrue(notification.vibrate.length > 0);
}
});
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_DUE);
new Notifications().onReceive(getContext(), intent);
// random notification does not
Notifications.setNotificationManager(new TestNotificationManager() {
public void notify(int id, Notification notification) {
assertNull(notification.sound);
assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
assertTrue(notification.vibrate == null ||
notification.vibrate.length == 0);
}
});
intent.removeExtra(Notifications.TYPE_KEY);
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_RANDOM);
new Notifications().onReceive(getContext(), intent);
// wrapping works
Preferences.setStringFromInteger(R.string.p_notif_quietStart, hour + 2);
Preferences.setStringFromInteger(R.string.p_notif_quietEnd, hour + 1);
Notifications.setNotificationManager(new TestNotificationManager() {
public void notify(int id, Notification notification) {
assertNull(notification.sound);
assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
}
});
intent.removeExtra(Notifications.TYPE_KEY);
intent.putExtra(Notifications.TYPE_KEY, ReminderService.TYPE_DUE);
new Notifications().onReceive(getContext(), intent);
// nonstop notification still sounds
task.setValue(Task.REMINDER_FLAGS, Task.NOTIFY_NONSTOP);
task.save();
Notifications.setNotificationManager(new TestNotificationManager() {
public void notify(int id, Notification notification) {
assertTrue(notification.sound != null ||
(notification.defaults & Notification.DEFAULT_SOUND) > 0);
}
});
new Notifications().onReceive(getContext(), intent);
}
abstract public class TestNotificationManager implements NotificationManager {
public void cancel(int id) {
fail("wtf cance?");
}
public void cancelAll() {
fail("wtf cancel all?");
}
}
}

@ -0,0 +1,172 @@
package com.todoroo.astrid.reminders;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.model.Task;
import com.todoroo.astrid.reminders.ReminderService.AlarmScheduler;
import com.todoroo.astrid.test.DatabaseTestCase;
import com.todoroo.astrid.utility.Preferences;
public class ReminderServiceTests extends DatabaseTestCase {
ReminderService service;
@Autowired
TaskDao taskDao;
@Override
protected void setUp() throws Exception {
super.setUp();
service = new ReminderService();
Preferences.setPreferenceDefaults();
}
/** tests with no alarms */
public void testNoReminders() {
service.setScheduler(new NoAlarmExpected());
Task task = new Task();
task.setValue(Task.TITLE, "water");
task.setValue(Task.REMINDER_FLAGS, 0);
taskDao.save(task, false);
service.scheduleAlarm(task);
}
/** tests with due date */
public void testDueDates() {
// test due date in the past
service.setScheduler(new NoAlarmExpected());
final Task task = new Task();
task.setValue(Task.TITLE, "water");
task.setValue(Task.DUE_DATE, DateUtilities.now() - DateUtilities.ONE_DAY);
task.setValue(Task.REMINDER_FLAGS, Task.NOTIFY_AT_DEADLINE);
taskDao.save(task, false);
service.scheduleAlarm(task);
// test due date in the future
task.setValue(Task.DUE_DATE, DateUtilities.now() + DateUtilities.ONE_DAY);
taskDao.save(task, false);
service.setScheduler(new AlarmExpected() {
@Override
public void createAlarm(Task task, long time, int type) {
super.createAlarm(task, time, type);
assertEquals((long)task.getValue(Task.DUE_DATE), time);
assertEquals(type, ReminderService.TYPE_DUE);
}
});
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
}
/** tests with random */
public void testRandom() {
// test random
final Task task = new Task();
task.setValue(Task.TITLE, "water");
task.setValue(Task.REMINDER_PERIOD, DateUtilities.ONE_WEEK);
taskDao.save(task, false);
service.setScheduler(new AlarmExpected() {
@Override
public void createAlarm(Task task, long time, int type) {
super.createAlarm(task, time, type);
assertTrue(time > DateUtilities.now());
assertTrue(time < DateUtilities.now() + 1.2 * DateUtilities.ONE_WEEK);
assertEquals(type, ReminderService.TYPE_RANDOM);
}
});
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
// test random with last notify way in the past
task.setValue(Task.REMINDER_LAST, DateUtilities.now() - 2 * DateUtilities.ONE_WEEK);
((AlarmExpected)service.getScheduler()).alarmCreated = false;
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
}
/** tests with overdue */
public void testOverdue() {
// test due date in the future
service.setScheduler(new NoAlarmExpected());
final Task task = new Task();
task.setValue(Task.TITLE, "water");
task.setValue(Task.DUE_DATE, DateUtilities.now() + DateUtilities.ONE_DAY);
task.setValue(Task.REMINDER_FLAGS, Task.NOTIFY_AFTER_DEADLINE);
taskDao.save(task, false);
service.scheduleAlarm(task);
// test due date in the past
task.setValue(Task.DUE_DATE, DateUtilities.now() - DateUtilities.ONE_DAY);
taskDao.save(task, false);
service.setScheduler(new AlarmExpected() {
@Override
public void createAlarm(Task task, long time, int type) {
super.createAlarm(task, time, type);
assertTrue(time > DateUtilities.now());
assertTrue(time < DateUtilities.now() + DateUtilities.ONE_DAY);
assertEquals(type, ReminderService.TYPE_OVERDUE);
}
});
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
}
/** tests with multiple */
public void testMultipleReminders() {
// test due date in the future, enable random
final Task task = new Task();
task.setValue(Task.TITLE, "water");
task.setValue(Task.DUE_DATE, DateUtilities.now() + DateUtilities.ONE_WEEK);
task.setValue(Task.REMINDER_FLAGS, Task.NOTIFY_AT_DEADLINE);
task.setValue(Task.REMINDER_PERIOD, DateUtilities.ONE_DAY);
taskDao.save(task, false);
service.setScheduler(new AlarmExpected() {
@Override
public void createAlarm(Task task, long time, int type) {
super.createAlarm(task, time, type);
assertTrue(time > DateUtilities.now());
assertTrue(time < DateUtilities.now() + DateUtilities.ONE_DAY);
assertEquals(type, ReminderService.TYPE_RANDOM);
}
});
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
// now set the due date in the past
task.setValue(Task.DUE_DATE, DateUtilities.now() - DateUtilities.ONE_WEEK);
((AlarmExpected)service.getScheduler()).alarmCreated = false;
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
// now set the due date before the random
task.setValue(Task.DUE_DATE, DateUtilities.now() + DateUtilities.ONE_HOUR);
taskDao.save(task, false);
service.setScheduler(new AlarmExpected() {
@Override
public void createAlarm(Task task, long time, int type) {
super.createAlarm(task, time, type);
assertEquals((long)task.getValue(Task.DUE_DATE), time);
assertEquals(type, ReminderService.TYPE_DUE);
}
});
service.scheduleAlarm(task);
assertTrue(((AlarmExpected)service.getScheduler()).alarmCreated);
}
// --- helper classes
public class NoAlarmExpected implements AlarmScheduler {
public void createAlarm(Task task, long time, int type) {
fail("created alarm, no alarm expected");
}
}
public class AlarmExpected implements AlarmScheduler {
public boolean alarmCreated = false;
public void createAlarm(Task task, long time, int type) {
alarmCreated = true;
}
}
}

@ -17,12 +17,6 @@ import com.todoroo.astrid.service.AstridDependencyInjector;
*/
public class DatabaseTestCase extends TodorooTestCase {
private static final String SYNC_TEST = "synctest";
private static final String ALERTS_TEST = "alertstest";
private static final String TAG_TASK_TEST = "tagtasktest";
private static final String TAGS_TEST = "tagstest";
private static final String TASKS_TEST = "taskstest";
public static Database database = new TestDatabase();
public AlarmDatabase alarmsDatabase;
@ -32,11 +26,6 @@ public class DatabaseTestCase extends TodorooTestCase {
// initialize test dependency injector
TestDependencyInjector injector = TestDependencyInjector.initialize("db");
injector.addInjectable("tasksTable", TASKS_TEST);
injector.addInjectable("tagsTable", TAGS_TEST);
injector.addInjectable("tagTaskTable", TAG_TASK_TEST);
injector.addInjectable("alertsTable", ALERTS_TEST);
injector.addInjectable("syncTable", SYNC_TEST);
injector.addInjectable("database", database);
}
@ -48,19 +37,15 @@ public class DatabaseTestCase extends TodorooTestCase {
// empty out test databases
database.clear();
deleteDatabase(TASKS_TEST);
deleteDatabase(TAGS_TEST);
deleteDatabase(TAG_TASK_TEST);
deleteDatabase(ALERTS_TEST);
deleteDatabase(SYNC_TEST);
alarmsDatabase = new AlarmDatabase();
alarmsDatabase.clear();
database.openForWriting();
}
private void deleteDatabase(String database) {
/**
* Helper to delete a database by name
* @param database
*/
protected void deleteDatabase(String database) {
File db = getContext().getDatabasePath(database);
if(db.exists())
db.delete();

@ -4,8 +4,10 @@ import java.util.Date;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.TestDependencyInjector;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.alarms.Alarm;
import com.todoroo.astrid.alarms.AlarmDatabase;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.legacy.data.alerts.AlertController;
import com.todoroo.astrid.legacy.data.enums.Importance;
@ -24,20 +26,63 @@ import com.todoroo.astrid.test.DatabaseTestCase;
public class Astrid2To3UpgradeTests extends DatabaseTestCase {
// --- legacy table names
private static final String SYNC_TEST = "synctest";
private static final String ALERTS_TEST = "alertstest";
private static final String TAG_TASK_TEST = "tagtasktest";
private static final String TAGS_TEST = "tagstest";
private static final String TASKS_TEST = "taskstest";
// --- setup and teardnwo
@Autowired
TaskDao taskDao;
@Override
protected void setUp() throws Exception {
super.setUp();
// initialize test dependency injector
TestDependencyInjector injector = TestDependencyInjector.initialize("upgrade");
injector.addInjectable("tasksTable", TASKS_TEST);
injector.addInjectable("tagsTable", TAGS_TEST);
injector.addInjectable("tagTaskTable", TAG_TASK_TEST);
injector.addInjectable("alertsTable", ALERTS_TEST);
injector.addInjectable("syncTable", SYNC_TEST);
injector.addInjectable("database", database);
deleteDatabase(TASKS_TEST);
deleteDatabase(TAGS_TEST);
deleteDatabase(TAG_TASK_TEST);
deleteDatabase(ALERTS_TEST);
deleteDatabase(SYNC_TEST);
alarmsDatabase = new AlarmDatabase();
alarmsDatabase.clear();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
TestDependencyInjector.deinitialize("upgrade");
}
// --- helper methods
public void upgrade2To3() {
new Astrid2To3UpgradeHelper().upgrade2To3();
}
public static void assertDatesEqual(Date old, int newDate) {
public static void assertDatesEqual(Date old, long newDate) {
if(old == null)
assertEquals(0, newDate);
else
assertEquals(old.getTime() / 1000L, newDate);
assertEquals(old.getTime(), newDate);
}
// --- tests
/**
* Test upgrade doesn't crash and burn when there is nothing
*/
@ -78,6 +123,7 @@ public class Astrid2To3UpgradeTests extends DatabaseTestCase {
guti.setHiddenUntil(new Date());
guti.setRepeat(new RepeatInfo(RepeatInterval.DAYS, 10));
guti.setElapsedSeconds(500);
guti.setNotificationIntervalSeconds(200);
taskController.saveTask(guti, false);
Date createdDate = new Date();
@ -96,22 +142,22 @@ public class Astrid2To3UpgradeTests extends DatabaseTestCase {
Task task = new Task(tasks);
assertEquals(griffey.getName(), task.getValue(Task.TITLE));
assertDatesEqual(griffey.getDefiniteDueDate(), task.getValue(Task.DUE_DATE));
assertEquals((Integer)Task.IMPORTANCE_NONE, task.getValue(Task.IMPORTANCE));
assertEquals(Task.IMPORTANCE_NONE, (int)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.REMINDER_LAST));
assertEquals((Integer)0, task.getValue(Task.HIDE_UNTIL));
assertEquals(0, (long)task.getValue(Task.REMINDER_LAST));
assertEquals(0, (long)task.getValue(Task.HIDE_UNTIL));
tasks.moveToNext();
task = new Task(tasks);
assertEquals(guti.getName(), task.getValue(Task.TITLE));
assertDatesEqual(guti.getDefiniteDueDate(), task.getValue(Task.DUE_DATE));
assertDatesEqual(guti.getPreferredDueDate(), task.getValue(Task.PREFERRED_DUE_DATE));
assertDatesEqual(guti.getPreferredDueDate(), task.getValue(Task.DUE_DATE));
assertDatesEqual(guti.getHiddenUntil(), task.getValue(Task.HIDE_UNTIL));
assertEquals((Integer)Task.IMPORTANCE_DO_OR_DIE, task.getValue(Task.IMPORTANCE));
assertEquals(guti.getRepeat().getValue(), task.getRepeatInfo().getValue());
assertEquals(guti.getRepeat().getInterval().ordinal(), task.getRepeatInfo().getInterval().ordinal());
assertEquals(guti.getElapsedSeconds(), task.getValue(Task.ELAPSED_SECONDS));
assertEquals(guti.getNotificationIntervalSeconds() * 1000L, (long)task.getValue(Task.REMINDER_PERIOD));
assertDatesEqual(createdDate, task.getValue(Task.CREATION_DATE));
assertDatesEqual(createdDate, task.getValue(Task.MODIFICATION_DATE));
}
@ -147,7 +193,7 @@ public class Astrid2To3UpgradeTests extends DatabaseTestCase {
// verify that data exists in our new table
database.openForReading();
TagService tagService = new TagService(getContext());
TagService tagService = new TagService();
Tag[] tags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA);
assertEquals(2, tags.length);
assertEquals("salty", tags[0].tag);
@ -201,7 +247,7 @@ public class Astrid2To3UpgradeTests extends DatabaseTestCase {
// verify that data exists in our new table
database.openForReading();
TagService tagService = new TagService(getContext());
TagService tagService = new TagService();
Tag[] tags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA);
assertEquals(1, tags.length);
assertEquals("attached", tags[0].tag);

Loading…
Cancel
Save