RecurrenceSetpublic class RecurrenceSet extends Object Basic information about a recurrence, following RFC 2445 Section 4.8.5.
Contains the RRULEs, RDATE, EXRULEs, and EXDATE properties. |
Fields Summary |
---|
private static final String | TAG | private static final String | RULE_SEPARATOR | public EventRecurrence[] | rrules | public long[] | rdates | public EventRecurrence[] | exrules | public long[] | exdates |
Constructors Summary |
---|
public RecurrenceSet(android.content.ContentValues values)Creates a new RecurrenceSet from information stored in the
events table in the CalendarProvider.
String rruleStr = values.getAsString(Calendar.Events.RRULE);
String rdateStr = values.getAsString(Calendar.Events.RDATE);
String exruleStr = values.getAsString(Calendar.Events.EXRULE);
String exdateStr = values.getAsString(Calendar.Events.EXDATE);
init(rruleStr, rdateStr, exruleStr, exdateStr);
| public RecurrenceSet(android.database.Cursor cursor)Creates a new RecurrenceSet from information stored in a database
{@link Cursor} pointing to the events table in the
CalendarProvider. The cursor must contain the RRULE, RDATE, EXRULE,
and EXDATE columns.
int rruleColumn = cursor.getColumnIndex(Calendar.Events.RRULE);
int rdateColumn = cursor.getColumnIndex(Calendar.Events.RDATE);
int exruleColumn = cursor.getColumnIndex(Calendar.Events.EXRULE);
int exdateColumn = cursor.getColumnIndex(Calendar.Events.EXDATE);
String rruleStr = cursor.getString(rruleColumn);
String rdateStr = cursor.getString(rdateColumn);
String exruleStr = cursor.getString(exruleColumn);
String exdateStr = cursor.getString(exdateColumn);
init(rruleStr, rdateStr, exruleStr, exdateStr);
| public RecurrenceSet(String rruleStr, String rdateStr, String exruleStr, String exdateStr)
init(rruleStr, rdateStr, exruleStr, exdateStr);
|
Methods Summary |
---|
private static void | addPropertiesForRuleStr(ICalendar.Component component, java.lang.String propertyName, java.lang.String ruleStr)
if (TextUtils.isEmpty(ruleStr)) {
return;
}
String[] rrules = ruleStr.split(RULE_SEPARATOR);
for (String rrule : rrules) {
ICalendar.Property prop = new ICalendar.Property(propertyName);
prop.setValue(rrule);
component.addProperty(prop);
}
| private static void | addPropertyForDateStr(ICalendar.Component component, java.lang.String propertyName, java.lang.String dateStr)
if (TextUtils.isEmpty(dateStr)) {
return;
}
ICalendar.Property prop = new ICalendar.Property(propertyName);
String tz = null;
int tzidx = dateStr.indexOf(";");
if (tzidx != -1) {
tz = dateStr.substring(0, tzidx);
dateStr = dateStr.substring(tzidx + 1);
}
if (!TextUtils.isEmpty(tz)) {
prop.addParameter(new ICalendar.Parameter("TZID", tz));
}
prop.setValue(dateStr);
component.addProperty(prop);
| private static java.lang.String | computeDuration(android.text.format.Time start, ICalendar.Component component)
// see if a duration is defined
ICalendar.Property durationProperty =
component.getFirstProperty("DURATION");
if (durationProperty != null) {
// just return the duration
return durationProperty.getValue();
}
// must compute a duration from the DTEND
ICalendar.Property dtendProperty =
component.getFirstProperty("DTEND");
if (dtendProperty == null) {
// no DURATION, no DTEND: 0 second duration
return "+P0S";
}
ICalendar.Parameter endTzidParameter =
dtendProperty.getFirstParameter("TZID");
String endTzid = (endTzidParameter == null)
? start.timezone : endTzidParameter.value;
Time end = new Time(endTzid);
end.parse(dtendProperty.getValue());
long durationMillis = end.toMillis(false /* use isDst */)
- start.toMillis(false /* use isDst */);
long durationSeconds = (durationMillis / 1000);
return "P" + durationSeconds + "S";
| private static java.lang.String | extractDates(ICalendar.Property recurrence)
if (recurrence == null) {
return null;
}
ICalendar.Parameter tzidParam =
recurrence.getFirstParameter("TZID");
if (tzidParam != null) {
return tzidParam.value + ";" + recurrence.getValue();
}
return recurrence.getValue();
| private static java.lang.String | flattenProperties(ICalendar.Component component, java.lang.String name)
List<ICalendar.Property> properties = component.getProperties(name);
if (properties == null || properties.isEmpty()) {
return null;
}
if (properties.size() == 1) {
return properties.get(0).getValue();
}
StringBuilder sb = new StringBuilder();
boolean first = true;
for (ICalendar.Property property : component.getProperties(name)) {
if (first) {
first = false;
} else {
// TODO: use commas. our RECUR parsing should handle that
// anyway.
sb.append(RULE_SEPARATOR);
}
sb.append(property.getValue());
}
return sb.toString();
| public boolean | hasRecurrence()Returns whether or not a recurrence is defined in this RecurrenceSet.
return (rrules != null || rdates != null);
| private void | init(java.lang.String rruleStr, java.lang.String rdateStr, java.lang.String exruleStr, java.lang.String exdateStr)
if (!TextUtils.isEmpty(rruleStr) || !TextUtils.isEmpty(rdateStr)) {
if (!TextUtils.isEmpty(rruleStr)) {
String[] rruleStrs = rruleStr.split(RULE_SEPARATOR);
rrules = new EventRecurrence[rruleStrs.length];
for (int i = 0; i < rruleStrs.length; ++i) {
EventRecurrence rrule = new EventRecurrence();
rrule.parse(rruleStrs[i]);
rrules[i] = rrule;
}
}
if (!TextUtils.isEmpty(rdateStr)) {
rdates = parseRecurrenceDates(rdateStr);
}
if (!TextUtils.isEmpty(exruleStr)) {
String[] exruleStrs = exruleStr.split(RULE_SEPARATOR);
exrules = new EventRecurrence[exruleStrs.length];
for (int i = 0; i < exruleStrs.length; ++i) {
EventRecurrence exrule = new EventRecurrence();
exrule.parse(exruleStr);
exrules[i] = exrule;
}
}
if (!TextUtils.isEmpty(exdateStr)) {
exdates = parseRecurrenceDates(exdateStr);
}
}
| public static long[] | parseRecurrenceDates(java.lang.String recurrence)Parses the provided RDATE or EXDATE string into an array of longs
representing each date/time in the recurrence.
// TODO: use "local" time as the default. will need to handle times
// that end in "z" (UTC time) explicitly at that point.
String tz = Time.TIMEZONE_UTC;
int tzidx = recurrence.indexOf(";");
if (tzidx != -1) {
tz = recurrence.substring(0, tzidx);
recurrence = recurrence.substring(tzidx + 1);
}
Time time = new Time(tz);
String[] rawDates = recurrence.split(",");
int n = rawDates.length;
long[] dates = new long[n];
for (int i = 0; i<n; ++i) {
// The timezone is updated to UTC if the time string specified 'Z'.
time.parse(rawDates[i]);
dates[i] = time.toMillis(false /* use isDst */);
time.timezone = tz;
}
return dates;
| public static boolean | populateComponent(android.database.Cursor cursor, ICalendar.Component component)
int dtstartColumn = cursor.getColumnIndex(Calendar.Events.DTSTART);
int durationColumn = cursor.getColumnIndex(Calendar.Events.DURATION);
int tzidColumn = cursor.getColumnIndex(Calendar.Events.EVENT_TIMEZONE);
int rruleColumn = cursor.getColumnIndex(Calendar.Events.RRULE);
int rdateColumn = cursor.getColumnIndex(Calendar.Events.RDATE);
int exruleColumn = cursor.getColumnIndex(Calendar.Events.EXRULE);
int exdateColumn = cursor.getColumnIndex(Calendar.Events.EXDATE);
int allDayColumn = cursor.getColumnIndex(Calendar.Events.ALL_DAY);
long dtstart = -1;
if (!cursor.isNull(dtstartColumn)) {
dtstart = cursor.getLong(dtstartColumn);
}
String duration = cursor.getString(durationColumn);
String tzid = cursor.getString(tzidColumn);
String rruleStr = cursor.getString(rruleColumn);
String rdateStr = cursor.getString(rdateColumn);
String exruleStr = cursor.getString(exruleColumn);
String exdateStr = cursor.getString(exdateColumn);
boolean allDay = cursor.getInt(allDayColumn) == 1;
if ((dtstart == -1) ||
(TextUtils.isEmpty(duration))||
((TextUtils.isEmpty(rruleStr))&&
(TextUtils.isEmpty(rdateStr)))) {
// no recurrence.
return false;
}
ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
Time dtstartTime = null;
if (!TextUtils.isEmpty(tzid)) {
if (!allDay) {
dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
}
dtstartTime = new Time(tzid);
} else {
// use the "floating" timezone
dtstartTime = new Time(Time.TIMEZONE_UTC);
}
dtstartTime.set(dtstart);
// make sure the time is printed just as a date, if all day.
// TODO: android.pim.Time really should take care of this for us.
if (allDay) {
dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
dtstartTime.allDay = true;
dtstartTime.hour = 0;
dtstartTime.minute = 0;
dtstartTime.second = 0;
}
dtstartProp.setValue(dtstartTime.format2445());
component.addProperty(dtstartProp);
ICalendar.Property durationProp = new ICalendar.Property("DURATION");
durationProp.setValue(duration);
component.addProperty(durationProp);
addPropertiesForRuleStr(component, "RRULE", rruleStr);
addPropertyForDateStr(component, "RDATE", rdateStr);
addPropertiesForRuleStr(component, "EXRULE", exruleStr);
addPropertyForDateStr(component, "EXDATE", exdateStr);
return true;
| public static boolean | populateContentValues(ICalendar.Component component, android.content.ContentValues values)Populates the database map of values with the appropriate RRULE, RDATE,
EXRULE, and EXDATE values extracted from the parsed iCalendar component.
ICalendar.Property dtstartProperty =
component.getFirstProperty("DTSTART");
String dtstart = dtstartProperty.getValue();
ICalendar.Parameter tzidParam =
dtstartProperty.getFirstParameter("TZID");
// NOTE: the timezone may be null, if this is a floating time.
String tzid = tzidParam == null ? null : tzidParam.value;
Time start = new Time(tzidParam == null ? Time.TIMEZONE_UTC : tzid);
boolean inUtc = start.parse(dtstart);
boolean allDay = start.allDay;
if (inUtc) {
tzid = Time.TIMEZONE_UTC;
}
String duration = computeDuration(start, component);
String rrule = flattenProperties(component, "RRULE");
String rdate = extractDates(component.getFirstProperty("RDATE"));
String exrule = flattenProperties(component, "EXRULE");
String exdate = extractDates(component.getFirstProperty("EXDATE"));
if ((TextUtils.isEmpty(dtstart))||
(TextUtils.isEmpty(duration))||
((TextUtils.isEmpty(rrule))&&
(TextUtils.isEmpty(rdate)))) {
if (Config.LOGD) {
Log.d(TAG, "Recurrence missing DTSTART, DTEND/DURATION, "
+ "or RRULE/RDATE: "
+ component.toString());
}
return false;
}
if (allDay) {
// TODO: also change tzid to be UTC? that would be consistent, but
// that would not reflect the original timezone value back to the
// server.
start.timezone = Time.TIMEZONE_UTC;
}
long millis = start.toMillis(false /* use isDst */);
values.put(Calendar.Events.DTSTART, millis);
if (millis == -1) {
if (Config.LOGD) {
Log.d(TAG, "DTSTART is out of range: " + component.toString());
}
return false;
}
values.put(Calendar.Events.RRULE, rrule);
values.put(Calendar.Events.RDATE, rdate);
values.put(Calendar.Events.EXRULE, exrule);
values.put(Calendar.Events.EXDATE, exdate);
values.put(Calendar.Events.EVENT_TIMEZONE, tzid);
values.put(Calendar.Events.DURATION, duration);
values.put(Calendar.Events.ALL_DAY, allDay ? 1 : 0);
return true;
|
|