Task and List notification receivers

pull/281/head
Alex Baker 9 years ago
parent 5af072c9e6
commit 8756099445

@ -68,6 +68,8 @@ public class NotificationTests extends DatabaseTestCase {
taskDao.persist(task);
notifier.triggerTaskNotification(task.getId(), ReminderService.TYPE_DUE);
verify(notificationManager).notify(eq((int) task.getId()), any(Notification.class));
}
public void testDeletedTaskDoesntTriggerNotification() {
@ -99,14 +101,14 @@ public class NotificationTests extends DatabaseTestCase {
// task.setTitle("rubberduck");
// taskDao.persist(task);
// Intent intent = new Intent();
// intent.putExtra(NotificationReceiver.ID_KEY, task.getId());
// intent.putExtra(TaskNotificationReceiver.ID_KEY, task.getId());
//
// int hour = newDate().getHours();
// Preferences.setStringFromInteger(R.string.p_rmd_quietStart, hour - 1);
// Preferences.setStringFromInteger(R.string.p_rmd_quietEnd, hour + 1);
//
// // due date notification has vibrate
// NotificationReceiver.setNotificationManager(new TestNotificationManager() {
// TaskNotificationReceiver.setNotificationManager(new TestNotificationManager() {
// public void notify(int id, Notification notification) {
// assertNull(notification.sound);
// assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
@ -114,11 +116,11 @@ public class NotificationTests extends DatabaseTestCase {
// assertTrue(notification.vibrate.length > 0);
// }
// });
// intent.putExtra(NotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_DUE);
// intent.putExtra(TaskNotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_DUE);
// notificationReceiver.onReceive(getContext(), intent);
//
// // random notification does not
// NotificationReceiver.setNotificationManager(new TestNotificationManager() {
// TaskNotificationReceiver.setNotificationManager(new TestNotificationManager() {
// public void notify(int id, Notification notification) {
// assertNull(notification.sound);
// assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
@ -126,28 +128,28 @@ public class NotificationTests extends DatabaseTestCase {
// notification.vibrate.length == 0);
// }
// });
// intent.removeExtra(NotificationReceiver.EXTRAS_TYPE);
// intent.putExtra(NotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_RANDOM);
// intent.removeExtra(TaskNotificationReceiver.EXTRAS_TYPE);
// intent.putExtra(TaskNotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_RANDOM);
// notificationReceiver.onReceive(getContext(), intent);
//
// // wrapping works
// Preferences.setStringFromInteger(R.string.p_rmd_quietStart, hour + 2);
// Preferences.setStringFromInteger(R.string.p_rmd_quietEnd, hour + 1);
//
// NotificationReceiver.setNotificationManager(new TestNotificationManager() {
// TaskNotificationReceiver.setNotificationManager(new TestNotificationManager() {
// public void notify(int id, Notification notification) {
// assertNull(notification.sound);
// assertTrue((notification.defaults & Notification.DEFAULT_SOUND) == 0);
// }
// });
// intent.removeExtra(NotificationReceiver.EXTRAS_TYPE);
// intent.putExtra(NotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_DUE);
// intent.removeExtra(TaskNotificationReceiver.EXTRAS_TYPE);
// intent.putExtra(TaskNotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_DUE);
// notificationReceiver.onReceive(getContext(), intent);
//
// // nonstop notification still sounds
// task.setReminderFlags(Task.NOTIFY_MODE_NONSTOP);
// taskDao.persist(task);
// NotificationReceiver.setNotificationManager(new TestNotificationManager() {
// TaskNotificationReceiver.setNotificationManager(new TestNotificationManager() {
// public void notify(int id, Notification notification) {
// assertTrue(notification.sound != null ||
// (notification.defaults & Notification.DEFAULT_SOUND) > 0);

@ -1,19 +1,18 @@
package com.todoroo.astrid.reminders;
package org.tasks;
import android.annotation.SuppressLint;
import android.test.AndroidTestCase;
import org.joda.time.DateTime;
import org.tasks.R;
import org.tasks.preferences.Preferences;
import java.util.concurrent.TimeUnit;
import static com.todoroo.astrid.reminders.TaskNotificationIntentService.isQuietHours;
import static org.tasks.Notifier.isQuietHours;
import static org.tasks.Freeze.freezeAt;
import static org.tasks.Freeze.thaw;
public class NotificationReceiverTest extends AndroidTestCase {
public class NotifierTests extends AndroidTestCase {
@SuppressLint("NewApi")
private static final int MILLIS_PER_HOUR = (int) TimeUnit.HOURS.toMillis(1);

@ -233,7 +233,11 @@
<!-- ======================================================= Receivers = -->
<receiver android:name="com.todoroo.astrid.reminders.NotificationReceiver" />
<receiver android:name=".receivers.TaskNotificationReceiver" />
<receiver
android:name=".receivers.ListNotificationReceiver"
android:exported="true" />
<receiver android:name=".receivers.RefreshReceiver" />
@ -543,9 +547,6 @@
<service
android:name=".scheduling.ReminderSchedulerIntentService"
android:exported="false" />
<service
android:name="com.todoroo.astrid.reminders.TaskNotificationIntentService"
android:exported="false" />
<!-- Uses Library -->
<uses-library

@ -22,11 +22,11 @@ import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.reminders.NotificationReceiver;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.service.SynchronizeMetadataCallback;
import org.tasks.injection.ForApplication;
import org.tasks.receivers.TaskNotificationReceiver;
import java.util.ArrayList;
import java.util.HashSet;
@ -130,10 +130,10 @@ public class AlarmService {
}
private PendingIntent pendingIntentForAlarm(Metadata alarm, long taskId) {
Intent intent = new Intent(context, NotificationReceiver.class);
Intent intent = new Intent(context, TaskNotificationReceiver.class);
intent.setAction("ALARM" + alarm.getId()); //$NON-NLS-1$
intent.putExtra(NotificationReceiver.ID_KEY, taskId);
intent.putExtra(NotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_ALARM);
intent.putExtra(TaskNotificationReceiver.ID_KEY, taskId);
intent.putExtra(TaskNotificationReceiver.EXTRAS_TYPE, ReminderService.TYPE_ALARM);
return PendingIntent.getBroadcast(context, (int)alarm.getId(),
intent, PendingIntent.FLAG_UPDATE_CURRENT);

@ -1,26 +0,0 @@
package com.todoroo.astrid.reminders;
import android.content.Context;
import android.content.Intent;
import org.tasks.Notifier;
import org.tasks.injection.InjectingBroadcastReceiver;
import javax.inject.Inject;
public class NotificationReceiver extends InjectingBroadcastReceiver {
public static final String ID_KEY = "id"; //$NON-NLS-1$
public static final String EXTRAS_TYPE = "type"; //$NON-NLS-1$
@Inject Notifier notifier;
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
notifier.triggerTaskNotification(
intent.getLongExtra(ID_KEY, 0),
intent.getIntExtra(EXTRAS_TYPE, (byte) 0));
}
}

@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.TaskNotificationReceiver;
import java.util.Date;
import java.util.Random;
@ -404,11 +405,11 @@ public final class ReminderService {
if(task.getId() == Task.NO_ID) {
return;
}
Intent intent = new Intent(context, NotificationReceiver.class);
Intent intent = new Intent(context, TaskNotificationReceiver.class);
intent.setType(Long.toString(task.getId()));
intent.setAction(Integer.toString(type));
intent.putExtra(NotificationReceiver.ID_KEY, task.getId());
intent.putExtra(NotificationReceiver.EXTRAS_TYPE, type);
intent.putExtra(TaskNotificationReceiver.ID_KEY, task.getId());
intent.putExtra(TaskNotificationReceiver.EXTRAS_TYPE, type);
// calculate the unique requestCode as a combination of the task-id and alarm-type:
// concatenate id+type to keep the combo unique

@ -1,248 +0,0 @@
package com.todoroo.astrid.reminders;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.voice.VoiceOutputAssistant;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.R;
import org.tasks.injection.ForApplication;
import org.tasks.injection.InjectingIntentService;
import org.tasks.notifications.AudioManager;
import org.tasks.notifications.NotificationManager;
import org.tasks.notifications.TelephonyManager;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.CompleteTaskReceiver;
import org.tasks.reminders.SnoozeActivity;
import javax.inject.Inject;
import static org.tasks.date.DateTimeUtils.currentTimeMillis;
/**
* Receives requests to show an Astrid notification if they were not intercepted and handled
* by the in-app reminders in AstridActivity.
*
* @author Sam
*/
public class TaskNotificationIntentService extends InjectingIntentService {
private static final Logger log = LoggerFactory.getLogger(TaskNotificationIntentService.class);
private static long lastNotificationSound = 0L;
/**
* Action name for broadcast intent notifying that task was created from repeating template
*/
public static final String EXTRAS_CUSTOM_INTENT = "intent"; //$NON-NLS-1$
public static final String EXTRAS_NOTIF_ID = "notifId"; //$NON-NLS-1$
/**
* notification type extra
*/
public static final String EXTRAS_TITLE = "title"; //$NON-NLS-1$
public static final String EXTRAS_TEXT = "text"; //$NON-NLS-1$
public static final String EXTRAS_RING_TIMES = "ringTimes"; //$NON-NLS-1$
public static final String EXTRA_TASK_ID = "extra_task_id";
public static final String EXTRAS_TYPE = "type"; //$NON-NLS-1$
@Inject NotificationManager notificationManager;
@Inject TelephonyManager telephonyManager;
@Inject Preferences preferences;
@Inject VoiceOutputAssistant voiceOutputAssistant;
@Inject AudioManager audioManager;
@Inject @ForApplication Context context;
public TaskNotificationIntentService() {
super(TaskNotificationIntentService.class.getSimpleName());
}
@Override
protected void onHandleIntent(Intent intent) {
super.onHandleIntent(intent);
showNotification(
context,
intent.getIntExtra(EXTRAS_NOTIF_ID, 0),
intent.getLongExtra(EXTRA_TASK_ID, 0L),
intent.<PendingIntent>getParcelableExtra(EXTRAS_CUSTOM_INTENT),
intent.getIntExtra(EXTRAS_TYPE, 0),
intent.getStringExtra(EXTRAS_TITLE),
intent.getStringExtra(EXTRAS_TEXT),
intent.getIntExtra(EXTRAS_RING_TIMES, 1));
}
/**
* @return true if notification should sound
*/
private static boolean checkLastNotificationSound() {
long now = DateUtilities.now();
if (now - lastNotificationSound > 10000) {
lastNotificationSound = now;
return true;
}
return false;
}
/**
* @return whether we're in quiet hours
*/
static boolean isQuietHours(Preferences preferences) {
boolean quietHoursEnabled = preferences.quietHoursEnabled();
if (quietHoursEnabled) {
long quietHoursStart = new DateTime().withMillisOfDay(preferences.getInt(R.string.p_rmd_quietStart)).getMillis();
long quietHoursEnd = new DateTime().withMillisOfDay(preferences.getInt(R.string.p_rmd_quietEnd)).getMillis();
long now = currentTimeMillis();
if (quietHoursStart <= quietHoursEnd) {
if (now >= quietHoursStart && now < quietHoursEnd) {
return true;
}
} else { // wrap across 24/hour boundary
if (now >= quietHoursStart || now < quietHoursEnd) {
return true;
}
}
}
return false;
}
/**
* Shows an Astrid notification. Pulls in ring tone and quiet hour settings
* from preferences. You can make it say anything you like.
*
* @param ringTimes number of times to ring (-1 = nonstop)
*/
private void showNotification(Context context, int notificationId, final long taskId, final PendingIntent pendingIntent, int type, String title,
String text, int ringTimes) {
// don't ring multiple times if random reminder
if (type == ReminderService.TYPE_RANDOM) {
ringTimes = 1;
}
// quiet hours? unless alarm clock
boolean quietHours = isQuietHours(preferences);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notif_astrid)
.setTicker(title)
.setWhen(System.currentTimeMillis())
.setContentTitle(title)
.setContentText(text)
.setContentIntent(pendingIntent);
if (preferences.useNotificationActions()) {
PendingIntent completeIntent = PendingIntent.getBroadcast(context, notificationId, new Intent(context, CompleteTaskReceiver.class) {{
putExtra(CompleteTaskReceiver.TASK_ID, taskId);
}}, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent snoozePendingIntent = PendingIntent.getActivity(context, notificationId, new Intent(context, SnoozeActivity.class) {{
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
putExtra(SnoozeActivity.EXTRA_TASK_ID, taskId);
}}, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.ic_check_white_24dp, context.getResources().getString(R.string.rmd_NoA_done), completeIntent)
.addAction(R.drawable.ic_snooze_white_24dp, context.getResources().getString(R.string.rmd_NoA_snooze), snoozePendingIntent);
}
Notification notification = builder.build();
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;
}
boolean voiceReminder = preferences.getBoolean(R.string.p_voiceRemindersEnabled, false);
// if multi-ring is activated and the setting p_rmd_maxvolume allows it, set up the flags for insistent
// notification, and increase the volume to full volume, so the user
// will actually pay attention to the alarm
boolean maxOutVolumeForMultipleRingReminders = preferences.getBoolean(R.string.p_rmd_maxvolume, true);
// remember it to set it to the old value after the alarm
int previousAlarmVolume = audioManager.getAlarmVolume();
if (ringTimes != 1) {
notification.audioStreamType = android.media.AudioManager.STREAM_ALARM;
if (maxOutVolumeForMultipleRingReminders) {
audioManager.setMaxAlarmVolume();
}
// insistent rings until notification is disabled
if (ringTimes < 0) {
notification.flags |= Notification.FLAG_INSISTENT;
voiceReminder = false;
}
} else {
notification.audioStreamType = android.media.AudioManager.STREAM_NOTIFICATION;
}
boolean soundIntervalOk = checkLastNotificationSound();
if (!quietHours && telephonyManager.callStateIdle()) {
String notificationPreference = preferences.getStringValue(R.string.p_rmd_ringtone);
if (audioManager.notificationsMuted()) {
notification.sound = null;
voiceReminder = false;
} else if (notificationPreference != null) {
if (notificationPreference.length() > 0 && soundIntervalOk) {
notification.sound = Uri.parse(notificationPreference);
} else {
notification.sound = null;
}
} else if (soundIntervalOk) {
notification.defaults |= Notification.DEFAULT_SOUND;
}
}
if (preferences.getBoolean(R.string.p_rmd_vibrate, true) && soundIntervalOk) {
notification.vibrate = new long[]{0, 1000, 500, 1000, 500, 1000};
} else {
notification.vibrate = null;
}
if (quietHours || !telephonyManager.callStateIdle()) {
notification.sound = null;
notification.vibrate = null;
voiceReminder = false;
}
for (int i = 0; i < Math.max(ringTimes, 1); i++) {
notificationManager.notify(notificationId, notification);
AndroidUtilities.sleepDeep(500);
}
Flags.set(Flags.REFRESH); // Forces a reload when app launches
if (voiceReminder || maxOutVolumeForMultipleRingReminders) {
AndroidUtilities.sleepDeep(2000);
for (int i = 0; i < 50; i++) {
AndroidUtilities.sleepDeep(500);
if (!audioManager.isRingtoneMode()) {
break;
}
}
try {
// first reset the Alarm-volume to the value before it was eventually maxed out
if (maxOutVolumeForMultipleRingReminders) {
audioManager.setAlarmVolume(previousAlarmVolume);
}
if (voiceReminder) {
voiceOutputAssistant.speak(text);
}
} catch (VerifyError e) {
// unavailable
log.error(e.getMessage(), e);
}
}
}
}

@ -1,46 +1,105 @@
package org.tasks;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.reminders.TaskNotificationIntentService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Flags;
import com.todoroo.astrid.voice.VoiceOutputAssistant;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.injection.ForApplication;
import org.tasks.notifications.AudioManager;
import org.tasks.notifications.NotificationManager;
import org.tasks.notifications.TelephonyManager;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.CompleteTaskReceiver;
import org.tasks.reminders.NotificationActivity;
import org.tasks.reminders.SnoozeActivity;
import javax.inject.Inject;
import static org.tasks.date.DateTimeUtils.currentTimeMillis;
public class Notifier {
private static final Logger log = LoggerFactory.getLogger(Notifier.class);
private Context context;
private TaskDao taskDao;
private NotificationManager notificationManager;
private static long lastNotificationSound = 0L;
private final Context context;
private final TaskDao taskDao;
private final NotificationManager notificationManager;
private final TaskService taskService;
private final TelephonyManager telephonyManager;
private final AudioManager audioManager;
private final VoiceOutputAssistant voiceOutputAssistant;
private Preferences preferences;
@Inject
public Notifier(@ForApplication Context context, TaskDao taskDao, NotificationManager notificationManager) {
public Notifier(@ForApplication Context context, TaskDao taskDao,
NotificationManager notificationManager, TaskService taskService,
TelephonyManager telephonyManager, AudioManager audioManager,
VoiceOutputAssistant voiceOutputAssistant, Preferences preferences) {
this.context = context;
this.taskDao = taskDao;
this.notificationManager = notificationManager;
this.taskService = taskService;
this.telephonyManager = telephonyManager;
this.audioManager = audioManager;
this.voiceOutputAssistant = voiceOutputAssistant;
this.preferences = preferences;
}
public void triggerFilterNotification(String title, String query) {
TodorooCursor<Task> taskTodorooCursor = null;
int count;
try {
taskTodorooCursor = taskService.fetchFiltered(query, null, Task.ID);
if (taskTodorooCursor == null) {
return;
}
count = taskTodorooCursor.getCount();
if (count == 0) {
return;
}
} catch (Exception e) {
log.error(e.getMessage(), e);
return;
} finally {
if (taskTodorooCursor != null) {
taskTodorooCursor.close();
}
}
String subtitle = context.getString(R.string.task_count, count);
showFilterNotification(title, subtitle, query);
}
public void triggerTaskNotification(long id, int type) {
if (!showTaskNotification(id, type)) {
if (!showNotification(id, type)) {
notificationManager.cancel(id);
}
}
private boolean showTaskNotification(final long id, final int type) {
private boolean showNotification(final long id, final int type) {
Task task;
try {
task = taskDao.fetch(id, Task.ID, Task.TITLE, Task.HIDE_UNTIL, Task.COMPLETION_DATE,
@ -66,7 +125,7 @@ public class Notifier {
// it's hidden - don't sound, don't delete
if (task.isHidden() && type == ReminderService.TYPE_RANDOM) {
return true;
return false;
}
// task due date was changed, but alarm wasn't rescheduled
@ -74,7 +133,7 @@ public class Notifier {
!task.hasDueTime() && task.getDueDate() - DateUtilities.now() > DateUtilities.ONE_DAY;
if ((type == ReminderService.TYPE_DUE || type == ReminderService.TYPE_OVERDUE) &&
(!task.hasDueDate() || dueInFuture)) {
return true;
return false;
}
// read properties
@ -96,16 +155,200 @@ public class Notifier {
putExtra(NotificationActivity.EXTRA_TITLE, taskTitle);
}};
context.startService(new Intent(context, TaskNotificationIntentService.class) {{
putExtra(TaskNotificationIntentService.EXTRAS_NOTIF_ID, (int) id);
putExtra(TaskNotificationIntentService.EXTRA_TASK_ID, id);
putExtra(TaskNotificationIntentService.EXTRAS_CUSTOM_INTENT, PendingIntent.getActivity(context, (int) id, intent, PendingIntent.FLAG_UPDATE_CURRENT));
putExtra(TaskNotificationIntentService.EXTRAS_TYPE, type);
putExtra(TaskNotificationIntentService.EXTRAS_TITLE, taskTitle);
putExtra(TaskNotificationIntentService.EXTRAS_TEXT, text);
putExtra(TaskNotificationIntentService.EXTRAS_RING_TIMES, ringTimes);
}});
showTaskNotification(
(int) id,
id,
PendingIntent.getActivity(context, (int) id, intent, PendingIntent.FLAG_UPDATE_CURRENT),
type,
taskTitle,
text,
ringTimes);
return true;
}
private void showFilterNotification(final String title, String subtitle, final String query) {
PendingIntent pendingIntent = PendingIntent.getActivity(context, (title + query).hashCode(), new Intent(context, TaskListActivity.class) {{
setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
putExtra(TaskListActivity.TOKEN_SWITCH_TO_FILTER, new Filter(title, query, null));
}}, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notif_astrid)
.setTicker(title)
.setWhen(System.currentTimeMillis())
.setContentTitle(title)
.setContentText(subtitle)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
Notification notification = builder.build();
activateNotification(1, (title + query).hashCode(), notification, "Poop");
}
/**
* Shows an Astrid notification. Pulls in ring tone and quiet hour settings
* from preferences. You can make it say anything you like.
*
* @param ringTimes number of times to ring (-1 = nonstop)
*/
private void showTaskNotification(int notificationId, final long taskId, final PendingIntent pendingIntent, int type, String title,
String text, int ringTimes) {
// don't ring multiple times if random reminder
if (type == ReminderService.TYPE_RANDOM) {
ringTimes = 1;
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notif_astrid)
.setTicker(title)
.setWhen(System.currentTimeMillis())
.setContentTitle(title)
.setContentText(text)
.setContentIntent(pendingIntent);
if (preferences.useNotificationActions()) {
PendingIntent completeIntent = PendingIntent.getBroadcast(context, notificationId, new Intent(context, CompleteTaskReceiver.class) {{
putExtra(CompleteTaskReceiver.TASK_ID, taskId);
}}, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent snoozePendingIntent = PendingIntent.getActivity(context, notificationId, new Intent(context, SnoozeActivity.class) {{
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
putExtra(SnoozeActivity.EXTRA_TASK_ID, taskId);
}}, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.ic_check_white_24dp, context.getResources().getString(R.string.rmd_NoA_done), completeIntent)
.addAction(R.drawable.ic_snooze_white_24dp, context.getResources().getString(R.string.rmd_NoA_snooze), snoozePendingIntent);
}
Notification notification = builder.build();
activateNotification(ringTimes, notificationId, notification, text);
}
private void activateNotification(int ringTimes, int notificationId, Notification notification, String text) {
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;
}
boolean voiceReminder = preferences.getBoolean(R.string.p_voiceRemindersEnabled, false);
// if multi-ring is activated and the setting p_rmd_maxvolume allows it, set up the flags for insistent
// notification, and increase the volume to full volume, so the user
// will actually pay attention to the alarm
boolean maxOutVolumeForMultipleRingReminders = preferences.getBoolean(R.string.p_rmd_maxvolume, true);
// remember it to set it to the old value after the alarm
int previousAlarmVolume = audioManager.getAlarmVolume();
if (ringTimes != 1) {
notification.audioStreamType = android.media.AudioManager.STREAM_ALARM;
if (maxOutVolumeForMultipleRingReminders) {
audioManager.setMaxAlarmVolume();
}
// insistent rings until notification is disabled
if (ringTimes < 0) {
notification.flags |= Notification.FLAG_INSISTENT;
voiceReminder = false;
}
} else {
notification.audioStreamType = android.media.AudioManager.STREAM_NOTIFICATION;
}
boolean soundIntervalOk = checkLastNotificationSound();
if (!isQuietHours(preferences) && telephonyManager.callStateIdle()) {
String notificationPreference = preferences.getStringValue(R.string.p_rmd_ringtone);
if (audioManager.notificationsMuted()) {
notification.sound = null;
voiceReminder = false;
} else if (notificationPreference != null) {
if (notificationPreference.length() > 0 && soundIntervalOk) {
notification.sound = Uri.parse(notificationPreference);
} else {
notification.sound = null;
}
} else if (soundIntervalOk) {
notification.defaults |= Notification.DEFAULT_SOUND;
}
}
if (preferences.getBoolean(R.string.p_rmd_vibrate, true) && soundIntervalOk) {
notification.vibrate = new long[]{0, 1000, 500, 1000, 500, 1000};
} else {
notification.vibrate = null;
}
if (isQuietHours(preferences) || !telephonyManager.callStateIdle()) {
notification.sound = null;
notification.vibrate = null;
voiceReminder = false;
}
for (int i = 0; i < Math.max(ringTimes, 1); i++) {
notificationManager.notify(notificationId, notification);
AndroidUtilities.sleepDeep(500);
}
Flags.set(Flags.REFRESH); // Forces a reload when app launches
if (voiceReminder || maxOutVolumeForMultipleRingReminders) {
AndroidUtilities.sleepDeep(2000);
for (int i = 0; i < 50; i++) {
AndroidUtilities.sleepDeep(500);
if (!audioManager.isRingtoneMode()) {
break;
}
}
try {
// first reset the Alarm-volume to the value before it was eventually maxed out
if (maxOutVolumeForMultipleRingReminders) {
audioManager.setAlarmVolume(previousAlarmVolume);
}
if (voiceReminder) {
voiceOutputAssistant.speak(text);
}
} catch (VerifyError e) {
// unavailable
log.error(e.getMessage(), e);
}
}
}
/**
* @return true if notification should sound
*/
private static boolean checkLastNotificationSound() {
long now = DateUtilities.now();
if (now - lastNotificationSound > 10000) {
lastNotificationSound = now;
return true;
}
return false;
}
/**
* @return whether we're in quiet hours
*/
static boolean isQuietHours(Preferences preferences) {
boolean quietHoursEnabled = preferences.quietHoursEnabled();
if (quietHoursEnabled) {
long quietHoursStart = new DateTime().withMillisOfDay(preferences.getInt(R.string.p_rmd_quietStart)).getMillis();
long quietHoursEnd = new DateTime().withMillisOfDay(preferences.getInt(R.string.p_rmd_quietEnd)).getMillis();
long now = currentTimeMillis();
if (quietHoursStart <= quietHoursEnd) {
if (now >= quietHoursStart && now < quietHoursEnd) {
return true;
}
} else { // wrap across 24/hour boundary
if (now >= quietHoursStart || now < quietHoursEnd) {
return true;
}
}
}
return false;
}
}

@ -6,7 +6,6 @@ import com.todoroo.astrid.gcal.CalendarAlarmReceiver;
import com.todoroo.astrid.gcal.CalendarStartupReceiver;
import com.todoroo.astrid.gcal.GCalTaskCompleteListener;
import com.todoroo.astrid.gtasks.GtasksCustomFilterCriteriaExposer;
import com.todoroo.astrid.reminders.NotificationReceiver;
import com.todoroo.astrid.repeats.RepeatTaskCompleteListener;
import com.todoroo.astrid.tags.TagCustomFilterCriteriaExposer;
import com.todoroo.astrid.timers.TimerTaskCompleteListener;
@ -15,17 +14,20 @@ import com.todoroo.astrid.widget.TasksWidget;
import org.tasks.receivers.BootCompletedReceiver;
import org.tasks.receivers.CompleteTaskReceiver;
import org.tasks.receivers.FirstLaunchReceiver;
import org.tasks.receivers.ListNotificationReceiver;
import org.tasks.receivers.MyPackageReplacedReceiver;
import org.tasks.receivers.PackageReplacedReceiver;
import org.tasks.receivers.RefreshReceiver;
import org.tasks.receivers.RepeatConfirmationReceiver;
import org.tasks.receivers.TaskNotificationReceiver;
import dagger.Module;
@Module(addsTo = TasksModule.class,
injects = {
TasksWidget.class,
NotificationReceiver.class,
TaskNotificationReceiver.class,
ListNotificationReceiver.class,
GtasksCustomFilterCriteriaExposer.class,
TagCustomFilterCriteriaExposer.class,
GCalTaskCompleteListener.class,

@ -1,7 +1,5 @@
package org.tasks.injection;
import com.todoroo.astrid.reminders.TaskNotificationIntentService;
import org.tasks.location.GeofenceTransitionsIntentService;
import org.tasks.scheduling.*;
@ -15,8 +13,7 @@ import dagger.Module;
MidnightRefreshService.class,
RefreshSchedulerIntentService.class,
ReminderSchedulerIntentService.class,
GeofenceTransitionsIntentService.class,
TaskNotificationIntentService.class
GeofenceTransitionsIntentService.class
})
public class IntentServiceModule {
}

@ -1,6 +1,5 @@
package org.tasks.intents;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

@ -0,0 +1,42 @@
package org.tasks.receivers;
import android.content.Context;
import android.content.Intent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.Notifier;
import org.tasks.injection.InjectingBroadcastReceiver;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
public class ListNotificationReceiver extends InjectingBroadcastReceiver {
private static final Logger log = LoggerFactory.getLogger(ListNotificationReceiver.class);
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static final String EXTRA_FILTER_TITLE = "extra_filter_title";
public static final String EXTRA_FILTER_QUERY = "extra_filter_query";
@Inject Notifier notifier;
@Override
public void onReceive(Context context, final Intent intent) {
super.onReceive(context, intent);
log.info("onReceive({}, {}", context, intent);
executorService.execute(new Runnable() {
@Override
public void run() {
notifier.triggerFilterNotification(
intent.getStringExtra(EXTRA_FILTER_TITLE),
intent.getStringExtra(EXTRA_FILTER_QUERY));
}
});
}
}

@ -0,0 +1,36 @@
package org.tasks.receivers;
import android.content.Context;
import android.content.Intent;
import org.tasks.Notifier;
import org.tasks.injection.InjectingBroadcastReceiver;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
public class TaskNotificationReceiver extends InjectingBroadcastReceiver {
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static final String ID_KEY = "id"; //$NON-NLS-1$
public static final String EXTRAS_TYPE = "type"; //$NON-NLS-1$
@Inject Notifier notifier;
@Override
public void onReceive(Context context, final Intent intent) {
super.onReceive(context, intent);
executorService.execute(new Runnable() {
@Override
public void run() {
notifier.triggerTaskNotification(
intent.getLongExtra(ID_KEY, 0),
intent.getIntExtra(EXTRAS_TYPE, (byte) 0));
}
});
}
}

@ -124,6 +124,7 @@
<string name="show_hidden">Show hidden</string>
<string name="show_completed">Show completed</string>
<string name="reverse">Reverse</string>
<string name="task_count">%s Tasks</string>
<string-array name="sync_SPr_interval_entries">
<!-- sync_SPr_interval_entries: Synchronization Intervals -->

Loading…
Cancel
Save