source: trunk/hiptop/pester/net/sabi/pester/Alarm.java@ 270

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

Sortable alarm list.

File size: 7.7 KB
Line 
1package net.sabi.pester;
2
3import java.io.ByteArrayInputStream;
4import java.io.ByteArrayOutputStream;
5import java.io.DataInputStream;
6import java.io.DataOutputStream;
7import danger.app.Application;
8import danger.audio.RingToneObject;
9import danger.internal.Date;
10import danger.system.Hardware;
11import danger.text.Collator;
12import danger.util.LocaleUtils;
13import danger.util.StdActiveList;
14import danger.util.StdActiveObject;
15import danger.util.DEBUG;
16import danger.util.format.DateFormat;
17import danger.util.format.StringFormat;
18import java.util.Comparator;
19
20public class Alarm extends StdActiveObject implements Comparator {
21 private static final int VERSION_1 = 1;
22
23 // persisted
24 private String mMessage;
25 private int mType;
26 private int mPeriod;
27 private Date mDate;
28 private RingToneObject mAlert;
29
30 // transient
31 private int mState;
32 private int mAbsoluteFireTime; // only valid if periodic
33 private danger.app.Alarm mAlarm;
34
35 public Alarm() {
36 mState = STATE_INVALID;
37 mAlarm = new danger.app.Alarm(0, Application.getCurrentApp(), this);
38 }
39
40 public String getMessage() {
41 return mMessage;
42 }
43 public int getPeriod() {
44 return mPeriod;
45 }
46 public boolean getUsesPeriod() {
47 return mType != TYPE_DATE;
48 }
49 public boolean getRepeating() {
50 return mType == TYPE_PERIODIC_REPEATING;
51 }
52 public Date getDate() {
53 return mDate;
54 }
55 public RingToneObject getAlert() {
56 return mAlert;
57 }
58
59 public void setMessage(String message) {
60 mMessage = message;
61 }
62 public void setPeriod(int period, boolean repeating) {
63 mType = repeating ? TYPE_PERIODIC_REPEATING : TYPE_PERIODIC;
64 mPeriod = period;
65 }
66 public void setDate(Date date) {
67 mType = TYPE_DATE;
68 mDate = date;
69 }
70 public void setAlert(RingToneObject alert) {
71 mAlert = alert.isValid() ? alert : null;
72 }
73
74 public byte[] toByteArray() {
75 try {
76 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
77 DataOutputStream dataStream = new DataOutputStream(byteStream);
78
79 dataStream.writeByte(VERSION_1);
80 dataStream.writeUTF(mMessage);
81 dataStream.writeInt(mPeriod);
82 dataStream.writeInt(mDate.getUnixTimeGMT());
83 dataStream.writeInt(mType);
84 dataStream.writeInt(mAlert == null ? 0 : mAlert.getID());
85 dataStream.flush();
86 return byteStream.toByteArray();
87 } catch (Exception e) {
88 // XXX do something
89 DEBUG.p("failed to write alarm:" + e);
90 }
91 return null;
92 }
93
94 public void fromByteArray(byte[] data) {
95 try {
96 ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
97 DataInputStream dataStream = new DataInputStream(byteStream);
98
99 byte version = dataStream.readByte();
100 if (version != VERSION_1) {
101 // XXX barf
102 }
103 mMessage = dataStream.readUTF();
104 mPeriod = dataStream.readInt();
105 mDate = new Date(dataStream.readInt());
106 mType = dataStream.readInt();
107 int alertID = dataStream.readInt();
108 mAlert = (alertID == 0 ? null : new RingToneObject(alertID));
109 } catch (Exception e) {
110 // XXX do something
111 DEBUG.p("failed to read alarm:" + e);
112 }
113 }
114
115 void beginEditing() {
116 mState = STATE_EDITING;
117 mAlarm.deactivate();
118 }
119
120 public static int secondsFromNow(Date date) {
121 return date.getDangerTimeGMT() - new Date().getDangerTimeGMT();
122 }
123
124 protected int remainingInterval() {
125 return secondsFromNow(mDate);
126 }
127
128 void resume() {
129 mState = STATE_SCHEDULED;
130 int interval = remainingInterval();
131 if (interval < 0) interval = 0;
132 mAlarm.resetWake(interval);
133 DEBUG.p("resetWake: " + description() + " - " + interval + "s left");
134 update();
135 }
136
137 void timeChanged() {
138 if (mState != STATE_SCHEDULED)
139 return;
140 if (getUsesPeriod()) {
141 int realSecondsLeft = mAbsoluteFireTime - Hardware.getAbsoluteTime();
142 mDate = new Date();
143 mDate.addSeconds(realSecondsLeft < 0 ? 0 : realSecondsLeft);
144 // no need to call resume(): alarm uses absolute time
145 } else {
146 resume();
147 }
148 }
149
150 void schedule() {
151 if (getUsesPeriod()) {
152 mDate = new Date();
153 mDate.addSeconds(mPeriod);
154 mAbsoluteFireTime = Hardware.getAbsoluteTime() + mPeriod;
155 }
156 resume();
157 }
158
159 void dismiss() {
160 if (getRepeating())
161 schedule();
162 else
163 ((StdActiveList)getDelegate()).removeItem(this);
164 }
165
166 void cancel() {
167 mState = STATE_INVALID;
168 mAlarm.deactivate();
169 }
170
171 public String description() {
172 StringBuffer sb = new StringBuffer();
173 switch (mState) {
174 case STATE_INVALID: sb.append("invalid "); break;
175 case STATE_EDITING: sb.append("editing "); break;
176 case STATE_SCHEDULED: sb.append("scheduled "); break;
177 }
178 switch (mType) {
179 case TYPE_PERIODIC:
180 sb.append("periodic (").append(mPeriod).append("s) "); break;
181 case TYPE_PERIODIC_REPEATING:
182 sb.append("repeating periodic (").append(mPeriod).append("s) ");
183 break;
184 case TYPE_DATE:
185 sb.append("date (").append(getDateTimeString()).append(") "); break;
186 }
187 sb.append("alarm: ");
188 sb.append('"').append(mMessage).append('"');
189 return sb.toString();
190 }
191
192 public static String dateTimeString(Date date, boolean relative) {
193 if (date == null)
194 return null;
195 String layout = LocaleUtils.getDateTimePattern();
196 String dateFormat = LocaleUtils.getMediumDateFormat();
197 String dateString;
198 String timeFormat;
199 if (relative) {
200 timeFormat = LocaleUtils.getShortTimeFormat();
201 int daysFromToday = date.getDaysBetween(new Date());
202 if (daysFromToday == 0)
203 dateString = "Today"; // XXX localize
204 else if (daysFromToday == 1)
205 dateString = "Tomorrow"; // XXX localize
206 else if (daysFromToday < 7)
207 dateString = date.getDayString();
208 else
209 dateString = DateFormat.withFormat(dateFormat, date);
210 } else {
211 dateString = DateFormat.withFormat(dateFormat, date);
212 timeFormat = LocaleUtils.getMediumTimeFormat();
213 }
214 String timeString = DateFormat.withFormat(timeFormat, date);
215 return StringFormat.withFormat(layout, timeString, dateString);
216 }
217
218 protected static void addUnit(StringBuffer sb, int n, String unit) {
219 if (n == 0) return;
220 if (sb.length() > 0) sb.append(", ");
221 if (n == 1) sb.append("one ").append(unit);
222 else sb.append(n).append(' ').append(unit).append("s");
223 }
224
225 public static String intervalString(int i) { // XXX localize
226 if (i < 0)
227 return "expired";
228 StringBuffer sb = new StringBuffer();
229 if (i < 60) {
230 addUnit(sb, i, "second");
231 } else {
232 i /= 60; // minutes
233 if (i < 24 * 60) {
234 addUnit(sb, i / 60, "hour");
235 addUnit(sb, i % 60, "minute");
236 } else {
237 i /= 60; // hours
238 if (i < 365) {
239 addUnit(sb, i / 24, "day");
240 addUnit(sb, i % 24, "hour");
241 } else {
242 i /= 24; // days
243 addUnit(sb, i / 365, "year"); // XXX actually 365.242199
244 addUnit(sb, i % 365, "day");
245 }
246 }
247 }
248 return sb.toString();
249 }
250
251 public String getDateTimeString(boolean relative) {
252 return dateTimeString(mDate, relative);
253 }
254
255 public String getDateTimeString() {
256 return getDateTimeString(false);
257 }
258
259 public String getIntervalString() {
260 return intervalString(remainingInterval());
261 }
262
263 public String toString() {
264 return getDateTimeString(true) + " - " + mMessage;
265 }
266
267 public int compare(Object arg0, Object arg1) {
268 Alarm alarm0 = (Alarm)arg0, alarm1 = (Alarm)arg1;
269 int result = alarm0.getDate().compareTo(alarm1.getDate());
270 if (result != 0) return result;
271 result = Collator.getInstance().compare(alarm0.getMessage(),
272 alarm1.getMessage());
273 if (result != 0) return result;
274 return alarm0.hashCode() - alarm1.hashCode();
275 }
276
277 public static final int TYPE_PERIODIC = 0;
278 public static final int TYPE_PERIODIC_REPEATING = 1;
279 public static final int TYPE_DATE = 2;
280
281 public static final int STATE_INVALID = 0;
282 public static final int STATE_EDITING = 1;
283 public static final int STATE_SCHEDULED = 2;
284}
Note: See TracBrowser for help on using the repository browser.