diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml
index c68897521..543e3a012 100644
--- a/astrid/AndroidManifest.xml
+++ b/astrid/AndroidManifest.xml
@@ -209,6 +209,12 @@
+
+
+
+
+
+
diff --git a/astrid/plugin-src/com/todoroo/astrid/reminders/NotificationFragment.java b/astrid/plugin-src/com/todoroo/astrid/reminders/NotificationFragment.java
index a4a44cd4b..e4183d6ed 100644
--- a/astrid/plugin-src/com/todoroo/astrid/reminders/NotificationFragment.java
+++ b/astrid/plugin-src/com/todoroo/astrid/reminders/NotificationFragment.java
@@ -43,7 +43,6 @@ import com.todoroo.astrid.activity.DisposableTaskListFragment;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.repeats.RepeatControlSet;
-import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.ui.NumberPicker;
@@ -66,13 +65,6 @@ public class NotificationFragment extends DisposableTaskListFragment implements
private long taskId;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- StartupService.bypassInitialization();
-
- super.onCreate(savedInstanceState);
- }
-
/* (non-Javadoc)
* @see com.todoroo.astrid.activity.TaskListActivity#onActivityCreated(android.os.Bundle)
*/
diff --git a/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementFragment.java b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementFragment.java
new file mode 100644
index 000000000..7eaa44082
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementFragment.java
@@ -0,0 +1,59 @@
+package com.todoroo.astrid.reminders;
+
+import android.content.res.Resources;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.timsu.astrid.R;
+import com.todoroo.astrid.activity.DisposableTaskListFragment;
+import com.todoroo.astrid.service.ThemeService;
+
+public class ReengagementFragment extends DisposableTaskListFragment {
+
+ public static final String EXTRA_TEXT = "dialogText"; //$NON-NLS-1$
+
+ @Override
+ protected void initializeData() {
+ // hide quick add
+ getView().findViewById(R.id.taskListFooter).setVisibility(View.GONE);
+
+ Resources r = getActivity().getResources();
+
+ super.initializeData();
+
+ TextView snooze = (TextView) getView().findViewById(R.id.reminder_snooze);
+ snooze.setBackgroundColor(r.getColor(ThemeService.getThemeColor()));
+ TextView reminder = (TextView) getView().findViewById(R.id.reminder_message);
+ if (taskAdapter.getCount() == 0) {
+ snooze.setText(R.string.rmd_reengage_add_tasks);
+ snooze.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ quickAddBar.performButtonClick();
+ }
+ });
+ } else {
+ snooze.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getActivity().finish();
+ }
+ });
+ }
+
+ reminder.setText(extras.getString(EXTRA_TEXT));
+ }
+
+ @Override
+ protected View getListBody(ViewGroup root) {
+ ViewGroup parent = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.task_list_body_reengagement, root, false);
+
+ View taskListView = super.getListBody(parent);
+ parent.addView(taskListView, 0);
+
+ return parent;
+ }
+
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementReceiver.java b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementReceiver.java
new file mode 100644
index 000000000..68a09b261
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementReceiver.java
@@ -0,0 +1,125 @@
+package com.todoroo.astrid.reminders;
+
+import org.json.JSONObject;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import com.timsu.astrid.R;
+import com.todoroo.andlib.data.TodorooCursor;
+import com.todoroo.andlib.service.Autowired;
+import com.todoroo.andlib.service.DependencyInjectionService;
+import com.todoroo.andlib.service.NotificationManager;
+import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager;
+import com.todoroo.andlib.sql.Query;
+import com.todoroo.andlib.sql.QueryTemplate;
+import com.todoroo.andlib.utility.Preferences;
+import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
+import com.todoroo.astrid.activity.TaskListActivity;
+import com.todoroo.astrid.activity.TaskListFragment;
+import com.todoroo.astrid.api.FilterWithCustomIntent;
+import com.todoroo.astrid.core.SortHelper;
+import com.todoroo.astrid.data.Task;
+import com.todoroo.astrid.data.TaskApiDao.TaskCriteria;
+import com.todoroo.astrid.service.TaskService;
+import com.todoroo.astrid.service.abtesting.ABChooser;
+import com.todoroo.astrid.service.abtesting.ABTests;
+import com.todoroo.astrid.utility.Constants;
+
+public class ReengagementReceiver extends BroadcastReceiver {
+
+ @Autowired ActFmPreferenceService actFmPreferenceService;
+
+ @Autowired TaskService taskService;
+
+ private static final int TASK_LIMIT = 3;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ DependencyInjectionService.getInstance().inject(this);
+ if (ABChooser.readChoiceForTest(ABTests.AB_TEST_REENGAGEMENT_ENABLED) == 0)
+ return;
+
+ int reengagementReminders = Preferences.getInt(ReengagementService.PREF_REENGAGEMENT_COUNT, 1);
+ Preferences.setInt(ReengagementService.PREF_REENGAGEMENT_COUNT, reengagementReminders + 1);
+
+ Intent notifIntent = new Intent(context, TaskListActivity.class);
+
+ QueryTemplate template = new QueryTemplate().where(TaskCriteria.activeVisibleMine());
+ String sql = SortHelper.adjustQueryForFlagsAndSort(template.toString(), 0, SortHelper.SORT_AUTO) + " LIMIT " + TASK_LIMIT; //$NON-NLS-1$
+
+ boolean hasTasks = false;
+ TodorooCursor tasks = taskService.query(Query.select(Task.ID).where(TaskCriteria.activeVisibleMine()).limit(TASK_LIMIT));
+ try {
+ hasTasks = tasks.getCount() > 0;
+ } finally {
+ tasks.close();
+ }
+
+ String title = Notifications.getRandomReminder(context.getResources().getStringArray(R.array.rmd_reengage_notif_titles));
+ if (title.contains("%s")) { //$NON-NLS-1$
+ String name = ""; //$NON-NLS-1$
+ if (actFmPreferenceService.isLoggedIn()) {
+ JSONObject thisUser = ActFmPreferenceService.thisUser();
+ name = thisUser.optString("first_name"); //$NON-NLS-1$
+ if (TextUtils.isEmpty(name))
+ name = thisUser.optString("name"); //$NON-NLS-1$
+ if (TextUtils.isEmpty(name))
+ name = context.getString(R.string.rmd_reengage_name_default);
+ }
+ title = String.format(title, name);
+ }
+
+ String text = Notifications.getRandomReminder(context.getResources().getStringArray(hasTasks ? R.array.rmd_reengage_dialog_options : R.array.rmd_reengage_dialog_empty_options));
+
+ FilterWithCustomIntent filter = new FilterWithCustomIntent(context.getString(R.string.rmd_NoA_filter),
+ context.getString(R.string.rmd_NoA_filter),
+ sql,
+ null);
+ filter.customTaskList = new ComponentName(context, ReengagementFragment.class);
+ filter.customExtras = new Bundle();
+ filter.customExtras.putString(ReengagementFragment.EXTRA_TEXT, text);
+
+ notifIntent.setAction("NOTIFY_reengagement"); //$NON-NLS-1$
+ notifIntent.putExtra(TaskListFragment.TOKEN_FILTER, filter);
+ notifIntent.putExtra(ReengagementFragment.EXTRA_TEXT, text);
+ notifIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ notifIntent.putExtra(TaskListActivity.TOKEN_SOURCE, Constants.SOURCE_REENGAGEMENT);
+
+
+ NotificationManager manager = new AndroidNotificationManager(context);
+ Notification notification = new Notification(R.drawable.notif_astrid,
+ text, System.currentTimeMillis());
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(context,
+ 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ notification.setLatestEventInfo(context,
+ title,
+ text,
+ pendingIntent);
+
+ notification.flags |= Notification.FLAG_AUTO_CANCEL;
+ if(Preferences.getBoolean(R.string.p_rmd_persistent, true)) {
+ notification.flags |= Notification.FLAG_NO_CLEAR |
+ Notification.FLAG_SHOW_LIGHTS;
+ notification.ledOffMS = 5000;
+ notification.ledOnMS = 700;
+ notification.ledARGB = Color.YELLOW;
+ } else {
+ notification.defaults = Notification.DEFAULT_LIGHTS;
+ }
+
+ manager.notify(0, notification);
+
+ ReengagementService.scheduleReengagementAlarm(context);
+ }
+
+}
diff --git a/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementService.java b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementService.java
new file mode 100644
index 000000000..983dc9f9f
--- /dev/null
+++ b/astrid/plugin-src/com/todoroo/astrid/reminders/ReengagementService.java
@@ -0,0 +1,50 @@
+package com.todoroo.astrid.reminders;
+
+import java.util.Date;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import com.todoroo.andlib.utility.DateUtilities;
+import com.todoroo.andlib.utility.Preferences;
+import com.todoroo.astrid.utility.Constants;
+
+public final class ReengagementService {
+
+ private static final int REQUEST_CODE = 10;
+
+ private static final int DAYS_INTERVAL = 2;
+
+ public static final String PREF_REENGAGEMENT_COUNT = "pref_reengagement_count"; //$NON-NLS-1$
+
+ public static final String BROADCAST_SHOW_REENGAGEMENT = Constants.PACKAGE + ".SHOW_REENGAGEMENT"; //$NON-NLS-1$
+
+ public static void scheduleReengagementAlarm(Context context) {
+ AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+ Intent intent = new Intent(BROADCAST_SHOW_REENGAGEMENT);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, 0);
+ am.cancel(pendingIntent);
+
+ long time = getNextReminderTime();
+ am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+
+ private static long getNextReminderTime() {
+ int reengagementReminders = Preferences.getInt(PREF_REENGAGEMENT_COUNT, 1);
+ int days;
+ if (reengagementReminders >= 4)
+ days = DAYS_INTERVAL * 4;
+ else
+ days = DAYS_INTERVAL * reengagementReminders;
+
+ Date date = new Date(DateUtilities.now() + DateUtilities.ONE_DAY * days / 1000L * 1000L);
+ date.setHours(18);
+ date.setMinutes(0);
+ date.setSeconds(0);
+
+ return date.getTime();
+ }
+
+}
diff --git a/astrid/res/drawable-hdpi/speech_bubble_reminder.9.png b/astrid/res/drawable-hdpi/speech_bubble_reminder.9.png
index aa29d212e..50b1902ef 100644
Binary files a/astrid/res/drawable-hdpi/speech_bubble_reminder.9.png and b/astrid/res/drawable-hdpi/speech_bubble_reminder.9.png differ
diff --git a/astrid/res/drawable/speech_bubble_reminder.9.png b/astrid/res/drawable/speech_bubble_reminder.9.png
index aa29d212e..50b1902ef 100644
Binary files a/astrid/res/drawable/speech_bubble_reminder.9.png and b/astrid/res/drawable/speech_bubble_reminder.9.png differ
diff --git a/astrid/res/layout/task_list_body_reengagement.xml b/astrid/res/layout/task_list_body_reengagement.xml
new file mode 100644
index 000000000..f96b95c19
--- /dev/null
+++ b/astrid/res/layout/task_list_body_reengagement.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/astrid/res/values/strings-reminders.xml b/astrid/res/values/strings-reminders.xml
index 4b928404b..6d154f591 100644
--- a/astrid/res/values/strings-reminders.xml
+++ b/astrid/res/values/strings-reminders.xml
@@ -60,6 +60,39 @@
Reminder:
+
+
+
+ - A note from Astrid
+ - Memo for %s.
+ - Your Astrid digest
+ - Reminders from Astrid
+
+
+ you
+
+ Snooze all
+
+ Add a task
+
+
+ - Time to shorten your to-do list!
+ - Dear sir or madam, some tasks await your inspection!
+ - Hi there, could you take a look at these?
+ - I\'ve got some tasks with your name on them!
+ - A fresh batch of tasks for you today!
+ - You look fabulous! Ready to get started?
+ - A lovely day for getting some work done, I think!
+
+
+
+ - Don\'t you want to get organized?
+ - I\'m Astrid! I\'m here to help you do more!
+ - You look busy! Let me take some of those tasks off of your plate.
+ - I can help you keep track of all of the details in your life.
+ - You\'re serious about getting more done? So am I!
+ - Pleasure to make your acquaintance!
+
diff --git a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
index b6f35ed28..13354e243 100644
--- a/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
+++ b/astrid/src/com/todoroo/astrid/activity/TaskListActivity.java
@@ -668,6 +668,8 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
case Constants.SOURCE_C2DM:
StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_C2DM);
break;
+ case Constants.SOURCE_REENGAGEMENT:
+ StatisticsService.reportEvent(StatisticsConstants.LAUNCH_FROM_REENGAGEMENT);
}
getIntent().putExtra(TOKEN_SOURCE, Constants.SOURCE_DEFAULT); // Only report source once
}
diff --git a/astrid/src/com/todoroo/astrid/service/StartupService.java b/astrid/src/com/todoroo/astrid/service/StartupService.java
index 84fbb7c55..81d9a194d 100644
--- a/astrid/src/com/todoroo/astrid/service/StartupService.java
+++ b/astrid/src/com/todoroo/astrid/service/StartupService.java
@@ -40,6 +40,7 @@ import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import com.todoroo.astrid.opencrx.OpencrxCoreUtils;
import com.todoroo.astrid.producteev.ProducteevUtilities;
+import com.todoroo.astrid.reminders.ReengagementService;
import com.todoroo.astrid.reminders.ReminderStartupReceiver;
import com.todoroo.astrid.service.abtesting.ABChooser;
import com.todoroo.astrid.service.abtesting.ABTestInvoker;
@@ -105,6 +106,7 @@ public class StartupService {
if(hasStartedUp || context == null)
return;
+
// sets up context manager
ContextManager.setContext(context);
@@ -193,6 +195,7 @@ public class StartupService {
am.setInexactRepeating(AlarmManager.RTC, 0,
Constants.WIDGET_UPDATE_INTERVAL, pendingIntent);
+ ReengagementService.scheduleReengagementAlarm(context);
taskService.cleanup();
// if sync ongoing flag was set, clear it
diff --git a/astrid/src/com/todoroo/astrid/service/StatisticsConstants.java b/astrid/src/com/todoroo/astrid/service/StatisticsConstants.java
index e8422c244..286bd348a 100644
--- a/astrid/src/com/todoroo/astrid/service/StatisticsConstants.java
+++ b/astrid/src/com/todoroo/astrid/service/StatisticsConstants.java
@@ -24,6 +24,7 @@ public class StatisticsConstants {
public static final String LAUNCH_FROM_PPW = "launch-from-ppw";
public static final String LAUNCH_FROM_WIDGET = "launch-from-widget";
public static final String LAUNCH_FROM_C2DM = "launch-from-c2dm";
+ public static final String LAUNCH_FROM_REENGAGEMENT = "launch-from-reengagement";
public static final String LOCALE_EDIT_ALERTS_NO_PLUGIN = "locale-edit-alerts-no-plugin";
public static final String LOCALE_EDIT_ALERTS = "locale-edit-alerts";
public static final String WIDGET_CONFIG = "widget-config";
diff --git a/astrid/src/com/todoroo/astrid/service/abtesting/ABTests.java b/astrid/src/com/todoroo/astrid/service/abtesting/ABTests.java
index a7386418c..301de6800 100644
--- a/astrid/src/com/todoroo/astrid/service/abtesting/ABTests.java
+++ b/astrid/src/com/todoroo/astrid/service/abtesting/ABTests.java
@@ -115,11 +115,14 @@ public class ABTests {
}
private void initialize() { // Set up
-
addTest(AB_TEST_PRODUCTEEV_ENABLED, new int[] { 1, 1 },
new int[] { 1, 0 }, new String[] { "producteev-disabled", "producteev-enabled" }); //$NON-NLS-1$ //$NON-NLS-2$
+
+ addTest(AB_TEST_REENGAGEMENT_ENABLED, new int[] { 1, 9 },
+ new int[] { 1, 9 }, new String[] { "reengagement-disabled", "reengagement-enabled" }); //$NON-NLS-1$ //$NON-NLS-2$
}
public static final String AB_TEST_PRODUCTEEV_ENABLED = "producteev"; //$NON-NLS-1$
+ public static final String AB_TEST_REENGAGEMENT_ENABLED = "reengagement"; ////$NON-NLS-1$
}
diff --git a/astrid/src/com/todoroo/astrid/utility/Constants.java b/astrid/src/com/todoroo/astrid/utility/Constants.java
index a41431af5..13a2ddc04 100644
--- a/astrid/src/com/todoroo/astrid/utility/Constants.java
+++ b/astrid/src/com/todoroo/astrid/utility/Constants.java
@@ -51,6 +51,7 @@ public final class Constants {
public static final int SOURCE_WIDGET = 2;
public static final int SOURCE_PPWIDGET = 3;
public static final int SOURCE_C2DM = 4;
+ public static final int SOURCE_REENGAGEMENT = 5;
// --- notification id's