EmailSyncAdapter.java revision 8d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1
1ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/* 2ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Copyright (C) 2008-2009 Marc Blank 3ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed to The Android Open Source Project. 4ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 5ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 6ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * you may not use this file except in compliance with the License. 7ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * You may obtain a copy of the License at 8ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 9ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * http://www.apache.org/licenses/LICENSE-2.0 10ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 11ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Unless required by applicable law or agreed to in writing, software 12ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * distributed under the License is distributed on an "AS IS" BASIS, 13ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * See the License for the specific language governing permissions and 15ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * limitations under the License. 16ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */ 17ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 18ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankpackage com.android.exchange.adapter; 19ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 2067698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.mail.Address; 211f19b92899b3589e5d6303a7dd35ebbf569e00b9Marc Blankimport com.android.email.provider.AttachmentProvider; 22c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blankimport com.android.email.provider.EmailContent; 2300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport com.android.email.provider.EmailProvider; 24894ec76e35053ab73ee9905b6737910e7fab7cd9Andrew Stadlerimport com.android.email.provider.EmailContent.Account; 25c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blankimport com.android.email.provider.EmailContent.AccountColumns; 2667698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.provider.EmailContent.Attachment; 2767698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.provider.EmailContent.Mailbox; 2867698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.provider.EmailContent.Message; 2967698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.provider.EmailContent.MessageColumns; 3067698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport com.android.email.provider.EmailContent.SyncColumns; 31a1e128b4676c1a4fb583b61ea94e561c6045e6f8Marc Blankimport com.android.email.service.MailService; 3200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport com.android.exchange.Eas; 3300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport com.android.exchange.EasSyncService; 34ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 35ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentProviderOperation; 36ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentResolver; 37ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentUris; 38ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.ContentValues; 39ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.content.OperationApplicationException; 40ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.database.Cursor; 4177424af660458104b732bdcb718874b17d0cab3aMarc Blankimport android.net.Uri; 42ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport android.os.RemoteException; 4300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport android.webkit.MimeTypeMap; 44ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.IOException; 4600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.InputStream; 4700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.ArrayList; 4836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blankimport java.util.Calendar; 4900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.GregorianCalendar; 5000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.TimeZone; 51ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 52ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/** 53ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Sync adapter for EAS email 54ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 55ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */ 567c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blankpublic class EmailSyncAdapter extends AbstractSyncAdapter { 5700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank 5891e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank private static final int UPDATES_READ_COLUMN = 0; 5991e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank private static final int UPDATES_MAILBOX_KEY_COLUMN = 1; 6091e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank private static final int UPDATES_SERVER_ID_COLUMN = 2; 6136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank private static final int UPDATES_FLAG_COLUMN = 3; 6291e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank private static final String[] UPDATES_PROJECTION = 6336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank {MessageColumns.FLAG_READ, MessageColumns.MAILBOX_KEY, SyncColumns.SERVER_ID, 6436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank MessageColumns.FLAG_FAVORITE}; 6591e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank 6691e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank String[] bindArguments = new String[2]; 67ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 68ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Long> mDeletedIdList = new ArrayList<Long>(); 69ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Long> mUpdatedIdList = new ArrayList<Long>(); 70ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 717c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank public EmailSyncAdapter(Mailbox mailbox, EasSyncService service) { 72147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank super(mailbox, service); 73ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 74ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 75ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 7648af7392c82262d17700e3fbdccf3a582809d449Marc Blank public boolean parse(InputStream is) throws IOException { 7748af7392c82262d17700e3fbdccf3a582809d449Marc Blank EasEmailSyncParser p = new EasEmailSyncParser(is, this); 78ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return p.parse(); 79ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 80147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank 81368adeb5779fed5d64770d2131125dd93e43ab78Marc Blank public class EasEmailSyncParser extends AbstractSyncParser { 82ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 83147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank private static final String WHERE_SERVER_ID_AND_MAILBOX_KEY = 84ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank SyncColumns.SERVER_ID + "=? and " + MessageColumns.MAILBOX_KEY + "=?"; 85ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 86ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private String mMailboxIdAsString; 87ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 8848af7392c82262d17700e3fbdccf3a582809d449Marc Blank ArrayList<Message> newEmails = new ArrayList<Message>(); 8948af7392c82262d17700e3fbdccf3a582809d449Marc Blank ArrayList<Long> deletedEmails = new ArrayList<Long>(); 9048af7392c82262d17700e3fbdccf3a582809d449Marc Blank ArrayList<ServerChange> changedEmails = new ArrayList<ServerChange>(); 9148af7392c82262d17700e3fbdccf3a582809d449Marc Blank 9248af7392c82262d17700e3fbdccf3a582809d449Marc Blank public EasEmailSyncParser(InputStream in, EmailSyncAdapter adapter) throws IOException { 9348af7392c82262d17700e3fbdccf3a582809d449Marc Blank super(in, adapter); 94ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mMailboxIdAsString = Long.toString(mMailbox.mId); 95ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 96ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 97147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank @Override 98ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void wipe() { 99ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.CONTENT_URI, 100ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 101ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.DELETED_CONTENT_URI, 102ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 103ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mContentResolver.delete(Message.UPDATED_CONTENT_URI, 104ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message.MAILBOX_KEY + "=" + mMailbox.mId, null); 105ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 106ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 107ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void addData (Message msg) throws IOException { 108ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<Attachment> atts = new ArrayList<Attachment>(); 109ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1107c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) { 111ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 1127c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_ATTACHMENTS: 1135ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.BASE_ATTACHMENTS: // BASE_ATTACHMENTS is used in EAS 12.0 and up 114d95115d72be6797835e1286fb8f0d2e5a01cf3a8Marc Blank attachmentsParser(atts, msg); 115ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1167c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_TO: 11767698e240187c902bed123bf18d342ff25ec75c7Marc Blank msg.mTo = Address.pack(Address.parse(getValue())); 118ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1197c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_FROM: 120705a309bd78efd77469ac90a57849619de3317e3Mihai Preda Address[] froms = Address.parse(getValue()); 121705a309bd78efd77469ac90a57849619de3317e3Mihai Preda if (froms != null && froms.length > 0) { 122705a309bd78efd77469ac90a57849619de3317e3Mihai Preda msg.mDisplayName = froms[0].toFriendly(); 123ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 124705a309bd78efd77469ac90a57849619de3317e3Mihai Preda msg.mFrom = Address.pack(froms); 125ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1267c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_CC: 12767698e240187c902bed123bf18d342ff25ec75c7Marc Blank msg.mCc = Address.pack(Address.parse(getValue())); 128ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1297c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_REPLY_TO: 13067698e240187c902bed123bf18d342ff25ec75c7Marc Blank msg.mReplyTo = Address.pack(Address.parse(getValue())); 131ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1327c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_DATE_RECEIVED: 133ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String date = getValue(); 134ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // 2009-02-11T18:03:03.627Z 135ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank GregorianCalendar cal = new GregorianCalendar(); 136ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cal.set(Integer.parseInt(date.substring(0, 4)), Integer.parseInt(date 137ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(5, 7)) - 1, Integer.parseInt(date.substring(8, 10)), 138ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Integer.parseInt(date.substring(11, 13)), Integer.parseInt(date 139ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(14, 16)), Integer.parseInt(date 140ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .substring(17, 19))); 141ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank cal.setTimeZone(TimeZone.getTimeZone("GMT")); 142ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mTimeStamp = cal.getTimeInMillis(); 143ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1447c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_SUBJECT: 145ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mSubject = getValue(); 146ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1477c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_READ: 148ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFlagRead = getValueInt() == 1; 149ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1507c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.BASE_BODY: 15100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank bodyParser(msg); 15200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank break; 1537c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_FLAG: 154ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank msg.mFlagFavorite = flagParser(); 155ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank break; 1567c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_BODY: 15767698e240187c902bed123bf18d342ff25ec75c7Marc Blank String text = getValue(); 15867698e240187c902bed123bf18d342ff25ec75c7Marc Blank msg.mText = text; 159ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 160ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 161ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 162ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 163ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 164ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 165ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (atts.size() > 0) { 166ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mAttachments = atts; 167ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 168ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 16967698e240187c902bed123bf18d342ff25ec75c7Marc Blank 17000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank private void addParser(ArrayList<Message> emails) throws IOException { 171ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Message msg = new Message(); 172ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mAccountKey = mAccount.mId; 173ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mMailboxKey = mMailbox.mId; 174f02459a766ddb1727d191daa0aeb559c8f848668Andrew Stadler msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; 175ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1767c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.SYNC_ADD) != END) { 177ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 1787c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.SYNC_SERVER_ID: 179ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mServerId = getValue(); 180ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 1817c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.SYNC_APPLICATION_DATA: 182ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank addData(msg); 183ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 184ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 185ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 186ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 187ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 188ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank emails.add(msg); 189ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 190ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 191ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank // For now, we only care about the "active" state 192ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank private Boolean flagParser() throws IOException { 193ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean state = false; 1947c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.EMAIL_FLAG) != END) { 195ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank switch (tag) { 1967c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_FLAG_STATUS: 197ce17455fc5abf061e252d495288d0d56404b0b62Marc Blank state = getValueInt() == 2; 198ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank break; 199ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank default: 200ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank skipTag(); 201ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank } 202ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank } 203ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank return state; 204ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank } 205ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank 20600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank private void bodyParser(Message msg) throws IOException { 20700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank String bodyType = Eas.BODY_PREFERENCE_TEXT; 20800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank String body = ""; 2097c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.EMAIL_BODY) != END) { 21000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank switch (tag) { 2117c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.BASE_TYPE: 21200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank bodyType = getValue(); 21300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank break; 2147c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.BASE_DATA: 21500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank body = getValue(); 21600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank break; 21700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank default: 21800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank skipTag(); 21900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 22000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 22100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank // We always ask for TEXT or HTML; there's no third option 22200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank if (bodyType.equals(Eas.BODY_PREFERENCE_HTML)) { 22300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank msg.mHtml = body; 22400d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } else { 22500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank msg.mText = body; 22600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 22700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 22800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank 2295ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank private void attachmentsParser(ArrayList<Attachment> atts, Message msg) throws IOException { 2305ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank while (nextTag(Tags.EMAIL_ATTACHMENTS) != END) { 2315ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank switch (tag) { 2325ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.EMAIL_ATTACHMENT: 2335ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.BASE_ATTACHMENT: // BASE_ATTACHMENT is used in EAS 12.0 and up 2345ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank attachmentParser(atts, msg); 2355ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank break; 2365ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank default: 2375ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank skipTag(); 2385ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank } 2395ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank } 2405ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank } 2415ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank 24200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank private void attachmentParser(ArrayList<Attachment> atts, Message msg) throws IOException { 243ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String fileName = null; 244ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String length = null; 245d95115d72be6797835e1286fb8f0d2e5a01cf3a8Marc Blank String location = null; 246ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 2477c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.EMAIL_ATTACHMENT) != END) { 248ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 2495ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank // We handle both EAS 2.5 and 12.0+ attachments here 2507c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_DISPLAY_NAME: 2515ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.BASE_DISPLAY_NAME: 252ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank fileName = getValue(); 253ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 2547c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_ATT_NAME: 2555ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.BASE_FILE_REFERENCE: 256d95115d72be6797835e1286fb8f0d2e5a01cf3a8Marc Blank location = getValue(); 257ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 2587c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_ATT_SIZE: 2595ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank case Tags.BASE_ESTIMATED_DATA_SIZE: 260ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank length = getValue(); 261ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 262ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 263ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 264ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 265ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 266ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 2675ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank if ((fileName != null) && (length != null) && (location != null)) { 268ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Attachment att = new Attachment(); 269ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mEncoding = "base64"; 270ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mSize = Long.parseLong(length); 271ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank att.mFileName = fileName; 272d95115d72be6797835e1286fb8f0d2e5a01cf3a8Marc Blank att.mLocation = location; 27300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank att.mMimeType = getMimeTypeFromFileName(fileName); 274ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank atts.add(att); 275ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank msg.mFlagAttachment = true; 276ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 277ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 278ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 27900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank /** 28000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * Try to determine a mime type from a file name, defaulting to application/x, where x 28100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * is either the extension or (if none) octet-stream 28200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * At the moment, this is somewhat lame, since many file types aren't recognized 28300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * @param fileName the file name to ponder 28400d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * @return 28500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank */ 28600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank // Note: The MimeTypeMap method currently uses a very limited set of mime types 28700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank // A bug has been filed against this issue. 28800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank public String getMimeTypeFromFileName(String fileName) { 28900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank String mimeType; 29000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank int lastDot = fileName.lastIndexOf('.'); 29100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank String extension = null; 2925ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank if ((lastDot > 0) && (lastDot < fileName.length() - 1)) { 29319fd685351de80c62c9bc7f0f05fe96983a8078dMarc Blank extension = fileName.substring(lastDot + 1).toLowerCase(); 29400d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 29500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank if (extension == null) { 29600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank // A reasonable default for now. 29700d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank mimeType = "application/octet-stream"; 29800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } else { 29900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 30000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank if (mimeType == null) { 30100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank mimeType = "application/" + extension; 30200d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 30300d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 30400d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank return mimeType; 30500d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank } 30600d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank 307ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private Cursor getServerIdCursor(String serverId, String[] projection) { 308ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank bindArguments[0] = serverId; 309ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank bindArguments[1] = mMailboxIdAsString; 310ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return mContentResolver.query(Message.CONTENT_URI, projection, 311ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank WHERE_SERVER_ID_AND_MAILBOX_KEY, bindArguments, null); 312ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 313ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 314048d45641b88c87172074aa5f29b3de307bc3712Marc Blank private void deleteParser(ArrayList<Long> deletes, int entryTag) throws IOException { 315048d45641b88c87172074aa5f29b3de307bc3712Marc Blank while (nextTag(entryTag) != END) { 316ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 3177c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.SYNC_SERVER_ID: 318ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String serverId = getValue(); 319ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Find the message in this mailbox with the given serverId 320ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = getServerIdCursor(serverId, Message.ID_COLUMN_PROJECTION); 321ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 322ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (c.moveToFirst()) { 3230a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank userLog("Deleting ", serverId); 324ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank deletes.add(c.getLong(Message.ID_COLUMNS_ID_COLUMN)); 325ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 326ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 327ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 328ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 329ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 330ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 331ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 332ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 333ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 334ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 335ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 336ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank class ServerChange { 337ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id; 338ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean read; 339ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean flag; 340ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 341ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank ServerChange(long _id, Boolean _read, Boolean _flag) { 342ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank id = _id; 343ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank read = _read; 344ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank flag = _flag; 345ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 346ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 347ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 34800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank private void changeParser(ArrayList<ServerChange> changes) throws IOException { 349ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String serverId = null; 350ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean oldRead = false; 351ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean read = null; 352ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean oldFlag = false; 353ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank Boolean flag = null; 354ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id = 0; 3557c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.SYNC_CHANGE) != END) { 356ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 3577c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.SYNC_SERVER_ID: 358ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank serverId = getValue(); 359ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = getServerIdCursor(serverId, Message.LIST_PROJECTION); 360ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 361ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (c.moveToFirst()) { 3620a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank userLog("Changing ", serverId); 363ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank oldRead = c.getInt(Message.LIST_READ_COLUMN) == Message.READ; 364ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank oldFlag = c.getInt(Message.LIST_FAVORITE_COLUMN) == 1; 365ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank id = c.getLong(Message.LIST_ID_COLUMN); 366ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 367ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 368ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 369ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 370ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 3717c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_READ: 372ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank read = getValueInt() == 1; 373ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 3747c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.EMAIL_FLAG: 375ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank flag = flagParser(); 376ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank break; 3777c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.SYNC_APPLICATION_DATA: 378ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 379ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 380ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 381ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 382ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 3835ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank if (((read != null) && !oldRead.equals(read)) || 3845ba0321df8ea8d854de76263348ba26b0a8cff16Marc Blank ((flag != null) && !oldFlag.equals(flag))) { 385ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank changes.add(new ServerChange(id, read, flag)); 386ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 387ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 388ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 38900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank /* (non-Javadoc) 39000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank * @see com.android.exchange.adapter.EasContentParser#commandsParser() 39100d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank */ 392147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank @Override 393ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public void commandsParser() throws IOException { 3947c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.SYNC_COMMANDS) != END) { 3957c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank if (tag == Tags.SYNC_ADD) { 396ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank addParser(newEmails); 3970a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank incrementChangeCount(); 398048d45641b88c87172074aa5f29b3de307bc3712Marc Blank } else if (tag == Tags.SYNC_DELETE || tag == Tags.SYNC_SOFT_DELETE) { 399048d45641b88c87172074aa5f29b3de307bc3712Marc Blank deleteParser(deletedEmails, tag); 4000a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank incrementChangeCount(); 4017c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank } else if (tag == Tags.SYNC_CHANGE) { 402ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank changeParser(changedEmails); 4030a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank incrementChangeCount(); 404ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else 405ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 406ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 40748af7392c82262d17700e3fbdccf3a582809d449Marc Blank } 40848af7392c82262d17700e3fbdccf3a582809d449Marc Blank 40948af7392c82262d17700e3fbdccf3a582809d449Marc Blank @Override 410a1e1f139046dfb28ea69c46d392f70764ad6f822Andrew Stadler public void responsesParser() { 41148af7392c82262d17700e3fbdccf3a582809d449Marc Blank } 41248af7392c82262d17700e3fbdccf3a582809d449Marc Blank 41348af7392c82262d17700e3fbdccf3a582809d449Marc Blank @Override 414a1e1f139046dfb28ea69c46d392f70764ad6f822Andrew Stadler public void commit() { 41548af7392c82262d17700e3fbdccf3a582809d449Marc Blank int notifyCount = 0; 416ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 417ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Use a batch operation to handle the changes 418ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // TODO New mail notifications? Who looks for these? 419ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); 42077424af660458104b732bdcb718874b17d0cab3aMarc Blank for (Message msg: newEmails) { 42177424af660458104b732bdcb718874b17d0cab3aMarc Blank if (!msg.mFlagRead) { 42277424af660458104b732bdcb718874b17d0cab3aMarc Blank notifyCount++; 42377424af660458104b732bdcb718874b17d0cab3aMarc Blank } 42477424af660458104b732bdcb718874b17d0cab3aMarc Blank msg.addSaveOps(ops); 425ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 426ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (Long id : deletedEmails) { 427ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newDelete( 428ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Message.CONTENT_URI, id)).build()); 4291f19b92899b3589e5d6303a7dd35ebbf569e00b9Marc Blank AttachmentProvider.deleteAllAttachmentFiles(mContext, mAccount.mId, id); 430ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 431ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!changedEmails.isEmpty()) { 432ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Server wins in a conflict... 433ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank for (ServerChange change : changedEmails) { 434ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank ContentValues cv = new ContentValues(); 435ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank if (change.read != null) { 436ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank cv.put(MessageColumns.FLAG_READ, change.read); 437ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank } 438ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank if (change.flag != null) { 439ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank cv.put(MessageColumns.FLAG_FAVORITE, change.flag); 440ede29869a74740fd93bd74aa42d085d3704699cfMarc Blank } 441ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newUpdate( 442ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Message.CONTENT_URI, change.id)) 443ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .withValues(cv) 444ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank .build()); 445ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 446ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4478d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank 4488d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank // We only want to update the sync key here 4498d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank ContentValues mailboxValues = new ContentValues(); 4508d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank mailboxValues.put(Mailbox.SYNC_KEY, mMailbox.mSyncKey); 451ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ops.add(ContentProviderOperation.newUpdate( 4528d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailbox.mId)) 4538d12fd6f9d0993a8eaf7777d57ad04d80dfd2dd1Marc Blank .withValues(mailboxValues).build()); 454ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4558480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank addCleanupOps(ops); 456147e03d50b8a793d58d67917af4bc6333f8afac1Marc Blank 4571b275b9408d5b856e2482fa3951827489e9585ccMarc Blank // No commits if we're stopped 4581b275b9408d5b856e2482fa3951827489e9585ccMarc Blank synchronized (mService.getSynchronizer()) { 4591b275b9408d5b856e2482fa3951827489e9585ccMarc Blank if (mService.isStopped()) return; 4601b275b9408d5b856e2482fa3951827489e9585ccMarc Blank try { 4610a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank mContentResolver.applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); 4620a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank userLog(mMailbox.mDisplayName, " SyncKey saved as: ", mMailbox.mSyncKey); 4631b275b9408d5b856e2482fa3951827489e9585ccMarc Blank } catch (RemoteException e) { 4641b275b9408d5b856e2482fa3951827489e9585ccMarc Blank // There is nothing to be done here; fail by returning null 4651b275b9408d5b856e2482fa3951827489e9585ccMarc Blank } catch (OperationApplicationException e) { 4661b275b9408d5b856e2482fa3951827489e9585ccMarc Blank // There is nothing to be done here; fail by returning null 4671b275b9408d5b856e2482fa3951827489e9585ccMarc Blank } 468ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4698480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank 47077424af660458104b732bdcb718874b17d0cab3aMarc Blank if (notifyCount > 0) { 471c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank // Use the new atomic add URI in EmailProvider 472c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank // We could add this to the operations being done, but it's not strictly 473c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank // speaking necessary, as the previous batch preserves the integrity of the 474c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank // database, whereas this is purely for notification purposes, and is itself atomic 475c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank ContentValues cv = new ContentValues(); 476c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT); 477c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank cv.put(EmailContent.ADD_COLUMN_NAME, notifyCount); 478c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank Uri uri = ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, mAccount.mId); 479c88a53832acb73bc6959cd544b2d6c7a2f52c367Marc Blank mContentResolver.update(uri, cv, null, null); 480a1e128b4676c1a4fb583b61ea94e561c6045e6f8Marc Blank MailService.actionNotifyNewMessages(mContext, mAccount.mId); 481894ec76e35053ab73ee9905b6737910e7fab7cd9Andrew Stadler } 48277424af660458104b732bdcb718874b17d0cab3aMarc Blank } 483ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 484ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 485ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 486ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public String getCollectionName() { 487ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return "Email"; 488ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 489ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4908480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank private void addCleanupOps(ArrayList<ContentProviderOperation> ops) { 4918480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank // If we've sent local deletions, clear out the deleted table 4928480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank for (Long id: mDeletedIdList) { 4938480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank ops.add(ContentProviderOperation.newDelete( 4948480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank ContentUris.withAppendedId(Message.DELETED_CONTENT_URI, id)).build()); 4958480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 4968480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank // And same with the updates 4978480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank for (Long id: mUpdatedIdList) { 4988480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank ops.add(ContentProviderOperation.newDelete( 4998480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank ContentUris.withAppendedId(Message.UPDATED_CONTENT_URI, id)).build()); 5008480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 5018480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 5028480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank 5038480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank @Override 50448af7392c82262d17700e3fbdccf3a582809d449Marc Blank public void cleanup() { 5058480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank if (!mDeletedIdList.isEmpty() || !mUpdatedIdList.isEmpty()) { 5068480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); 5078480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank addCleanupOps(ops); 5088480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank try { 50948af7392c82262d17700e3fbdccf3a582809d449Marc Blank mContext.getContentResolver() 5108480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank .applyBatch(EmailProvider.EMAIL_AUTHORITY, ops); 5118480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } catch (RemoteException e) { 5128480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank // There is nothing to be done here; fail by returning null 5138480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } catch (OperationApplicationException e) { 5148480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank // There is nothing to be done here; fail by returning null 5158480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 5168480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 5178480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank } 5188480f5bc2eb612920f7e17312a693b4d8c26f14bMarc Blank 51936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank private String formatTwo(int num) { 52036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (num < 10) { 52136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank return "0" + (char)('0' + num); 52236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } else 52336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank return Integer.toString(num); 52436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 52536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 52636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank /** 52736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank * Create date/time in RFC8601 format. Oddly enough, for calendar date/time, Microsoft uses 52836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank * a different format that excludes the punctuation (this is why I'm not putting this in a 52936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank * parent class) 53036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank */ 53136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank public String formatDateTime(Calendar calendar) { 53236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank StringBuilder sb = new StringBuilder(); 53336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank //YYYY-MM-DDTHH:MM:SS.MSSZ 53436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(calendar.get(Calendar.YEAR)); 53536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append('-'); 53636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(formatTwo(calendar.get(Calendar.MONTH) + 1)); 53736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append('-'); 53836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(formatTwo(calendar.get(Calendar.DAY_OF_MONTH))); 53936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append('T'); 54036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(formatTwo(calendar.get(Calendar.HOUR_OF_DAY))); 54136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(':'); 54236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(formatTwo(calendar.get(Calendar.MINUTE))); 54336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(':'); 54436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(formatTwo(calendar.get(Calendar.SECOND))); 54536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank sb.append(".000Z"); 54636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank return sb.toString(); 54736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 54836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 549ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank @Override 55048af7392c82262d17700e3fbdccf3a582809d449Marc Blank public boolean sendLocalChanges(Serializer s) throws IOException { 5510a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank ContentResolver cr = mContext.getContentResolver(); 552ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 5535acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank // Never upsync from these folders 5545acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank if (mMailbox.mType == Mailbox.TYPE_DRAFTS || mMailbox.mType == Mailbox.TYPE_OUTBOX) { 5555acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank return false; 5565acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank } 5575acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank 558ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Find any of our deleted items 559ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor c = cr.query(Message.DELETED_CONTENT_URI, Message.LIST_PROJECTION, 560ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); 561ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean first = true; 562ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // We keep track of the list of deleted item id's so that we can remove them from the 563ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // deleted table after the server receives our command 564ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mDeletedIdList.clear(); 565ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 566ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (c.moveToNext()) { 5675acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank String serverId = c.getString(Message.LIST_SERVER_ID_COLUMN); 5685acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank // Keep going if there's no serverId 5695acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank if (serverId == null) { 5705acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank continue; 5715acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank } else if (first) { 5727c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank s.start(Tags.SYNC_COMMANDS); 573ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank first = false; 574ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 575ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Send the command to delete this message 5765acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); 577ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mDeletedIdList.add(c.getLong(Message.LIST_ID_COLUMN)); 578ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 579ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 580ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 581ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 582ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 58391e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank // Find our trash mailbox, since deletions will have been moved there... 58491e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank long trashMailboxId = 5850a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank Mailbox.findMailboxOfType(mContext, mMailbox.mAccountKey, Mailbox.TYPE_TRASH); 58691e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank 587ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Do the same now for updated items 588ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c = cr.query(Message.UPDATED_CONTENT_URI, Message.LIST_PROJECTION, 589ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); 59091e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank 59191e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank // We keep track of the list of updated item id's as we did above with deleted items 592ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mUpdatedIdList.clear(); 593ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 594ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (c.moveToNext()) { 595ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank long id = c.getLong(Message.LIST_ID_COLUMN); 596ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Say we've handled this update 597ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mUpdatedIdList.add(id); 598ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // We have the id of the changed item. But first, we have to find out its current 599ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // state, since the updated table saves the opriginal state 600ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank Cursor currentCursor = cr.query(ContentUris.withAppendedId(Message.CONTENT_URI, id), 601ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank UPDATES_PROJECTION, null, null, null); 602ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 603ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // If this item no longer exists (shouldn't be possible), just move along 604ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!currentCursor.moveToFirst()) { 605ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank continue; 606ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 6075acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank // Keep going if there's no serverId 6085acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank String serverId = currentCursor.getString(UPDATES_SERVER_ID_COLUMN); 6095acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank if (serverId == null) { 6105acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank continue; 6115acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank } 61291e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank // If the message is now in the trash folder, it has been deleted by the user 61391e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank if (currentCursor.getLong(UPDATES_MAILBOX_KEY_COLUMN) == trashMailboxId) { 61491e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank if (first) { 6157c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank s.start(Tags.SYNC_COMMANDS); 61691e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank first = false; 61791e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank } 61891e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank // Send the command to delete this message 6195acdc9b59e5cd708bf568cded8ddfe3cacb23b73Marc Blank s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); 62091e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank continue; 62191e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank } 62291e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank 62336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank boolean flagChange = false; 62436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank boolean readChange = false; 62536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 62636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank int flag = 0; 62736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 62836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // We can only send flag changes to the server in 12.0 or later 62936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (mService.mProtocolVersionDouble >= 12.0) { 63036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank flag = currentCursor.getInt(UPDATES_FLAG_COLUMN); 63136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (flag != c.getInt(Message.LIST_FAVORITE_COLUMN)) { 63236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank flagChange = true; 63336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 63436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 63536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 63691e4233059a8b734dd67ffcfa0d08a0d4d8ab17dMarc Blank int read = currentCursor.getInt(UPDATES_READ_COLUMN); 63776eb7b252fc410f5f5d4e90ad54d4bde837de0aaMarc Blank if (read != c.getInt(Message.LIST_READ_COLUMN)) { 63836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank readChange = true; 63936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 64036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 64136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (!flagChange && !readChange) { 64236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // In this case, we've got nothing to send to the server 643ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank continue; 644ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 64536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank 646ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (first) { 6477c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank s.start(Tags.SYNC_COMMANDS); 648ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank first = false; 649ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 65036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // Send the change to "read" and "favorite" (flagged) 6517c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank s.start(Tags.SYNC_CHANGE) 6527c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank .data(Tags.SYNC_SERVER_ID, c.getString(Message.LIST_SERVER_ID_COLUMN)) 65336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank .start(Tags.SYNC_APPLICATION_DATA); 65436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (readChange) { 65536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.data(Tags.EMAIL_READ, Integer.toString(read)); 65636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 65736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // "Flag" is a relatively complex concept in EAS 12.0 and above. It is not only 65836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // the boolean "favorite" that we think of in Gmail, but it also represents a 65936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // follow up action, which can include a subject, start and due dates, and even 66036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // recurrences. We don't support any of this as yet, but EAS 12.0 and higher 66136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // require that a flag contain a status, a type, and four date fields, two each 66236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // for start date and end (due) date. 66336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (flagChange) { 66436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank if (flag != 0) { 66536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // Status 2 = set flag 66636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.start(Tags.EMAIL_FLAG).data(Tags.EMAIL_FLAG_STATUS, "2"); 66736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // "FollowUp" is the standard type 66836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.data(Tags.EMAIL_FLAG_TYPE, "FollowUp"); 66936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank long now = System.currentTimeMillis(); 67036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank Calendar calendar = 67136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT")); 67236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank calendar.setTimeInMillis(now); 67336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // Flags are required to have a start date and end date (duplicated) 67436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // First, we'll set the current date/time in GMT as the start time 67536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank String utc = formatDateTime(calendar); 67636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.data(Tags.TASK_START_DATE, utc).data(Tags.TASK_UTC_START_DATE, utc); 67736e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank // And then we'll use one week from today for completion date 67836e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank calendar.setTimeInMillis(now + 1*WEEKS); 67936e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank utc = formatDateTime(calendar); 68036e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.data(Tags.TASK_DUE_DATE, utc).data(Tags.TASK_UTC_DUE_DATE, utc); 68136e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.end(); 68236e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } else { 68336e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.tag(Tags.EMAIL_FLAG); 68436e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 68536e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank } 68636e08ce9f808425ed573e182812f3a82ef4d5d45Marc Blank s.end().end(); // SYNC_APPLICATION_DATA, SYNC_CHANGE 687ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 688ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank currentCursor.close(); 689ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 690ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 691ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 692ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 693ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 694ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 695ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (!first) { 6967c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank s.end(); // SYNC_COMMANDS 697ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 698ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return false; 699ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 700ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank} 701