diff options
3 files changed, 167 insertions, 157 deletions
diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java index 09303eee5..9f16738f5 100644 --- a/src/com/android/exchange/utility/CalendarUtilities.java +++ b/src/com/android/exchange/utility/CalendarUtilities.java @@ -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); - } + 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); + } + 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"); - } + 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)); + 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))); - } - } 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 (!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("DTEND", - CalendarUtilities.millisToEasDateTime(startTime + durationMillis)); - } - ics.writeTag("DTSTAMP", CalendarUtilities.millisToEasDateTime(System.currentTimeMillis())); + 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"; - } + 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 + // 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 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); - } + 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 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; - } - 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; + // 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; - } - ics.writeTag(icalTag, "MAILTO:" + organizerEmail); - if (method.equals("REPLY")) { - toList.add(organizerName == null ? new Address(organizerEmail) : - new Address(organizerEmail, 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)); + } } - } - // 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; + // 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); + + 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(); diff --git a/src/com/android/exchange/utility/SimpleIcsWriter.java b/src/com/android/exchange/utility/SimpleIcsWriter.java index 2de9d25c2..fa1d26487 100644 --- a/src/com/android/exchange/utility/SimpleIcsWriter.java +++ b/src/com/android/exchange/utility/SimpleIcsWriter.java @@ -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); diff --git a/tests/src/com/android/exchange/utility/SimpleIcsWriterTests.java b/tests/src/com/android/exchange/utility/SimpleIcsWriterTests.java index aed90ebb3..212627d03 100644 --- a/tests/src/com/android/exchange/utility/SimpleIcsWriterTests.java +++ b/tests/src/com/android/exchange/utility/SimpleIcsWriterTests.java @@ -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()); |
