Add support for syncing the favorite flag to server (EAS 12.0 and up)

* Add test for date formatting
This commit is contained in:
Marc Blank 2009-08-17 14:07:47 -07:00
parent 3479356779
commit cc8d74bd03
5 changed files with 176 additions and 21 deletions

View File

@ -1311,8 +1311,10 @@ public class SyncManager extends Service implements Runnable {
INSTANCE.notify();
}
}
synchronized (sConnectivityLock) {
sConnectivityLock.notify();
if (sConnectivityLock != null) {
synchronized (sConnectivityLock) {
sConnectivityLock.notify();
}
}
}

View File

@ -31,6 +31,13 @@ import java.io.InputStream;
*
*/
public abstract class AbstractSyncAdapter {
public static final int SECONDS = 1000;
public static final int MINUTES = SECONDS*60;
public static final int HOURS = MINUTES*60;
public static final int DAYS = HOURS*24;
public static final int WEEKS = DAYS*7;
public Mailbox mMailbox;
public EasSyncService mService;
public Context mContext;

View File

@ -49,6 +49,7 @@ import android.webkit.MimeTypeMap;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
@ -61,8 +62,10 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
private static final int UPDATES_READ_COLUMN = 0;
private static final int UPDATES_MAILBOX_KEY_COLUMN = 1;
private static final int UPDATES_SERVER_ID_COLUMN = 2;
private static final int UPDATES_FLAG_COLUMN = 3;
private static final String[] UPDATES_PROJECTION =
{MessageColumns.FLAG_READ, MessageColumns.MAILBOX_KEY, SyncColumns.SERVER_ID};
{MessageColumns.FLAG_READ, MessageColumns.MAILBOX_KEY, SyncColumns.SERVER_ID,
MessageColumns.FLAG_FAVORITE};
String[] bindArguments = new String[2];
@ -524,6 +527,36 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
}
}
private String formatTwo(int num) {
if (num < 10) {
return "0" + (char)('0' + num);
} else
return Integer.toString(num);
}
/**
* Create date/time in RFC8601 format. Oddly enough, for calendar date/time, Microsoft uses
* a different format that excludes the punctuation (this is why I'm not putting this in a
* parent class)
*/
public String formatDateTime(Calendar calendar) {
StringBuilder sb = new StringBuilder();
//YYYY-MM-DDTHH:MM:SS.MSSZ
sb.append(calendar.get(Calendar.YEAR));
sb.append('-');
sb.append(formatTwo(calendar.get(Calendar.MONTH) + 1));
sb.append('-');
sb.append(formatTwo(calendar.get(Calendar.DAY_OF_MONTH)));
sb.append('T');
sb.append(formatTwo(calendar.get(Calendar.HOUR_OF_DAY)));
sb.append(':');
sb.append(formatTwo(calendar.get(Calendar.MINUTE)));
sb.append(':');
sb.append(formatTwo(calendar.get(Calendar.SECOND)));
sb.append(".000Z");
return sb.toString();
}
@Override
public boolean sendLocalChanges(Serializer s, EasSyncService service) throws IOException {
ContentResolver cr = mContext.getContentResolver();
@ -589,23 +622,70 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
continue;
}
boolean flagChange = false;
boolean readChange = false;
int flag = 0;
// We can only send flag changes to the server in 12.0 or later
if (mService.mProtocolVersionDouble >= 12.0) {
flag = currentCursor.getInt(UPDATES_FLAG_COLUMN);
if (flag != c.getInt(Message.LIST_FAVORITE_COLUMN)) {
flagChange = true;
}
}
int read = currentCursor.getInt(UPDATES_READ_COLUMN);
if (read == c.getInt(Message.LIST_READ_COLUMN)) {
// The read state hasn't really changed, so move on...
readChange = true;
}
if (!flagChange && !readChange) {
// In this case, we've got nothing to send to the server
continue;
}
if (first) {
s.start(Tags.SYNC_COMMANDS);
first = false;
}
// Send the change to "read". We'll do "flagged" here eventually as well
// TODO Add support for flags here (EAS 12.0 and above)
// Or is this not safe??
// Send the change to "read" and "favorite" (flagged)
s.start(Tags.SYNC_CHANGE)
.data(Tags.SYNC_SERVER_ID, c.getString(Message.LIST_SERVER_ID_COLUMN))
.start(Tags.SYNC_APPLICATION_DATA)
.data(Tags.EMAIL_READ, Integer.toString(read))
.end().end(); // SYNC_APPLICATION_DATA, SYNC_CHANGE
.start(Tags.SYNC_APPLICATION_DATA);
if (readChange) {
s.data(Tags.EMAIL_READ, Integer.toString(read));
}
// "Flag" is a relatively complex concept in EAS 12.0 and above. It is not only
// the boolean "favorite" that we think of in Gmail, but it also represents a
// follow up action, which can include a subject, start and due dates, and even
// recurrences. We don't support any of this as yet, but EAS 12.0 and higher
// require that a flag contain a status, a type, and four date fields, two each
// for start date and end (due) date.
if (flagChange) {
if (flag != 0) {
// Status 2 = set flag
s.start(Tags.EMAIL_FLAG).data(Tags.EMAIL_FLAG_STATUS, "2");
// "FollowUp" is the standard type
s.data(Tags.EMAIL_FLAG_TYPE, "FollowUp");
long now = System.currentTimeMillis();
Calendar calendar =
GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.setTimeInMillis(now);
// Flags are required to have a start date and end date (duplicated)
// First, we'll set the current date/time in GMT as the start time
String utc = formatDateTime(calendar);
s.data(Tags.TASK_START_DATE, utc).data(Tags.TASK_UTC_START_DATE, utc);
// And then we'll use one week from today for completion date
calendar.setTimeInMillis(now + 1*WEEKS);
utc = formatDateTime(calendar);
s.data(Tags.TASK_DUE_DATE, utc).data(Tags.TASK_UTC_DUE_DATE, utc);
s.end();
} else {
s.tag(Tags.EMAIL_FLAG);
}
}
s.end().end(); // SYNC_APPLICATION_DATA, SYNC_CHANGE
} finally {
currentCursor.close();
}

