source: trunk/hiptop/pester/net/sabi/pester/Alarms.java@ 296

Last change on this file since 296 was 296, checked in by Nicholas Riley, 18 years ago

Better alarm debug description, datastore debugging; use absolute fire time for snoozed alarms too; replace the buggy alarm stack and misaligned sleep message with a painfully constructed alert.

File size: 5.6 KB
Line 
1package net.sabi.pester;
2
3import java.util.Comparator;
4import danger.app.Application;
5import danger.app.DataStore;
6import danger.app.Event;
7import danger.app.SettingsDB;
8import danger.app.SettingsDBException;
9import danger.internal.Date;
10import danger.util.StdActiveList;
11import danger.util.DEBUG;
12
13public class Alarms extends StdActiveList {
14 // max # records in a datastore
15 public static final int MAX_ALARM_COUNT = 50;
16
17 private static Alarms sAlarmList = null;
18 private static Listener sListener;
19 private static SettingsDB sSettingsDB;
20
21 private DataStore mDataStore;
22
23 private Alarms() {
24 mDataStore = DataStore.createDataStore("alarms", true /* auto sync */);
25 // register us for Event.EVENT_DATASTORE_RESTORED, which only
26 // seems to be documented at:
27 // <http://developer.danger.com/forum/index.php?t=msg&th=27>
28 mDataStore.setAutoSyncNotifyee(sListener);
29 refreshFromDataStore(false);
30 }
31
32 private void dumpAlarms() { // XXX enable via IPC, make validity checking
33 int i;
34 DEBUG.p("== ALARMS ==");
35 for (i = 0 ; i < size() ; ++i) {
36 DEBUG.p(((Alarm)getItem(i)).description());
37 }
38
39 }
40 private void dumpDatastore() {
41 int i;
42 DEBUG.p("== DATASTORE CONTENTS ==");
43 byte[][] alarmsData = mDataStore.getRecords();
44 for (i = 0 ; i < alarmsData.length ; ++i) {
45 Alarm alarm = new Alarm();
46 alarm.fromByteArray(alarmsData[i]);
47 alarm.setUID(mDataStore.getRecordUID(i));
48 DEBUG.p(alarm.description());
49 }
50 }
51 void refreshFromDataStore(boolean datastoreRestored) {
52 sAlarmList = null;
53 if (datastoreRestored) {
54 DEBUG.p("+++ BEFORE RESOLUTION +++");
55 dumpAlarms();
56 dumpDatastore();
57 }
58 removeAllItems(); // XXX no, we can't do this because some alarms may be (a) in the process of being edited, (b) sitting at expiry, or (c) are periodic or snoozed and need their absolute time preserved. Instead, we should just add all the new records - but what about conflicts?
59 if (datastoreRestored)
60 mDataStore.doneResolvingConflict(); // renumbers on-device records
61 if (datastoreRestored) {
62 DEBUG.p("+++ AFTER RESOLUTION +++");
63 dumpDatastore();
64 }
65 byte[][] alarmsData = mDataStore.getRecords();
66 int i;
67 for (i = 0 ; i < alarmsData.length ; ++i) {
68 Alarm alarm = new Alarm();
69 alarm.fromByteArray(alarmsData[i]);
70 alarm.setUID(mDataStore.getRecordUID(i));
71 insertItemSorted(alarm, alarm);
72 alarm.resume();
73 }
74 try {
75 MessageFinder.setMessageListFromByteArray(sSettingsDB.getBytes(KEY_RECENT_MESSAGES));
76 } catch (SettingsDBException e) {
77 MessageFinder.setDefaultMessageList();
78 }
79 DEBUG.p("+++ AFTER RESTORATION +++");
80 dumpAlarms();
81 dumpDatastore();
82 sAlarmList = this;
83 }
84
85 public static Alarms getList() {
86 if (sAlarmList == null) {
87 sSettingsDB = new SettingsDB("settings", true /* auto sync */);
88 sListener = new Listener();
89 new Alarms();
90 Application.registerForEvent(sListener, Event.EVENT_TIME_CHANGED);
91 }
92 return sAlarmList;
93 }
94
95 public static boolean canCreateAlarm() {
96 return (sAlarmList.size() < MAX_ALARM_COUNT);
97 }
98 public static void addAlarm(Alarm alarm) {
99 sAlarmList.insertItemSorted(alarm, alarm);
100 }
101 public static void removeAlarm(Alarm alarm) {
102 sAlarmList.removeItem(alarm);
103 }
104 public static void recentMessagesChanged() {
105 sSettingsDB.setBytes(KEY_RECENT_MESSAGES,
106 MessageFinder.messageListAsByteArray());
107 }
108
109 protected void onItemAdded(Object item, int index) {
110 if (sAlarmList == null) // restoring from service
111 return;
112 Alarm alarm = (Alarm)item;
113 index = mDataStore.addRecord(alarm.toByteArray());
114 alarm.setUID(mDataStore.getRecordUID(index));
115 DEBUG.p("ADD" + alarm.description());
116 }
117
118 protected void onItemRemoved(Object item, int index) {
119 if (sAlarmList == null) // restoring from service (after hard reset)
120 return;
121 Alarm alarm = (Alarm)item;
122 int uid = alarm.getUID();
123 if (uid == 0)
124 return;
125 mDataStore.removeRecordByUID(uid);
126 if (uid < 0)
127 mDataStore.removeRecordByUID(-uid);
128 DEBUG.p("DEL" + alarm.description());
129 }
130
131 public void onItemUpdated(Object item, int index) {
132 if (sAlarmList == null) // restoring from service
133 return;
134 Alarm alarm = (Alarm)item;
135 mDataStore.setRecordDataByUID(alarm.getUID(), alarm.toByteArray(), true);
136 DEBUG.p("MOD" + alarm.description());
137 }
138
139 private static String KEY_DEFAULT_ALARM = "default alarm";
140 private static String KEY_RECENT_MESSAGES = "recent messages";
141
142 public static Alarm getDefaultAlarm() {
143 Alarm defaultAlarm = new Alarm();
144 try {
145 defaultAlarm.fromByteArray(sSettingsDB.getBytes(KEY_DEFAULT_ALARM));
146 } catch (SettingsDBException e) {
147 defaultAlarm = new Alarm();
148 defaultAlarm.setDate(new Date());
149 defaultAlarm.setPeriod(600, false);
150 }
151 return defaultAlarm;
152 }
153 public static void setDefaultAlarm(Alarm alarm) {
154 sSettingsDB.setBytes(KEY_DEFAULT_ALARM, alarm.toByteArray());
155 }
156
157 static class Listener extends danger.app.Listener
158 implements danger.util.ActiveList.ForEach {
159
160 public void receive(Object item) {
161 ((Alarm)item).timeChanged();
162 }
163
164 public boolean receiveEvent(Event e) {
165 if (e.type == Event.EVENT_TIME_CHANGED) {
166 Alarms.getList().forEach(this);
167 return true;
168 } else if (e.type == Event.EVENT_DATASTORE_RESTORED) {
169 String dbName = (String)e.argument;
170 DEBUG.p("Pester: DATASTORE_RESTORED " + dbName);
171 if (dbName.endsWith("alarms")) {
172 // because we only get/set the default alarm on demand
173 // there's no need to handle conflicts with the settings...
174 // XXX but what happens if we set a (default) alarm, then
175 // the SettingsDB restores?
176 Alarms.getList().refreshFromDataStore(true);
177 }
178 }
179 return super.receiveEvent(e);
180 }
181 }
182}
Note: See TracBrowser for help on using the repository browser.