Got the alarm stuff working... I think.

pull/14/head
Tim Su 16 years ago
parent 7c317b4b52
commit 4d46900f45

@ -23,7 +23,7 @@
<activity android:name=".activities.TagList"/>
<receiver android:name=".utilities.Notifications">
<receiver android:name=".utilities.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

After

Width:  |  Height:  |  Size: 176 B

@ -207,10 +207,10 @@
</LinearLayout>
<TextView android:id="@+id/blockingon_label"
<!--<TextView android:id="@+id/blockingon_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/importance_label"
android:text="@string/blockingon_label"
style="@style/TextAppearance.EditEvent_Label"/>
<LinearLayout
@ -226,7 +226,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>-->
</LinearLayout>
<!-- MISC FIELDS -->

@ -141,10 +141,15 @@
<string name="tagList_context_create">Create Task With Tag</string>
<string name="tagList_context_edit">Edit Tag</string>
<string name="tagList_context_delete">Delete Tag</string>
<string name="tagList_menu_sortAlpha">Sort A-Z</string>
<string name="tagList_menu_sortSize">Sort by Size</string>
<!-- Dialog Boxes -->
<skip />
<string name="question_title">Question</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="delete_title">Delete</string>
<string name="delete_this_task_title">Delete this task?</string>
@ -152,5 +157,7 @@
<string name="stop_timer_title">Stop the timer?</string>
<string name="alarm_toast_title">Next notification time: </string>
</resources>

@ -58,6 +58,8 @@ public class TagList extends Activity {
private static final int ACTIVITY_LIST = 0;
private static final int ACTIVITY_CREATE = 1;
private static final int MENU_SORT_ALPHA_ID = Menu.FIRST;
private static final int MENU_SORT_SIZE_ID = Menu.FIRST + 1;
private static final int CONTEXT_CREATE_ID = Menu.FIRST + 10;
private static final int CONTEXT_DELETE_ID = Menu.FIRST + 11;
@ -228,4 +230,23 @@ public class TagList extends Activity {
super.onDestroy();
controller.close();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item;
item = menu.add(Menu.NONE, MENU_SORT_ALPHA_ID, Menu.NONE,
R.string.tagList_menu_sortAlpha);
item.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
item.setAlphabeticShortcut('a');
item = menu.add(Menu.NONE, MENU_SORT_SIZE_ID, Menu.NONE,
R.string.tagList_menu_sortSize);
item.setIcon(android.R.drawable.ic_menu_sort_by_size);
item.setAlphabeticShortcut('s');
return true;
}
}

