summaryrefslogtreecommitdiffstats
path: root/core/java/android/pim/EventRecurrence.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/pim/EventRecurrence.java')
-rw-r--r--core/java/android/pim/EventRecurrence.java420
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);
+ }
+ }
+}