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 @@ + + + + + + + + + + + + + + + + +