@ -77,7 +77,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
private static final int DELETE_ID = Menu.FIRST + 2;
// activity results
public static final int RESULT_DELETE = RESULT_FIRST_USER;
public static final int RESULT_DELETE = RESULT_FIRST_USER + 10;
// other constants
private static final int MAX_TAGS = 5;
@ -146,7 +146,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
definiteDueDate.setDate(model.getDefiniteDueDate());
preferredDueDate.setDate(model.getPreferredDueDate());
hiddenUntil.setDate(model.getHiddenUntil());
blockingOn.setBlockingOn(model.getBlockingOn());
// blockingOn.setBlockingOn(model.getBlockingOn());
notification.setTimeDuration(model.getNotificationIntervalSeconds());
notes.setText(model.getNotes());
@ -186,7 +186,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
model.setDefiniteDueDate(definiteDueDate.getDate());
model.setPreferredDueDate(preferredDueDate.getDate());
model.setHiddenUntil(hiddenUntil.getDate());
model.setBlockingOn(blockingOn.getBlockingOn());
// model.setBlockingOn(blockingOn.getBlockingOn());
model.setNotes(notes.getText().toString());
model.setNotificationIntervalSeconds(notification.getTimeDurationInSeconds());
@ -198,10 +198,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
Log.e(getClass().getSimpleName(), "Error saving task!", e); // TODO
}
// recompute task visibility
// set up notification
Notifications.scheduleNextNotification(this, model);
Notifications.scheduleNextAlarm(this, model);
}
/** Save task tags. Must be called after task already has an ID */
@ -264,7 +262,7 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
TimeDurationType.HOURS_MINUTES);
notification = new TimeDurationControlSet(this, R.id.notification,
R.string.notification_prefix, R.string.notification_dialog,
TimeDurationType.DAYS_HOURS);
TimeDurationType.HOURS_MINUTES);
definiteDueDate = new DateControlSet(this, R.id.definiteDueDate_notnull,
R.id.definiteDueDate_date, R.id.definiteDueDate_time);
preferredDueDate = new DateControlSet(this, R.id.preferredDueDate_notnull,
@ -272,8 +270,8 @@ public class TaskEdit extends TaskModificationActivity<TaskModelForEdit> {
hiddenUntil = new DateControlSet(this, R.id.hiddenUntil_notnull,
R.id.hiddenUntil_date, R.id.hiddenUntil_time);
notes = (EditText)findViewById(R.id.notes);
blockingOn = new BlockingOnControlSet(R.id.blockingOn_notnull,
R.id.blockingon);
// blockingOn = new BlockingOnControlSet(R.id.blockingOn_notnull,
// R.id.blockingon);
// individual ui component initialization
ImportanceAdapter importanceAdapter = new ImportanceAdapter(this,

@ -59,20 +59,20 @@ import com.timsu.astrid.data.task.TaskModelForList;
public class TaskList extends Activity {
// bundle tokens
public static final String TAG_TOKEN = "tag";
public static final String TAG_TOKEN = "tag";
// activities
private static final int ACTIVITY_CREATE = 0;
private static final int ACTIVITY_VIEW = 1;
private static final int ACTIVITY_EDIT = 2;
private static final int ACTIVITY_TAGS = 3;
private static final int ACTIVITY_CREATE = 0;
private static final int ACTIVITY_VIEW = 1;
private static final int ACTIVITY_EDIT = 2;
private static final int ACTIVITY_TAGS = 3;
// menu codes
private static final int INSERT_ID = Menu.FIRST;
private static final int FILTERS_ID = Menu.FIRST + 1;
private static final int TAGS_ID = Menu.FIRST + 2;
private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20;
private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21;
private static final int INSERT_ID = Menu.FIRST;
private static final int FILTERS_ID = Menu.FIRST + 1;
private static final int TAGS_ID = Menu.FIRST + 2;
private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20;
private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21;
// UI components
private TaskController controller;
@ -175,7 +175,7 @@ public class TaskList extends Activity {
title.append(r.getQuantityString(R.plurals.Ntasks,
taskArray.size(), taskArray.size()));
if(hiddenTasks > 0)
title.append(" (").append(hiddenTasks).append(" ").
title.append(" (+").append(hiddenTasks).append(" ").
append(r.getString(R.string.taskList_hiddenSuffix)).append(")");
setTitle(title);
@ -228,6 +228,12 @@ public class TaskList extends Activity {
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if(resultCode == TaskView.RESULT_DISMISS) {
finish();
return;
}
fillData();
}

@ -61,6 +61,9 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
private static final int EDIT_ID = Menu.FIRST;
private static final int DELETE_ID = Menu.FIRST + 1;
// activity results
public static final int RESULT_DISMISS = RESULT_FIRST_USER + 20;
// UI components
private TextView name;
private TextView elapsed;
@ -105,7 +108,7 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
// clear residual, schedule the next one
Notifications.clearAllNotifications(this, model.getTaskIdentifier());
Notifications.scheduleNextNotification(this, model);
Notifications.scheduleNextAlarm(this, model);
String[] responses = r.getStringArray(R.array.reminder_responses);
String response = responses[new Random().nextInt(responses.length)];
@ -113,8 +116,8 @@ public class TaskView extends TaskModificationActivity<TaskModelForView> {
.setTitle(R.string.taskView_notifyTitle)
.setMessage(response)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes, null)
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
.setPositiveButton(R.string.yes, null)
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setResult(RESULT_CANCELED);

@ -31,6 +31,7 @@ import android.database.sqlite.SQLiteOpenHelper;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper;
import com.timsu.astrid.utilities.Notifications;
/** Controller for task-related operations */
public class TaskController extends AbstractController {
@ -118,6 +119,7 @@ public class TaskController extends AbstractController {
if(taskId == null)
throw new UnsupportedOperationException("Cannot delete uncreated task!");
long id = taskId.getId();
Notifications.deleteAlarm(context, id);
return database.delete(TASK_TABLE_NAME, KEY_ROWID + "=" + id, null) > 0;
}

@ -19,6 +19,8 @@
*/
package com.timsu.astrid.data.task;
import java.util.Date;
import android.database.Cursor;
import com.timsu.astrid.data.AbstractController;
@ -32,6 +34,7 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
static String[] FIELD_LIST = new String[] {
AbstractController.KEY_ROWID,
NOTIFICATIONS,
HIDDEN_UNTIL,
};
// --- constructors
@ -39,6 +42,7 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
public TaskModelForNotify(Cursor cursor) {
super(cursor);
getNotificationIntervalSeconds();
getHiddenUntil();
}
// --- getters and setters
@ -48,4 +52,8 @@ public class TaskModelForNotify extends AbstractTaskModel implements Notifiable
return super.getNotificationIntervalSeconds();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
}

@ -42,6 +42,7 @@ public class TaskModelForView extends AbstractTaskModel implements Notifiable {
TIMER_START,
DEFINITE_DUE_DATE,
PREFERRED_DUE_DATE,
HIDDEN_UNTIL,
CREATION_DATE,
NOTIFICATIONS,
NOTES,
@ -120,6 +121,11 @@ public class TaskModelForView extends AbstractTaskModel implements Notifiable {
return super.getCreationDate();
}
@Override
public Date getHiddenUntil() {
return super.getHiddenUntil();
}
@Override
public void setTimerStart(Date timerStart) {
super.setTimerStart(timerStart);

@ -1,9 +1,11 @@
package com.timsu.astrid.utilities;
import java.util.Date;
import java.util.List;
import java.util.Random;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -21,53 +23,82 @@ import com.timsu.astrid.data.task.TaskModelForNotify;
public class Notifications extends BroadcastReceiver {
private static final int MIN_INTERVAL_SECONDS = 60;
private static final String ID_KEY = "id";
private static final int MIN_INTERVAL_SECONDS = 120;
private static Random random = new Random();
/** Something we can create a notification for */
public interface Notifiable {
public TaskIdentifier getTaskIdentifier();
public Integer getNotificationIntervalSeconds();
public Date getHiddenUntil();
}
@Override
/** Startup intent */
public void onReceive(Context context, Intent intent) {
NotificationManager nm = (NotificationManager) context.
getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(
android.R.drawable.stat_notify_chat, "started up",
System.currentTimeMillis());
long id = intent.getLongExtra(ID_KEY, 0);
Log.e("ALARM", "Alarm triggered id " + id);
showNotification(context, id);
}
nm.notify(0, notification);
// --- alarm manager stuff
public static void scheduleAllAlarms(Context context) {
TaskController controller = new TaskController(context);
controller.open();
List<TaskModelForNotify> tasks = controller.getTasksWithNotifications();
for(TaskModelForNotify task : tasks)
scheduleNextNotification(context, task);
}
public interface Notifiable {
public TaskIdentifier getTaskIdentifier();
public Integer getNotificationIntervalSeconds();
scheduleNextAlarm(context, task);
}
/** Schedules the next notification for this task */
public static void scheduleNextNotification(Context context,
public static void scheduleNextAlarm(Context context,
Notifiable task) {
if(task.getNotificationIntervalSeconds() == null ||
task.getNotificationIntervalSeconds() == 0 ||
task.getTaskIdentifier() == null)
return;
// TODO if task is hidden, disregard
if(task.getHiddenUntil() != null && task.getHiddenUntil().after(new Date()))
return;
// compute, and add a fudge factor to mix things up a bit
int interval = task.getNotificationIntervalSeconds();
int currentSeconds = (int)(System.currentTimeMillis() / 1000);
int untilNextInterval = interval - currentSeconds % interval;
untilNextInterval *= 0.2f + random.nextFloat() * 0.6f;
if(untilNextInterval < MIN_INTERVAL_SECONDS)
untilNextInterval = MIN_INTERVAL_SECONDS;
long when = System.currentTimeMillis() + untilNextInterval * 1000;
scheduleAlarm(context, task.getTaskIdentifier().getId(), when);
}
/** Delete the given alarm */
public static void deleteAlarm(Context context, long id) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// add a fudge factor to mix things up a bit
int nextSeconds = (int)((random.nextFloat() * 0.2f + 0.8f) *
task.getNotificationIntervalSeconds()/60); // TODO remove /60
if(nextSeconds < MIN_INTERVAL_SECONDS)
nextSeconds = MIN_INTERVAL_SECONDS;
long when = System.currentTimeMillis() + nextSeconds * 1000;
scheduleNotification(context, task.getTaskIdentifier(), when);
Intent intent = new Intent(context, Notifications.class);
intent.putExtra(ID_KEY, id);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
am.cancel(sender);
}
/** Schedules a single alarm */
public static void scheduleAlarm(Context context, long id, long when) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Notifications.class);
intent.putExtra(ID_KEY, id);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
Log.e("ALARM", "Alarm set for " + new Date(when));
am.set(AlarmManager.RTC, when, sender);
}
// --- notification manager stuff
/** Clear notifications associated with this application */
public static void clearAllNotifications(Context context, TaskIdentifier taskId) {
@ -77,16 +108,14 @@ public class Notifications extends BroadcastReceiver {
}
/** Schedule a new notification about the given task */
public static void scheduleNotification(Context context,
TaskIdentifier taskId, long when) {
public static void showNotification(Context context, long id) {
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources r = context.getResources();
Intent notifyIntent = new Intent(context, TaskView.class);
notifyIntent.putExtra(TaskView.LOAD_INSTANCE_TOKEN,
taskId.getId());
notifyIntent.putExtra(TaskView.LOAD_INSTANCE_TOKEN, id);
notifyIntent.putExtra(TaskView.FROM_NOTIFICATION_TOKEN, true);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, notifyIntent, PendingIntent.FLAG_ONE_SHOT);
@ -98,7 +127,8 @@ public class Notifications extends BroadcastReceiver {
String reminder = reminders[next];
Notification notification = new Notification(
android.R.drawable.stat_notify_chat, reminder, when);
android.R.drawable.stat_notify_chat, reminder,
System.currentTimeMillis());
notification.setLatestEventInfo(context,
appName,
@ -109,9 +139,8 @@ public class Notifications extends BroadcastReceiver {
notification.vibrate = new long[] { 300, 50, 50, 300, 100, 300, 100,
100, 200 };
Log.w("Notifications", "Logging notification: " + reminder + " for " +
(when - System.currentTimeMillis())/1000 + " seconds from now");
nm.notify((int)taskId.getId(), notification);
Log.w("Notifications", "Logging notification: " + reminder);
nm.notify((int)id, notification);
}
}

@ -0,0 +1,14 @@
package com.timsu.astrid.utilities;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// do nothing...?
}
}

@ -94,8 +94,8 @@ public class NNumberPickerDialog extends AlertDialog implements OnClickListener
if(separators[i].length() < 3)
text.setTextSize(48);
else
text.setTextSize(24);
text.setGravity(Gravity.CENTER_VERTICAL);
text.setTextSize(20);
text.setGravity(Gravity.CENTER);
text.setLayoutParams(sepLayout);
container.addView(text);
}

Loading…
Cancel
Save