View File

@ -39,6 +39,7 @@ public class Tags {
public static final int MOVE = 0x05;
public static final int GIE = 0x06;
public static final int FOLDER = 0x07;
public static final int TASK = 0x09;
public static final int CONTACTS2 = 0x0C;
public static final int PING = 0x0D;
public static final int GAL = 0x10;
@ -277,6 +278,39 @@ public class Tags {
public static final int EMAIL_FLAG_TYPE = EMAIL_PAGE + 0x3D;
public static final int EMAIL_COMPLETE_TIME = EMAIL_PAGE + 0x3E;
public static final int TASK_PAGE = TASK << PAGE_SHIFT;
public static final int TASK_BODY = TASK_PAGE + 5;
public static final int TASK_BODY_SIZE = TASK_PAGE + 6;
public static final int TASK_BODY_TRUNCATED = TASK_PAGE + 7;
public static final int TASK_CATEGORIES = TASK_PAGE + 8;
public static final int TASK_CATEGORY = TASK_PAGE + 9;
public static final int TASK_COMPLETE = TASK_PAGE + 0xA;
public static final int TASK_DATE_COMPLETED = TASK_PAGE + 0xB;
public static final int TASK_DUE_DATE = TASK_PAGE + 0xC;
public static final int TASK_UTC_DUE_DATE = TASK_PAGE + 0xD;
public static final int TASK_IMPORTANCE = TASK_PAGE + 0xE;
public static final int TASK_RECURRENCE = TASK_PAGE + 0xF;
public static final int TASK_RECURRENCE_TYPE = TASK_PAGE + 0x10;
public static final int TASK_RECURRENCE_START = TASK_PAGE + 0x11;
public static final int TASK_RECURRENCE_UNTIL = TASK_PAGE + 0x12;
public static final int TASK_RECURRENCE_OCCURRENCES = TASK_PAGE + 0x13;
public static final int TASK_RECURRENCE_INTERVAL = TASK_PAGE + 0x14;
public static final int TASK_RECURRENCE_DAY_OF_MONTH = TASK_PAGE + 0x15;
public static final int TASK_RECURRENCE_DAY_OF_WEEK = TASK_PAGE + 0x16;
public static final int TASK_RECURRENCE_WEEK_OF_MONTH = TASK_PAGE + 0x17;
public static final int TASK_RECURRENCE_MONTH_OF_YEAR = TASK_PAGE + 0x18;
public static final int TASK_RECURRENCE_REGENERATE = TASK_PAGE + 0x19;
public static final int TASK_RECURRENCE_DEAD_OCCUR = TASK_PAGE + 0x1A;
public static final int TASK_REMINDER_SET = TASK_PAGE + 0x1B;
public static final int TASK_REMINDER_TIME = TASK_PAGE + 0x1C;
public static final int TASK_SENSITIVITY = TASK_PAGE + 0x1D;
public static final int TASK_START_DATE = TASK_PAGE + 0x1E;
public static final int TASK_UTC_START_DATE = TASK_PAGE + 0x1F;
public static final int TASK_SUBJECT = TASK_PAGE + 0x20;
public static final int COMPRESSED_RTF = TASK_PAGE + 0x21;
public static final int ORDINAL_DATE = TASK_PAGE + 0x22;
public static final int SUBORDINAL_DATE = TASK_PAGE + 0x23;
public static final int MOVE_PAGE = MOVE << PAGE_SHIFT;
public static final int MOVE_MOVE_ITEMS = MOVE_PAGE + 5;
public static final int MOVE_MOVE = MOVE_PAGE + 6;
@ -410,6 +444,13 @@ public class Tags {
},
{
// 0x09 Tasks
"Body", "BodySize", "BodyTruncated", "Categories", "Category", "Complete",
"DateCompleted", "DueDate", "UTCDueDate", "Importance", "Recurrence", "RecurrenceType",
"RecurrenceStart", "RecurrenceUntil", "RecurrenceOccurrences", "RecurrenceInterval",
"RecurrenceDOM", "RecurrenceDOW", "RecurrenceWOM", "RecurrenceMOY",
"RecurrenceRegenerate", "RecurrenceDeadOccur", "ReminderSet", "ReminderTime",
"Sensitivity", "StartDate", "UTCStartDate", "Subject", "CompressedRTF", "OrdinalDate",
"SubordinalDate"
},
{
// 0x0A ResolveRecipients

View File

@ -26,6 +26,8 @@ import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class EasEmailSyncAdapterTests extends AndroidTestCase {
@ -38,22 +40,32 @@ public class EasEmailSyncAdapterTests extends AndroidTestCase {
return new ByteArrayInputStream(new byte[] {0, 0, 0, 0, 0});
}
EasSyncService getTestService() {
Account account = new Account();
account.mId = -1;
Mailbox mailbox = new Mailbox();
mailbox.mId = -1;
EasSyncService service = new EasSyncService();
service.mContext = getContext();
service.mMailbox = mailbox;
service.mAccount = account;
return service;
}
EmailSyncAdapter getTestSyncAdapter() {
EasSyncService service = getTestService();
EmailSyncAdapter adapter = new EmailSyncAdapter(service.mMailbox, service);
return adapter;
}
/**
* Check functionality for getting mime type from a file name (using its extension)
* The default for all unknown files is application/octet-stream
*/
public void testGetMimeTypeFromFileName() throws IOException {
Mailbox mailbox = new Mailbox();
mailbox.mId = -1;
Account account = new Account();
account.mId = -1;
EasSyncService service = new EasSyncService();
service.mContext = getContext();
service.mMailbox = mailbox;
service.mAccount = account;
EmailSyncAdapter adapter = new EmailSyncAdapter(mailbox, service);
EasEmailSyncParser p;
p = adapter.new EasEmailSyncParser(getTestInputStream(), service);
EasSyncService service = getTestService();
EmailSyncAdapter adapter = new EmailSyncAdapter(service.mMailbox, service);
EasEmailSyncParser p = adapter.new EasEmailSyncParser(getTestInputStream(), service);
// Test a few known types
String mimeType = p.getMimeTypeFromFileName("foo.jpg");
assertEquals("image/jpeg", mimeType);
@ -72,4 +84,17 @@ public class EasEmailSyncAdapterTests extends AndroidTestCase {
mimeType = p.getMimeTypeFromFileName("");
assertEquals("application/octet-stream", mimeType);
}
public void testFormatDateTime() throws IOException {
EmailSyncAdapter adapter = getTestSyncAdapter();
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
// Calendar is odd, months are zero based, so the first 11 below is December...
calendar.set(2008, 11, 11, 18, 19, 20);
String date = adapter.formatDateTime(calendar);
assertEquals("2008-12-11T18:19:20.000Z", date);
calendar.clear();
calendar.set(2012, 0, 2, 23, 0, 1);
date = adapter.formatDateTime(calendar);
assertEquals("2012-01-02T23:00:01.000Z", date);
}
}