diff options
Diffstat (limited to 'core/java/android/pim/EventRecurrence.java')
-rw-r--r-- | core/java/android/pim/EventRecurrence.java | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/core/java/android/pim/EventRecurrence.java b/core/java/android/pim/EventRecurrence.java new file mode 100644 index 0000000..ad671f6 --- /dev/null +++ b/core/java/android/pim/EventRecurrence.java @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.pim; + +import android.content.res.Resources; +import android.text.TextUtils; + +import java.util.Calendar; + +public class EventRecurrence +{ + /** + * Thrown when a recurrence string provided can not be parsed according + * to RFC2445. + */ + public static class InvalidFormatException extends RuntimeException + { + InvalidFormatException(String s) { + super(s); + } + } + + public EventRecurrence() + { + wkst = MO; + } + + /** + * Parse an iCalendar/RFC2445 recur type according to Section 4.3.10. + */ + public native void parse(String recur); + + public void setStartDate(Time date) { + startDate = date; + } + + public static final int SECONDLY = 1; + public static final int MINUTELY = 2; + public static final int HOURLY = 3; + public static final int DAILY = 4; + public static final int WEEKLY = 5; + public static final int MONTHLY = 6; + public static final int YEARLY = 7; + + public static final int SU = 0x00010000; + public static final int MO = 0x00020000; + public static final int TU = 0x00040000; + public static final int WE = 0x00080000; + public static final int TH = 0x00100000; + public static final int FR = 0x00200000; + public static final int SA = 0x00400000; + + public Time startDate; + public int freq; + public String until; + public int count; + public int interval; + public int wkst; + + public int[] bysecond; + public int bysecondCount; + public int[] byminute; + public int byminuteCount; + public int[] byhour; + public int byhourCount; + public int[] byday; + public int[] bydayNum; + public int bydayCount; + public int[] bymonthday; + public int bymonthdayCount; + public int[] byyearday; + public int byyeardayCount; + public int[] byweekno; + public int byweeknoCount; + public int[] bymonth; + public int bymonthCount; + public int[] bysetpos; + public int bysetposCount; + + /** + * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc. + * constants. btw, I think we should switch to those here too, to + * get rid of this function, if possible. + */ + public static int calendarDay2Day(int day) + { + switch (day) + { + case Calendar.SUNDAY: + return SU; + case Calendar.MONDAY: + return MO; + case Calendar.TUESDAY: + return TU; + case Calendar.WEDNESDAY: + return WE; + case Calendar.THURSDAY: + return TH; + case Calendar.FRIDAY: + return FR; + case Calendar.SATURDAY: + return SA; + default: + throw new RuntimeException("bad day of week: " + day); + } + } + + public static int timeDay2Day(int day) + { + switch (day) + { + case Time.SUNDAY: + return SU; + case Time.MONDAY: + return MO; + case Time.TUESDAY: + return TU; + case Time.WEDNESDAY: + return WE; + case Time.THURSDAY: + return TH; + case Time.FRIDAY: + return FR; + case Time.SATURDAY: + return SA; + default: + throw new RuntimeException("bad day of week: " + day); + } + } + public static int day2TimeDay(int day) + { + switch (day) + { + case SU: + return Time.SUNDAY; + case MO: + return Time.MONDAY; + case TU: + return Time.TUESDAY; + case WE: + return Time.WEDNESDAY; + case TH: + return Time.THURSDAY; + case FR: + return Time.FRIDAY; + case SA: + return Time.SATURDAY; + default: + throw new RuntimeException("bad day of week: " + day); + } + } + + /** + * Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY + * constants. btw, I think we should switch to those here too, to + * get rid of this function, if possible. + */ + public static int day2CalendarDay(int day) + { + switch (day) + { + case SU: + return Calendar.SUNDAY; + case MO: + return Calendar.MONDAY; + case TU: + return Calendar.TUESDAY; + case WE: + return Calendar.WEDNESDAY; + case TH: + return Calendar.THURSDAY; + case FR: + return Calendar.FRIDAY; + case SA: + return Calendar.SATURDAY; + default: + throw new RuntimeException("bad day of week: " + day); + } + } + + /** + * Converts one of the internal day constants (SU, MO, etc.) to the + * two-letter string representing that constant. + * + * @throws IllegalArgumentException Thrown if the day argument is not one of + * the defined day constants. + * + * @param day one the internal constants SU, MO, etc. + * @return the two-letter string for the day ("SU", "MO", etc.) + */ + private static String day2String(int day) { + switch (day) { + case SU: + return "SU"; + case MO: + return "MO"; + case TU: + return "TU"; + case WE: + return "WE"; + case TH: + return "TH"; + case FR: + return "FR"; + case SA: + return "SA"; + default: + throw new IllegalArgumentException("bad day argument: " + day); + } + } + + private static void appendNumbers(StringBuilder s, String label, + int count, int[] values) + { + if (count > 0) { + s.append(label); + count--; + for (int i=0; i<count; i++) { + s.append(values[i]); + s.append(","); + } + s.append(values[count]); + } + } + + private void appendByDay(StringBuilder s, int i) + { + int n = this.bydayNum[i]; + if (n != 0) { + s.append(n); + } + + String str = day2String(this.byday[i]); + s.append(str); + } + + @Override + public String toString() + { + StringBuilder s = new StringBuilder(); + + s.append("FREQ="); + switch (this.freq) + { + case SECONDLY: + s.append("SECONDLY"); + break; + case MINUTELY: + s.append("MINUTELY"); + break; + case HOURLY: + s.append("HOURLY"); + break; + case DAILY: + s.append("DAILY"); + break; + case WEEKLY: + s.append("WEEKLY"); + break; + case MONTHLY: + s.append("MONTHLY"); + break; + case YEARLY: + s.append("YEARLY"); + break; + } + + if (!TextUtils.isEmpty(this.until)) { + s.append(";UNTIL="); + s.append(until); + } + + if (this.count != 0) { + s.append(";COUNT="); + s.append(this.count); + } + + if (this.interval != 0) { + s.append(";INTERVAL="); + s.append(this.interval); + } + + if (this.wkst != 0) { + s.append(";WKST="); + s.append(day2String(this.wkst)); + } + + appendNumbers(s, ";BYSECOND=", this.bysecondCount, this.bysecond); + appendNumbers(s, ";BYMINUTE=", this.byminuteCount, this.byminute); + appendNumbers(s, ";BYSECOND=", this.byhourCount, this.byhour); + + // day + int count = this.bydayCount; + if (count > 0) { + s.append(";BYDAY="); + count--; + for (int i=0; i<count; i++) { + appendByDay(s, i); + s.append(","); + } + appendByDay(s, count); + } + + appendNumbers(s, ";BYMONTHDAY=", this.bymonthdayCount, this.bymonthday); + appendNumbers(s, ";BYYEARDAY=", this.byyeardayCount, this.byyearday); + appendNumbers(s, ";BYWEEKNO=", this.byweeknoCount, this.byweekno); + appendNumbers(s, ";BYMONTH=", this.bymonthCount, this.bymonth); + appendNumbers(s, ";BYSETPOS=", this.bysetposCount, this.bysetpos); + + return s.toString(); + } + + public String getRepeatString() { + Resources r = Resources.getSystem(); + + // TODO Implement "Until" portion of string, as well as custom settings + switch (this.freq) { + case DAILY: + return r.getString(com.android.internal.R.string.daily); + case WEEKLY: { + if (repeatsOnEveryWeekDay()) { + return r.getString(com.android.internal.R.string.every_weekday); + } else { + String format = r.getString(com.android.internal.R.string.weekly); + StringBuilder days = new StringBuilder(); + + // Do one less iteration in the loop so the last element is added out of the + // loop. This is done so the comma is not placed after the last item. + int count = this.bydayCount - 1; + if (count >= 0) { + for (int i = 0 ; i < count ; i++) { + days.append(dayToString(r, this.byday[i])); + days.append(","); + } + days.append(dayToString(r, this.byday[count])); + + return String.format(format, days.toString()); + } + + // There is no "BYDAY" specifier, so use the day of the + // first event. For this to work, the setStartDate() + // method must have been used by the caller to set the + // date of the first event in the recurrence. + if (startDate == null) { + return null; + } + + int day = timeDay2Day(startDate.weekDay); + return String.format(format, dayToString(r, day)); + } + } + case MONTHLY: { + return r.getString(com.android.internal.R.string.monthly); + } + case YEARLY: + return r.getString(com.android.internal.R.string.yearly); + } + + return null; + } + + public boolean repeatsOnEveryWeekDay() { + if (this.freq != WEEKLY) { + return false; + } + + int count = this.bydayCount; + if (count != 5) { + return false; + } + + for (int i = 0 ; i < count ; i++) { + int day = byday[i]; + if (day == SU || day == SA) { + return false; + } + } + + return true; + } + + public boolean repeatsMonthlyOnDayCount() { + if (this.freq != MONTHLY) { + return false; + } + + if (bydayCount != 1 || bymonthdayCount != 0) { + return false; + } + + return true; + } + + private String dayToString(Resources r, int day) { + switch (day) { + case SU: return r.getString(com.android.internal.R.string.sunday); + case MO: return r.getString(com.android.internal.R.string.monday); + case TU: return r.getString(com.android.internal.R.string.tuesday); + case WE: return r.getString(com.android.internal.R.string.wednesday); + case TH: return r.getString(com.android.internal.R.string.thursday); + case FR: return r.getString(com.android.internal.R.string.friday); + case SA: return r.getString(com.android.internal.R.string.saturday); + default: throw new IllegalArgumentException("bad day argument: " + day); + } + } +} |