Merge "Fix bugs in SimpleIcsWriter"
This commit is contained in:
commit
d12bb138b0
|
@ -855,184 +855,191 @@ public class CalendarUtilities {
|
|||
}
|
||||
|
||||
// Create our iCalendar writer and start generating tags
|
||||
SimpleIcsWriter ics = new SimpleIcsWriter();
|
||||
ics.writeTag("BEGIN", "VCALENDAR");
|
||||
ics.writeTag("METHOD", method);
|
||||
ics.writeTag("PRODID", "AndroidEmail");
|
||||
ics.writeTag("VERSION", "2.0");
|
||||
ics.writeTag("BEGIN", "VEVENT");
|
||||
ics.writeTag("CLASS", "PUBLIC");
|
||||
ics.writeTag("STATUS", "CONFIRMED");
|
||||
ics.writeTag("TRANSP", "OPAQUE"); // What Exchange uses
|
||||
ics.writeTag("PRIORITY", "5"); // 1 to 9, 5 = medium
|
||||
ics.writeTag("SEQUENCE", "0");
|
||||
if (uid == null) {
|
||||
uid = entityValues.getAsString(Events._SYNC_LOCAL_ID);
|
||||
}
|
||||
if (uid != null) {
|
||||
ics.writeTag("UID", uid);
|
||||
}
|
||||
|
||||
if (entityValues.containsKey(Events.ALL_DAY)) {
|
||||
Integer ade = entityValues.getAsInteger(Events.ALL_DAY);
|
||||
ics.writeTag("X-MICROSOFT-CDO-ALLDAYEVENT", ade == 0 ? "FALSE" : "TRUE");
|
||||
}
|
||||
|
||||
long startTime = entityValues.getAsLong(Events.DTSTART);
|
||||
ics.writeTag("DTSTART", CalendarUtilities.millisToEasDateTime(startTime));
|
||||
|
||||
if (!entityValues.containsKey(Events.DURATION)) {
|
||||
if (entityValues.containsKey(Events.DTEND)) {
|
||||
ics.writeTag("DTEND", CalendarUtilities.millisToEasDateTime(
|
||||
entityValues.getAsLong(Events.DTEND)));
|
||||
SimpleIcsWriter ics;
|
||||
try {
|
||||
ics = new SimpleIcsWriter();
|
||||
ics.writeTag("BEGIN", "VCALENDAR");
|
||||
ics.writeTag("METHOD", method);
|
||||
ics.writeTag("PRODID", "AndroidEmail");
|
||||
ics.writeTag("VERSION", "2.0");
|
||||
ics.writeTag("BEGIN", "VEVENT");
|
||||
ics.writeTag("CLASS", "PUBLIC");
|
||||
ics.writeTag("STATUS", "CONFIRMED");
|
||||
ics.writeTag("TRANSP", "OPAQUE"); // What Exchange uses
|
||||
ics.writeTag("PRIORITY", "5"); // 1 to 9, 5 = medium
|
||||
ics.writeTag("SEQUENCE", "0");
|
||||
if (uid == null) {
|
||||
uid = entityValues.getAsString(Events._SYNC_LOCAL_ID);
|
||||
}
|
||||
} else {
|
||||
// Convert this into millis and add it to DTSTART for DTEND
|
||||
// We'll use 1 hour as a default
|
||||
long durationMillis = HOURS;
|
||||
Duration duration = new Duration();
|
||||
try {
|
||||
duration.parse(entityValues.getAsString(Events.DURATION));
|
||||
} catch (ParseException e) {
|
||||
// We'll use the default in this case
|
||||
if (uid != null) {
|
||||
ics.writeTag("UID", uid);
|
||||
}
|
||||
ics.writeTag("DTEND",
|
||||
CalendarUtilities.millisToEasDateTime(startTime + durationMillis));
|
||||
}
|
||||
|
||||
ics.writeTag("DTSTAMP", CalendarUtilities.millisToEasDateTime(System.currentTimeMillis()));
|
||||
|
||||
if (entityValues.containsKey(Events.EVENT_LOCATION)) {
|
||||
ics.writeTag("LOCATION", entityValues.getAsString(Events.EVENT_LOCATION));
|
||||
}
|
||||
String title = entityValues.getAsString(Events.TITLE);
|
||||
if (title != null) {
|
||||
ics.writeTag("SUMMARY", title);
|
||||
// TODO Add to strings.xml
|
||||
msg.mSubject = "Invitation" + ": " + title;
|
||||
} else {
|
||||
msg.mSubject = "Invitation";
|
||||
}
|
||||
|
||||
// TODO Handle time zone
|
||||
|
||||
String desc = entityValues.getAsString(Events.DESCRIPTION);
|
||||
if (desc != null) {
|
||||
// TODO Do we need to create something (like we'll do with the email)?
|
||||
ics.writeTag("DESCRIPTION", desc);
|
||||
msg.mText = "Boilerplate" + "\n\n" + desc;
|
||||
} else {
|
||||
msg.mText = "Boilerplate";
|
||||
}
|
||||
|
||||
String rrule = entityValues.getAsString(Events.RRULE);
|
||||
if (rrule != null) {
|
||||
ics.writeTag("RRULE", rrule);
|
||||
}
|
||||
|
||||
// Handle associated data EXCEPT for attendees, which have to be grouped
|
||||
ArrayList<NamedContentValues> subValues = entity.getSubValues();
|
||||
for (NamedContentValues ncv: subValues) {
|
||||
Uri ncvUri = ncv.uri;
|
||||
if (ncvUri.equals(Reminders.CONTENT_URI)) {
|
||||
// TODO Consider sending out alarm information in the meeting request, although
|
||||
// it's not obviously appropriate (i.e. telling the user what alarm to use)
|
||||
// This should be for REQUEST only
|
||||
// Here's what the VALARM would look like:
|
||||
// BEGIN:VALARM
|
||||
// ACTION:DISPLAY
|
||||
// DESCRIPTION:REMINDER
|
||||
// TRIGGER;RELATED=START:-PT15M
|
||||
// END:VALARM
|
||||
if (entityValues.containsKey(Events.ALL_DAY)) {
|
||||
Integer ade = entityValues.getAsInteger(Events.ALL_DAY);
|
||||
ics.writeTag("X-MICROSOFT-CDO-ALLDAYEVENT", ade == 0 ? "FALSE" : "TRUE");
|
||||
}
|
||||
}
|
||||
|
||||
// Handle attendee data here; keep track of organizer and stream it afterward
|
||||
String organizerName = null;
|
||||
String organizerEmail = null;
|
||||
ArrayList<Address> toList = new ArrayList<Address>();
|
||||
for (NamedContentValues ncv: subValues) {
|
||||
Uri ncvUri = ncv.uri;
|
||||
ContentValues ncvValues = ncv.values;
|
||||
if (ncvUri.equals(Attendees.CONTENT_URI)) {
|
||||
Integer relationship =
|
||||
ncvValues.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP);
|
||||
// If there's no relationship, we can't create this for EAS
|
||||
// Similarly, we need an attendee email for each invitee
|
||||
if (relationship != null &&
|
||||
ncvValues.containsKey(Attendees.ATTENDEE_EMAIL)) {
|
||||
// Organizer isn't among attendees in EAS
|
||||
if (relationship == Attendees.RELATIONSHIP_ORGANIZER) {
|
||||
organizerName = ncvValues.getAsString(Attendees.ATTENDEE_NAME);
|
||||
organizerEmail = ncvValues.getAsString(Attendees.ATTENDEE_EMAIL);
|
||||
continue;
|
||||
}
|
||||
String attendeeEmail = ncvValues.getAsString(Attendees.ATTENDEE_EMAIL);
|
||||
String attendeeName = ncvValues.getAsString(Attendees.ATTENDEE_NAME);
|
||||
// This shouldn't be possible, but allow for it
|
||||
if (attendeeEmail == null) continue;
|
||||
long startTime = entityValues.getAsLong(Events.DTSTART);
|
||||
ics.writeTag("DTSTART", CalendarUtilities.millisToEasDateTime(startTime));
|
||||
|
||||
if (messageFlag == Message.FLAG_OUTGOING_MEETING_INVITE) {
|
||||
String icalTag = ICALENDAR_ATTENDEE_INVITE;
|
||||
if (attendeeName != null) {
|
||||
icalTag += ";CN=" + attendeeName;
|
||||
if (!entityValues.containsKey(Events.DURATION)) {
|
||||
if (entityValues.containsKey(Events.DTEND)) {
|
||||
ics.writeTag("DTEND", CalendarUtilities.millisToEasDateTime(
|
||||
entityValues.getAsLong(Events.DTEND)));
|
||||
}
|
||||
} else {
|
||||
// Convert this into millis and add it to DTSTART for DTEND
|
||||
// We'll use 1 hour as a default
|
||||
long durationMillis = HOURS;
|
||||
Duration duration = new Duration();
|
||||
try {
|
||||
duration.parse(entityValues.getAsString(Events.DURATION));
|
||||
} catch (ParseException e) {
|
||||
// We'll use the default in this case
|
||||
}
|
||||
ics.writeTag("DTEND",
|
||||
CalendarUtilities.millisToEasDateTime(startTime + durationMillis));
|
||||
}
|
||||
|
||||
ics.writeTag("DTSTAMP",
|
||||
CalendarUtilities.millisToEasDateTime(System.currentTimeMillis()));
|
||||
|
||||
if (entityValues.containsKey(Events.EVENT_LOCATION)) {
|
||||
ics.writeTag("LOCATION", entityValues.getAsString(Events.EVENT_LOCATION));
|
||||
}
|
||||
String title = entityValues.getAsString(Events.TITLE);
|
||||
if (title != null) {
|
||||
ics.writeTag("SUMMARY", title);
|
||||
// TODO Add to strings.xml
|
||||
msg.mSubject = "Invitation" + ": " + title;
|
||||
} else {
|
||||
msg.mSubject = "Invitation";
|
||||
}
|
||||
|
||||
// TODO Handle time zone
|
||||
|
||||
String desc = entityValues.getAsString(Events.DESCRIPTION);
|
||||
if (desc != null) {
|
||||
// TODO Do we need to create something (like we'll do with the email)?
|
||||
ics.writeTag("DESCRIPTION", desc);
|
||||
msg.mText = "Boilerplate" + "\n\n" + desc;
|
||||
} else {
|
||||
msg.mText = "Boilerplate";
|
||||
}
|
||||
|
||||
String rrule = entityValues.getAsString(Events.RRULE);
|
||||
if (rrule != null) {
|
||||
ics.writeTag("RRULE", rrule);
|
||||
}
|
||||
|
||||
// Handle associated data EXCEPT for attendees, which have to be grouped
|
||||
ArrayList<NamedContentValues> subValues = entity.getSubValues();
|
||||
for (NamedContentValues ncv: subValues) {
|
||||
Uri ncvUri = ncv.uri;
|
||||
if (ncvUri.equals(Reminders.CONTENT_URI)) {
|
||||
// TODO Consider sending out alarm information in the meeting request, although
|
||||
// it's not obviously appropriate (i.e. telling the user what alarm to use)
|
||||
// This should be for REQUEST only
|
||||
// Here's what the VALARM would look like:
|
||||
// BEGIN:VALARM
|
||||
// ACTION:DISPLAY
|
||||
// DESCRIPTION:REMINDER
|
||||
// TRIGGER;RELATED=START:-PT15M
|
||||
// END:VALARM
|
||||
}
|
||||
}
|
||||
|
||||
// Handle attendee data here; keep track of organizer and stream it afterward
|
||||
String organizerName = null;
|
||||
String organizerEmail = null;
|
||||
ArrayList<Address> toList = new ArrayList<Address>();
|
||||
for (NamedContentValues ncv: subValues) {
|
||||
Uri ncvUri = ncv.uri;
|
||||
ContentValues ncvValues = ncv.values;
|
||||
if (ncvUri.equals(Attendees.CONTENT_URI)) {
|
||||
Integer relationship =
|
||||
ncvValues.getAsInteger(Attendees.ATTENDEE_RELATIONSHIP);
|
||||
// If there's no relationship, we can't create this for EAS
|
||||
// Similarly, we need an attendee email for each invitee
|
||||
if (relationship != null &&
|
||||
ncvValues.containsKey(Attendees.ATTENDEE_EMAIL)) {
|
||||
// Organizer isn't among attendees in EAS
|
||||
if (relationship == Attendees.RELATIONSHIP_ORGANIZER) {
|
||||
organizerName = ncvValues.getAsString(Attendees.ATTENDEE_NAME);
|
||||
organizerEmail = ncvValues.getAsString(Attendees.ATTENDEE_EMAIL);
|
||||
continue;
|
||||
}
|
||||
ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
|
||||
toList.add(attendeeName == null ? new Address(attendeeEmail) :
|
||||
new Address(attendeeEmail, attendeeName));
|
||||
} else if (attendeeEmail.equalsIgnoreCase(account.mEmailAddress)) {
|
||||
String icalTag = null;
|
||||
switch (messageFlag) {
|
||||
case Message.FLAG_OUTGOING_MEETING_ACCEPT:
|
||||
icalTag = ICALENDAR_ATTENDEE_ACCEPT;
|
||||
break;
|
||||
case Message.FLAG_OUTGOING_MEETING_DECLINE:
|
||||
icalTag = ICALENDAR_ATTENDEE_DECLINE;
|
||||
break;
|
||||
case Message.FLAG_OUTGOING_MEETING_TENTATIVE:
|
||||
icalTag = ICALENDAR_ATTENDEE_TENTATIVE;
|
||||
break;
|
||||
}
|
||||
if (icalTag != null) {
|
||||
String attendeeEmail = ncvValues.getAsString(Attendees.ATTENDEE_EMAIL);
|
||||
String attendeeName = ncvValues.getAsString(Attendees.ATTENDEE_NAME);
|
||||
// This shouldn't be possible, but allow for it
|
||||
if (attendeeEmail == null) continue;
|
||||
|
||||
if (messageFlag == Message.FLAG_OUTGOING_MEETING_INVITE) {
|
||||
String icalTag = ICALENDAR_ATTENDEE_INVITE;
|
||||
if (attendeeName != null) {
|
||||
icalTag += ";CN=" + attendeeName;
|
||||
}
|
||||
ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
|
||||
toList.add(attendeeName == null ? new Address(attendeeEmail) :
|
||||
new Address(attendeeEmail, attendeeName));
|
||||
} else if (attendeeEmail.equalsIgnoreCase(account.mEmailAddress)) {
|
||||
String icalTag = null;
|
||||
switch (messageFlag) {
|
||||
case Message.FLAG_OUTGOING_MEETING_ACCEPT:
|
||||
icalTag = ICALENDAR_ATTENDEE_ACCEPT;
|
||||
break;
|
||||
case Message.FLAG_OUTGOING_MEETING_DECLINE:
|
||||
icalTag = ICALENDAR_ATTENDEE_DECLINE;
|
||||
break;
|
||||
case Message.FLAG_OUTGOING_MEETING_TENTATIVE:
|
||||
icalTag = ICALENDAR_ATTENDEE_TENTATIVE;
|
||||
break;
|
||||
}
|
||||
if (icalTag != null) {
|
||||
if (attendeeName != null) {
|
||||
icalTag += ";CN=" + attendeeName;
|
||||
}
|
||||
ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the organizer tag for ical
|
||||
if (organizerEmail != null) {
|
||||
String icalTag = "ORGANIZER";
|
||||
// We should be able to find this, assuming the Email is the user's email
|
||||
// TODO Find this in the account
|
||||
if (organizerName != null) {
|
||||
icalTag += ";CN=" + organizerName;
|
||||
// Create the organizer tag for ical
|
||||
if (organizerEmail != null) {
|
||||
String icalTag = "ORGANIZER";
|
||||
// We should be able to find this, assuming the Email is the user's email
|
||||
// TODO Find this in the account
|
||||
if (organizerName != null) {
|
||||
icalTag += ";CN=" + organizerName;
|
||||
}
|
||||
ics.writeTag(icalTag, "MAILTO:" + organizerEmail);
|
||||
if (method.equals("REPLY")) {
|
||||
toList.add(organizerName == null ? new Address(organizerEmail) :
|
||||
new Address(organizerEmail, organizerName));
|
||||
}
|
||||
}
|
||||
ics.writeTag(icalTag, "MAILTO:" + organizerEmail);
|
||||
if (method.equals("REPLY")) {
|
||||
toList.add(organizerName == null ? new Address(organizerEmail) :
|
||||
new Address(organizerEmail, organizerName));
|
||||
|
||||
// If we have no "to" list, we're done
|
||||
if (toList.isEmpty()) return null;
|
||||
// Write out the "to" list
|
||||
Address[] toArray = new Address[toList.size()];
|
||||
int i = 0;
|
||||
for (Address address: toList) {
|
||||
toArray[i++] = address;
|
||||
}
|
||||
}
|
||||
msg.mTo = Address.pack(toArray);
|
||||
|
||||
// If we have no "to" list, we're done
|
||||
if (toList.isEmpty()) return null;
|
||||
// Write out the "to" list
|
||||
Address[] toArray = new Address[toList.size()];
|
||||
int i = 0;
|
||||
for (Address address: toList) {
|
||||
toArray[i++] = address;
|
||||
ics.writeTag("END", "VEVENT");
|
||||
ics.writeTag("END", "VCALENDAR");
|
||||
ics.flush();
|
||||
ics.close();
|
||||
} catch (IOException e) {;;
|
||||
Log.w(TAG, "IOException creating message for Event");
|
||||
return null;
|
||||
}
|
||||
msg.mTo = Address.pack(toArray);
|
||||
|
||||
ics.writeTag("END", "VEVENT");
|
||||
ics.writeTag("END", "VCALENDAR");
|
||||
ics.flush();
|
||||
ics.close();
|
||||
|
||||
// Create the ics attachment using the "content" field
|
||||
Attachment att = new Attachment();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package com.android.exchange.utility;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SimpleIcsWriter extends CharArrayWriter {
|
||||
public static final int MAX_LINE_LENGTH = 75;
|
||||
|
@ -34,12 +35,12 @@ public class SimpleIcsWriter extends CharArrayWriter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(String str) {
|
||||
public void write(String str) throws IOException {
|
||||
int len = str.length();
|
||||
// Handle the simple case here to avoid unnecessary looping
|
||||
if (mLineCount + len < MAX_LINE_LENGTH) {
|
||||
mLineCount += len;
|
||||
write(str);
|
||||
super.write(str);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < len; i++, mLineCount++) {
|
||||
|
@ -53,7 +54,7 @@ public class SimpleIcsWriter extends CharArrayWriter {
|
|||
}
|
||||
}
|
||||
|
||||
public void writeTag(String name, String value) {
|
||||
public void writeTag(String name, String value) throws IOException {
|
||||
write(name);
|
||||
write(":");
|
||||
write(value);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
package com.android.exchange.utility;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
|
@ -35,7 +37,7 @@ public class SimpleIcsWriterTests extends TestCase {
|
|||
private final String expectedSecondLineBreak =
|
||||
string80Chars.charAt(SimpleIcsWriter.MAX_LINE_LENGTH - 1) + SimpleIcsWriter.LINE_BREAK;
|
||||
|
||||
public void testWriter() {
|
||||
public void testWriter() throws IOException {
|
||||
// Sanity test on constant strings
|
||||
assertEquals(63, string63Chars.length());
|
||||
assertEquals(80, string80Chars.length());
|
||||
|
|
Loading…
Reference in New Issue