FolderSyncParser.java revision ab4fe820cb8e1fa3781485ab2e44ec458ce0669e
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 206aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.content.ContentProviderOperation; 21c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.content.ContentResolver; 226aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.content.ContentUris; 236aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.content.ContentValues; 24c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Huimport android.content.Context; 256aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.content.OperationApplicationException; 266aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.database.Cursor; 276aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.os.RemoteException; 28ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantlerimport android.os.TransactionTooLargeException; 296aa35f65d70f476367b3ee951b4470662a296fa1Marc Blankimport android.text.TextUtils; 305586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Huimport android.util.SparseBooleanArray; 315586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Huimport android.util.SparseIntArray; 326aa35f65d70f476367b3ee951b4470662a296fa1Marc Blank 337372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.Account; 34c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent; 35c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns; 36c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 374d8774462ace9a45154b2df418b9f2fe7a9c685dBen Komaloimport com.android.emailcommon.provider.Mailbox; 38f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport com.android.emailcommon.service.SyncWindow; 39e951b589c5134a1154ec3743d79236dee54a6519Marc Blankimport com.android.emailcommon.utility.AttachmentUtilities; 4077186bb1a174432ef272584374942d8b9228e39cMarc Blankimport com.android.exchange.CommandStatusException; 4177186bb1a174432ef272584374942d8b9228e39cMarc Blankimport com.android.exchange.CommandStatusException.CommandStatus; 42ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blankimport com.android.exchange.Eas; 437b6a75def9f415a75b4ff4b640216c95a7e799a5Martin Hibdonimport com.android.exchange.service.EasCalendarSyncHandler; 447b6a75def9f415a75b4ff4b640216c95a7e799a5Martin Hibdonimport com.android.exchange.service.EasContactsSyncHandler; 45942b7d73f2f5b3d6c651e39463e615fe6902a910Scott Kennedyimport com.android.mail.utils.LogUtils; 46f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blankimport com.google.common.annotations.VisibleForTesting; 47ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4800d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.IOException; 4900d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.io.InputStream; 5000d91b2e12d65df06916afdc4bebca67fd27214cMarc Blankimport java.util.ArrayList; 51d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blankimport java.util.HashMap; 52ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantlerimport java.util.LinkedHashSet; 53ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantlerimport java.util.Set; 5400d91b2e12d65df06916afdc4bebca67fd27214cMarc Blank 55ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/** 56ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Parse the result of a FolderSync command 57ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * 58ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Handles the addition, deletion, and changes to folders in the user's Exchange account. 59ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank **/ 60ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 610a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blankpublic class FolderSyncParser extends AbstractSyncParser { 6222bc4e0e4f4a5e43e4eea8d59e1961860c507594Marc Blank 63ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank public static final String TAG = "FolderSyncParser"; 64ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 655586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu /** 665586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * Mapping from EAS type values to {@link Mailbox} types. 675586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * See http://msdn.microsoft.com/en-us/library/gg650877(v=exchg.80).aspx for the list of EAS 685586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * type values. 695586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * If an EAS type is not in the map, or is inserted with a value of {@link Mailbox#TYPE_NONE}, 705586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * then we don't support that type and we should ignore it. 715586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * TODO: Maybe we should store the mailbox anyway, otherwise it'll be annoying to upgrade. 725586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu */ 735586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu private static final SparseIntArray MAILBOX_TYPE_MAP; 745586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu static { 755586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP = new SparseIntArray(11); 765586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(1, Mailbox.TYPE_MAIL); // User-created folder (generic) 775586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(2, Mailbox.TYPE_INBOX); // Default Inbox folder 785586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(3, Mailbox.TYPE_DRAFTS); // Default Drafts folder 795586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(4, Mailbox.TYPE_TRASH); // Default Deleted Items folder 805586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(5, Mailbox.TYPE_SENT); // Default Sent Items folder 815586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(6, Mailbox.TYPE_OUTBOX); // Default Outbox folder 825586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(7, Mailbox.TYPE_TASKS); // Default Tasks folder 835586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(8, Mailbox.TYPE_CALENDAR); // Default Calendar folder 845586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(9, Mailbox.TYPE_CONTACTS); // Default Contacts folder 855586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(10, Mailbox.TYPE_NONE); // Default Notes folder 865586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(11, Mailbox.TYPE_NONE); // Default Journal folder 875586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(12, Mailbox.TYPE_MAIL); // User-created Mail folder 885586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(13, Mailbox.TYPE_CALENDAR); // User-created Calendar folder 895586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu MAILBOX_TYPE_MAP.put(14, Mailbox.TYPE_CONTACTS); // User-created Contacts folder 905586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(15, Mailbox.TYPE_TASKS); // User-created Tasks folder 915586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(16, Mailbox.TYPE_NONE); // User-created Journal folder 925586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(17, Mailbox.TYPE_NONE); // User-created Notes folder 935586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(18, Mailbox.TYPE_NONE); // Unknown folder type 945586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu //MAILBOX_TYPE_MAP.put(19, Mailbox.TYPE_NONE); // Recipient information cache 955586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } 96ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 976c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Content selection for all mailboxes belonging to an account. */ 986c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final String WHERE_ACCOUNT_KEY = MailboxColumns.ACCOUNT_KEY + "=?"; 999d4ac93efbba01afe668f9406feec69b3a2374ebMarc Blank 1006c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 1016c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Content selection to find a specific mailbox by server id. Since server ids aren't unique 1026c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * across all accounts, this must also check account id. 1036c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 104d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank private static final String WHERE_SERVER_ID_AND_ACCOUNT = MailboxColumns.SERVER_ID + "=? and " + 105ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MailboxColumns.ACCOUNT_KEY + "=?"; 106ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1076c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 1086c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Content selection to find a specific mailbox by display name and account. 1096c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 110ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private static final String WHERE_DISPLAY_NAME_AND_ACCOUNT = MailboxColumns.DISPLAY_NAME + 111ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 112ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1136c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 1146c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Content selection to find children by parent's server id. Since server ids aren't unique 1156c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * across accounts, this must also use account id. 1166c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 117ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private static final String WHERE_PARENT_SERVER_ID_AND_ACCOUNT = 118ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank MailboxColumns.PARENT_SERVER_ID +"=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 119ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1206c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Projection used when fetching a Mailbox's ids. */ 121ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank private static final String[] MAILBOX_ID_COLUMNS_PROJECTION = 122e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank new String[] {MailboxColumns.ID, MailboxColumns.SERVER_ID, MailboxColumns.PARENT_SERVER_ID}; 123e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank private static final int MAILBOX_ID_COLUMNS_ID = 0; 124e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank private static final int MAILBOX_ID_COLUMNS_SERVER_ID = 1; 125e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank private static final int MAILBOX_ID_COLUMNS_PARENT_SERVER_ID = 2; 126ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1276c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Projection used for changed parents during parent/child fixup. */ 1286c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final String[] FIXUP_PARENT_PROJECTION = 129ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler { MailboxColumns.ID, MailboxColumns.FLAGS }; 1306c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final int FIXUP_PARENT_ID_COLUMN = 0; 131ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler private static final int FIXUP_PARENT_FLAGS_COLUMN = 1; 1326c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 1336c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Projection used for changed children during parent/child fixup. */ 1346c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final String[] FIXUP_CHILD_PROJECTION = 135ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler { MailboxColumns.ID }; 1366c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final int FIXUP_CHILD_ID_COLUMN = 0; 1376c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 1386c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Flags that are set or cleared when a mailbox's child status changes. */ 1396c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final int HAS_CHILDREN_FLAGS = 1406c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu Mailbox.FLAG_HAS_CHILDREN | Mailbox.FLAG_CHILDREN_VISIBLE; 1416c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 1426c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Mailbox.NO_MAILBOX, as a string (convenience since this is used in several places). */ 1436c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private static final String NO_MAILBOX_STRING = Long.toString(Mailbox.NO_MAILBOX); 1446c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 145f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank @VisibleForTesting 146f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank long mAccountId; 147f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank @VisibleForTesting 148f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank String mAccountIdAsString; 1499f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank 1507b6a75def9f415a75b4ff4b640216c95a7e799a5Martin Hibdon private final String[] mBindArguments = new String[2]; 1516c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 1526c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** List of pending operations to send as a batch to the content provider. */ 1537b6a75def9f415a75b4ff4b640216c95a7e799a5Martin Hibdon private final ArrayList<ContentProviderOperation> mOperations = 1546c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu new ArrayList<ContentProviderOperation>(); 1556c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Indicates whether this sync is an initial FolderSync. */ 156e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank private boolean mInitialSync; 1576c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** List of folder server ids whose children changed with this sync. */ 158ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler private final Set<String> mParentFixupsNeeded = new LinkedHashSet<String>(); 1596c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** Indicates whether the sync response provided a different sync key than we had. */ 1606c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private boolean mSyncKeyChanged = false; 1616c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 16277186bb1a174432ef272584374942d8b9228e39cMarc Blank // If true, we only care about status (this is true when validating an account) and ignore 16377186bb1a174432ef272584374942d8b9228e39cMarc Blank // other data 16477186bb1a174432ef272584374942d8b9228e39cMarc Blank private final boolean mStatusOnly; 165e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank 1665586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu /** Map of folder types that have been created during this sync. */ 1675586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu private final SparseBooleanArray mCreatedFolderTypes = 1685586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu new SparseBooleanArray(Mailbox.REQUIRED_FOLDER_TYPES.length); 169fc8809b47ba408d74ca49c08d9b3299d377ef1a0Yu Ping Hu 170e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank private static final ContentValues UNINITIALIZED_PARENT_KEY = new ContentValues(); 171e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank 172ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler static { 173e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank UNINITIALIZED_PARENT_KEY.put(MailboxColumns.PARENT_KEY, Mailbox.PARENT_KEY_UNINITIALIZED); 174e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank } 175ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 176c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu public FolderSyncParser(final Context context, final ContentResolver resolver, 177bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu final InputStream in, final Account account, final boolean statusOnly) 178bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu throws IOException { 179bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu super(context, resolver, in, null, account); 180c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mAccountId = mAccount.mId; 181c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu mAccountIdAsString = Long.toString(mAccountId); 182bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu mStatusOnly = statusOnly; 183c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu } 184c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu 18548af7392c82262d17700e3fbdccf3a582809d449Marc Blank public FolderSyncParser(InputStream in, AbstractSyncAdapter adapter) throws IOException { 18677186bb1a174432ef272584374942d8b9228e39cMarc Blank this(in, adapter, false); 18777186bb1a174432ef272584374942d8b9228e39cMarc Blank } 18877186bb1a174432ef272584374942d8b9228e39cMarc Blank 18977186bb1a174432ef272584374942d8b9228e39cMarc Blank public FolderSyncParser(InputStream in, AbstractSyncAdapter adapter, boolean statusOnly) 19077186bb1a174432ef272584374942d8b9228e39cMarc Blank throws IOException { 19148af7392c82262d17700e3fbdccf3a582809d449Marc Blank super(in, adapter); 192ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mAccountId = mAccount.mId; 193ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mAccountIdAsString = Long.toString(mAccountId); 19477186bb1a174432ef272584374942d8b9228e39cMarc Blank mStatusOnly = statusOnly; 195ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 196ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 1977c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank @Override 19877186bb1a174432ef272584374942d8b9228e39cMarc Blank public boolean parse() throws IOException, CommandStatusException { 199ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int status; 200ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank boolean res = false; 2011b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank boolean resetFolders = false; 2026c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mInitialSync = (mAccount.mSyncKey == null) || "0".equals(mAccount.mSyncKey); 203e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank if (mInitialSync) { 2046c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // We're resyncing all folders for this account, so nuke any existing ones. 2056c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mContentResolver.delete(Mailbox.CONTENT_URI, WHERE_ACCOUNT_KEY, 2066c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu new String[] {mAccountIdAsString}); 207f1284e663702435fda3bb96bee5a75fbdc858e8aMarc Blank } 2087c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank if (nextTag(START_DOCUMENT) != Tags.FOLDER_FOLDER_SYNC) 2091431215b5fc40d0d6498b0fe602ad4d1b8a66ff3Marc Blank throw new EasParserException(); 210ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank while (nextTag(START_DOCUMENT) != END_DOCUMENT) { 2117c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank if (tag == Tags.FOLDER_STATUS) { 212ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank status = getValueInt(); 213e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank // Do a sanity check on the account here; if we have any duplicated folders, we'll 214e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank // act as though we have a bad folder sync key (wipe/reload mailboxes) 215e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank // Note: The ContentValues isn't used, but no point creating a new one 216e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank int dupes = 0; 217e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank if (mAccountId > 0) { 218e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank dupes = mContentResolver.update( 219e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank ContentUris.withAppendedId(EmailContent.ACCOUNT_CHECK_URI, mAccountId), 220e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank UNINITIALIZED_PARENT_KEY, null, null); 221e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 222e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank if (dupes > 0) { 2236c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu LogUtils.w(TAG, "Duplicate mailboxes found for account %d: %d", mAccountId, 2246c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu dupes); 225e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank status = Eas.FOLDER_STATUS_INVALID_KEY; 226e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 227ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (status != Eas.FOLDER_STATUS_OK) { 2286aa35f65d70f476367b3ee951b4470662a296fa1Marc Blank // If the account hasn't been saved, this is a validation attempt, so we don't 2296aa35f65d70f476367b3ee951b4470662a296fa1Marc Blank // try reloading the folder list... 23077186bb1a174432ef272584374942d8b9228e39cMarc Blank if (CommandStatus.isDeniedAccess(status) || 2316aa35f65d70f476367b3ee951b4470662a296fa1Marc Blank CommandStatus.isNeedsProvisioning(status) || 2326aa35f65d70f476367b3ee951b4470662a296fa1Marc Blank (mAccount.mId == Account.NOT_SAVED)) { 23377186bb1a174432ef272584374942d8b9228e39cMarc Blank throw new CommandStatusException(status); 23477186bb1a174432ef272584374942d8b9228e39cMarc Blank // Note that we need to catch both old-style (Eas.FOLDER_STATUS_INVALID_KEY) 23577186bb1a174432ef272584374942d8b9228e39cMarc Blank // and EAS 14 style command status 23677186bb1a174432ef272584374942d8b9228e39cMarc Blank } else if (status == Eas.FOLDER_STATUS_INVALID_KEY || 23777186bb1a174432ef272584374942d8b9228e39cMarc Blank CommandStatus.isBadSyncKey(status)) { 23828f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon wipe(); 239c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu // Reconstruct _main 240ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank res = true; 2411b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank resetFolders = true; 242ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else { 243ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Other errors are at the server, so let's throw an error that will 244ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // cause this sync to be retried at a later time 2451431215b5fc40d0d6498b0fe602ad4d1b8a66ff3Marc Blank throw new EasParserException("Folder status error"); 246ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 247ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 2487c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank } else if (tag == Tags.FOLDER_SYNC_KEY) { 2496c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final String newKey = getValue(); 2506c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (newKey != null && !resetFolders) { 2516c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mSyncKeyChanged = !newKey.equals(mAccount.mSyncKey); 252e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank mAccount.mSyncKey = newKey; 253e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 2547c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank } else if (tag == Tags.FOLDER_CHANGES) { 25577186bb1a174432ef272584374942d8b9228e39cMarc Blank if (mStatusOnly) return res; 2566c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu changesParser(); 257ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else 258ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 259ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 260c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu if (!mStatusOnly) { 261c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu commit(); 2621b275b9408d5b856e2482fa3951827489e9585ccMarc Blank } 263ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank return res; 264ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 265ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 2666c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 2676c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Get a cursor with folder ids for a specific folder. 2686c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @param serverId The server id for the folder we are interested in. 2696c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @return A cursor for the folder specified by serverId for this account. 2706c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 2716c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private Cursor getServerIdCursor(final String serverId) { 272ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mBindArguments[0] = serverId; 273ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank mBindArguments[1] = mAccountIdAsString; 274e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank return mContentResolver.query(Mailbox.CONTENT_URI, MAILBOX_ID_COLUMNS_PROJECTION, 275ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank WHERE_SERVER_ID_AND_ACCOUNT, mBindArguments, null); 276ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 277ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 2786c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 2796c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Add the appropriate {@link ContentProviderOperation} to {@link #mOperations} for a Delete 2806c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * change in the FolderSync response. 2816c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 2826c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 2836c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void deleteParser() throws IOException { 284135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank while (nextTag(Tags.FOLDER_DELETE) != END) { 285ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 2867c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.FOLDER_SERVER_ID: 287bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu final String serverId = getValue(); 288ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank // Find the mailbox in this account with the given serverId 289bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu final Cursor c = getServerIdCursor(serverId); 290ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank try { 291ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank if (c.moveToFirst()) { 2926c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu LogUtils.i(TAG, "Deleting %s", serverId); 293bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu final long mailboxId = c.getLong(MAILBOX_ID_COLUMNS_ID); 2946c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add(ContentProviderOperation.newDelete( 295ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank ContentUris.withAppendedId(Mailbox.CONTENT_URI, 296bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu mailboxId)).build()); 297e951b589c5134a1154ec3743d79236dee54a6519Marc Blank AttachmentUtilities.deleteAllMailboxAttachmentFiles(mContext, 298bc96ce2b61336a99ce044dcb77d0c69ec9ddb718Yu Ping Hu mAccountId, mailboxId); 2996c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final String parentId = 3006c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu c.getString(MAILBOX_ID_COLUMNS_PARENT_SERVER_ID); 3016c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (!TextUtils.isEmpty(parentId)) { 3026c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mParentFixupsNeeded.add(parentId); 303e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank } 304ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 305ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } finally { 306ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank c.close(); 307ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 308ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 309ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 310ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 311ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 312ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 313ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 314ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 315f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static class SyncOptions { 316f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private final int mInterval; 317f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private final int mLookback; 318f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 319f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private SyncOptions(int interval, int lookback) { 320f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mInterval = interval; 321f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mLookback = lookback; 322f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 323f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 324f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 325f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static final String MAILBOX_STATE_SELECTION = 326f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank MailboxColumns.ACCOUNT_KEY + "=? AND (" + MailboxColumns.SYNC_INTERVAL + "!=" + 327f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank Account.CHECK_INTERVAL_NEVER + " OR " + Mailbox.SYNC_LOOKBACK + "!=" + 32835b892c7570b06e72c97c0915d0e41abc83ed6b0Yu Ping Hu SyncWindow.SYNC_WINDOW_ACCOUNT + ")"; 329f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 330f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static final String[] MAILBOX_STATE_PROJECTION = new String[] { 331f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank MailboxColumns.SERVER_ID, MailboxColumns.SYNC_INTERVAL, MailboxColumns.SYNC_LOOKBACK}; 332f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static final int MAILBOX_STATE_SERVER_ID = 0; 333f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static final int MAILBOX_STATE_INTERVAL = 1; 334f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank private static final int MAILBOX_STATE_LOOKBACK = 2; 335f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank @VisibleForTesting 336f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank final HashMap<String, SyncOptions> mSyncOptionsMap = new HashMap<String, SyncOptions>(); 337f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 338f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank /** 339f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank * For every mailbox in this account that has a non-default interval or lookback, save those 340f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank * values. 341f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank */ 342f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank @VisibleForTesting 343f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank void saveMailboxSyncOptions() { 344f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank // Shouldn't be necessary, but... 345f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mSyncOptionsMap.clear(); 346f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank Cursor c = mContentResolver.query(Mailbox.CONTENT_URI, MAILBOX_STATE_PROJECTION, 347f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank MAILBOX_STATE_SELECTION, new String[] {mAccountIdAsString}, null); 348f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank if (c != null) { 349f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank try { 350f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank while (c.moveToNext()) { 351f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mSyncOptionsMap.put(c.getString(MAILBOX_STATE_SERVER_ID), 352f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank new SyncOptions(c.getInt(MAILBOX_STATE_INTERVAL), 353f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank c.getInt(MAILBOX_STATE_LOOKBACK))); 354f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 355f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } finally { 356f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank c.close(); 357f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 358f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 359f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 360f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 361f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank /** 362f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank * For every set of saved mailbox sync options, try to find and restore those values 363f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank */ 364f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank @VisibleForTesting 365f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank void restoreMailboxSyncOptions() { 366f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank try { 367f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank ContentValues cv = new ContentValues(); 368f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mBindArguments[1] = mAccountIdAsString; 369f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank for (String serverId: mSyncOptionsMap.keySet()) { 370f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank SyncOptions options = mSyncOptionsMap.get(serverId); 371f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank cv.put(MailboxColumns.SYNC_INTERVAL, options.mInterval); 372f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank cv.put(MailboxColumns.SYNC_LOOKBACK, options.mLookback); 373f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mBindArguments[0] = serverId; 374f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank // If we match account and server id, set the sync options 375f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_SERVER_ID_AND_ACCOUNT, 376f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mBindArguments); 377f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 378f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } finally { 379f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank mSyncOptionsMap.clear(); 380f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 381f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 382f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 3836c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 3846c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Add a {@link ContentProviderOperation} to {@link #mOperations} to add a mailbox. 3856c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @param name The new mailbox's name. 3866c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @param serverId The new mailbox's server id. 3876c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @param parentServerId The server id of the new mailbox's parent ("0" if none). 3885586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * @param mailboxType The mailbox's type, which is one of the values defined in {@link Mailbox}. 3895586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu * @param fromServer Whether this mailbox was synced from server (as opposed to local-only). 3906c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 3916c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 3926c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void addMailboxOp(final String name, final String serverId, 3935586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu final String parentServerId, final int mailboxType, final boolean fromServer) 3945586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu throws IOException { 3955586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu final ContentValues cv = new ContentValues(10); 3966c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.DISPLAY_NAME, name); 3975586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (fromServer) { 3985586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.SERVER_ID, serverId); 3995586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu final String parentId; 4005586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (parentServerId.equals("0")) { 4015586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu parentId = NO_MAILBOX_STRING; 4025586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.PARENT_KEY, Mailbox.NO_MAILBOX); 4035586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } else { 4045586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu parentId = parentServerId; 4055586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu mParentFixupsNeeded.add(parentId); 4065586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } 4075586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.PARENT_SERVER_ID, parentId); 4086c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } else { 4095586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.SERVER_ID, ""); 4105586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.PARENT_KEY, Mailbox.NO_MAILBOX); 4115586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.PARENT_SERVER_ID, NO_MAILBOX_STRING); 4125586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu cv.put(MailboxColumns.TOTAL_COUNT, -1); 4136c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 4146c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.ACCOUNT_KEY, mAccountId); 4156c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.TYPE, mailboxType); 4165586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu 4175586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu final boolean shouldSync = fromServer && Mailbox.getDefaultSyncStateForType(mailboxType); 418456a6e3e01205e8c779930d8c7533b1c7467df5eYu Ping Hu cv.put(MailboxColumns.SYNC_INTERVAL, shouldSync ? 1 : 0); 4196c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 4206c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Set basic flags 4216c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu int flags = 0; 4226c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (mailboxType <= Mailbox.TYPE_NOT_EMAIL) { 4236c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu flags |= Mailbox.FLAG_HOLDS_MAIL + Mailbox.FLAG_SUPPORTS_SETTINGS; 4246c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 4256c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Outbox, Drafts, and Sent don't allow mail to be moved to them 4266c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (mailboxType == Mailbox.TYPE_MAIL || mailboxType == Mailbox.TYPE_TRASH || 4276c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mailboxType == Mailbox.TYPE_JUNK || mailboxType == Mailbox.TYPE_INBOX) { 4286c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu flags |= Mailbox.FLAG_ACCEPTS_MOVED_MAIL; 4296c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 4306c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.FLAGS, flags); 4316c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 4326c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Make boxes like Contacts and Calendar invisible in the folder list 4336c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.FLAG_VISIBLE, (mailboxType < Mailbox.TYPE_NOT_EMAIL)); 4346c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 4356c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add( 4366c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu ContentProviderOperation.newInsert(Mailbox.CONTENT_URI).withValues(cv).build()); 4375586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu 4385586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu mCreatedFolderTypes.put(mailboxType, true); 4396c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 4406c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 4416c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 4426c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Add the appropriate {@link ContentProviderOperation} to {@link #mOperations} for an Add 4436c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * change in the FolderSync response. 4446c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 4456c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 4466c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void addParser() throws IOException { 447ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String name = null; 448ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String serverId = null; 449ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank String parentId = null; 450ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank int type = 0; 451ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4527c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.FOLDER_ADD) != END) { 453ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank switch (tag) { 4547c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.FOLDER_DISPLAY_NAME: { 455ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank name = getValue(); 456ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 457ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4587c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.FOLDER_TYPE: { 459ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank type = getValueInt(); 460ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 461ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4627c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.FOLDER_PARENT_ID: { 463ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank parentId = getValue(); 464ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 465ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4667c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank case Tags.FOLDER_SERVER_ID: { 467ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank serverId = getValue(); 468ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank break; 469ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 470ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank default: 471ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 472ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 473ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 4745586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (name != null && serverId != null && parentId != null) { 4755586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu final int mailboxType = MAILBOX_TYPE_MAP.get(type, Mailbox.TYPE_NONE); 4765586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (mailboxType != Mailbox.TYPE_NONE) { 4775586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu addMailboxOp(name, serverId, parentId, mailboxType, true); 4785586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } 479ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 480d3eab5e6ffa39c931c2ca31e6670b7743723e034Marc Blank } 481ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 4826c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 4836c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Add the appropriate {@link ContentProviderOperation} to {@link #mOperations} for an Update 4846c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * change in the FolderSync response. 4856c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 4866c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 4876c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void updateParser() throws IOException { 488135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank String serverId = null; 489135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank String displayName = null; 490135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank String parentId = null; 491135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank while (nextTag(Tags.FOLDER_UPDATE) != END) { 492135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank switch (tag) { 493135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank case Tags.FOLDER_SERVER_ID: 494135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank serverId = getValue(); 495135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank break; 496135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank case Tags.FOLDER_DISPLAY_NAME: 497135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank displayName = getValue(); 498135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank break; 499135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank case Tags.FOLDER_PARENT_ID: 500135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank parentId = getValue(); 501135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank break; 502135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank default: 503135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank skipTag(); 504135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank break; 505135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 506135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 507135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank // We'll make a change if one of parentId or displayName are specified 508135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank // serverId is required, but let's be careful just the same 509135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank if (serverId != null && (displayName != null || parentId != null)) { 5106c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final Cursor c = getServerIdCursor(serverId); 511135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank try { 512135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank // If we find the mailbox (using serverId), make the change 513135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank if (c.moveToFirst()) { 5146c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu LogUtils.i(TAG, "Updating %s", serverId); 5156c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final ContentValues cv = new ContentValues(); 5166c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Store the new parent key. 5176c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(Mailbox.PARENT_SERVER_ID, parentId); 518e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank // Fix up old and new parents, as needed 519e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank if (!TextUtils.isEmpty(parentId)) { 520e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank mParentFixupsNeeded.add(parentId); 5216c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } else { 5226c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(Mailbox.PARENT_KEY, Mailbox.NO_MAILBOX); 523e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank } 5246c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final String oldParentId = c.getString(MAILBOX_ID_COLUMNS_PARENT_SERVER_ID); 525e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank if (!TextUtils.isEmpty(oldParentId)) { 526e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank mParentFixupsNeeded.add(oldParentId); 527e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank } 528e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank // Set display name if we've got one 529135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank if (displayName != null) { 530135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank cv.put(Mailbox.DISPLAY_NAME, displayName); 531135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 5326c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add(ContentProviderOperation.newUpdate( 533135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank ContentUris.withAppendedId(Mailbox.CONTENT_URI, 534e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank c.getLong(MAILBOX_ID_COLUMNS_ID))).withValues(cv).build()); 535135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 536135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } finally { 537135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank c.close(); 538135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 539135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 540135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } 541135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank 5426c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 5436c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Handle the Changes element of the FolderSync response. This is the container for Add, Delete, 5446c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * and Update elements. 5456c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 5466c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 5476c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void changesParser() throws IOException { 5487c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank while (nextTag(Tags.FOLDER_CHANGES) != END) { 5497c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank if (tag == Tags.FOLDER_ADD) { 5506c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu addParser(); 5517c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank } else if (tag == Tags.FOLDER_DELETE) { 5526c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu deleteParser(); 553135e3c2c6653131e57525a50e0a3bc6ccf6c7f45Marc Blank } else if (tag == Tags.FOLDER_UPDATE) { 5546c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu updateParser(); 5557c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank } else if (tag == Tags.FOLDER_COUNT) { 5566c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // TODO: Maybe we can make use of this count somehow. 557ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank getValueInt(); 558ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } else 559ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank skipTag(); 560ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 5616c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 562ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 5636c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 5646c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Commit the contents of {@link #mOperations} to the content provider. 5656c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 5666c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 5676c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void flushOperations() throws IOException { 5686c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (mOperations.isEmpty()) { 5696c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu return; 57092c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank } 571ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler int transactionSize = mOperations.size(); 572ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler final ArrayList<ContentProviderOperation> subOps = 573ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler new ArrayList<ContentProviderOperation>(transactionSize); 574ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler while (!mOperations.isEmpty()) { 575ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler subOps.clear(); 576ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler subOps.addAll(mOperations.subList(0, transactionSize)); 577ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler // Try to apply the ops. If the transaction is too large, split it in half and try again 578ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler // If some other error happens then throw an IOException up the stack. 579ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler try { 580ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler mContentResolver.applyBatch(EmailContent.AUTHORITY, subOps); 581ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler mOperations.removeAll(subOps); 582ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } catch (final TransactionTooLargeException e) { 583ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler // If the transaction is too large, try splitting it. 584ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler if (transactionSize == 1) { 585ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler LogUtils.e(TAG, "Single operation transaction too large"); 586ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler throw new IOException("Single operation transaction too large"); 587ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } 588ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler LogUtils.d(TAG, "Transaction operation count %d too large, halving...", 589ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler transactionSize); 590ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler transactionSize = transactionSize / 2; 591ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler if (transactionSize < 1) { 592ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler transactionSize = 1; 593ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } 594ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } catch (final RemoteException e) { 595ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler LogUtils.e(TAG, "RemoteException in commit"); 596ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler throw new IOException("RemoteException in commit"); 597ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } catch (final OperationApplicationException e) { 598ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler LogUtils.e(TAG, "OperationApplicationException in commit"); 599ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler throw new IOException("OperationApplicationException in commit"); 600ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler } 6016c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 6026c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.clear(); 6036c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 6046c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 6056c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu /** 6066c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Fix folder data for any folders whose parent or children changed during this sync. 6076c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * Unfortunately this cannot be done in the same pass as the actual sync: newly synced folders 6086c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * lack ids until they're committed to the content provider, so we can't set the parentKey 6096c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * for their children. 6106c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * During parsing, we only track the parents who have changed. We need to do a query for 6116c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * children anyway (to determine whether a parent still has any) so it's simpler to not bother 6126c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * tracking which folders have had their parents changed. 6136c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * TODO: Figure out if we can avoid the two-pass. 6146c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu * @throws IOException 6156c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu */ 6166c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu private void doParentFixups() throws IOException { 6176c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (mParentFixupsNeeded.isEmpty()) { 6186c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu return; 6196c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 6206c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 6216c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // These objects will be used in every loop iteration, so create them here for efficiency 6226c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // and just reset the values inside the loop as necessary. 6236c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final String[] bindArguments = new String[2]; 6246c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu bindArguments[1] = mAccountIdAsString; 625ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler final ContentValues cv = new ContentValues(1); 6266c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 6276c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu for (final String parentServerId : mParentFixupsNeeded) { 6286c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Get info about this parent. 6296c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu bindArguments[0] = parentServerId; 6306c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final Cursor parentCursor = mContentResolver.query(Mailbox.CONTENT_URI, 6316c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu FIXUP_PARENT_PROJECTION, WHERE_SERVER_ID_AND_ACCOUNT, bindArguments, null); 6326c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (parentCursor == null) { 6336c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // TODO: Error handling. 6346c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu continue; 6356c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 6366c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final long parentId; 6376c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final int parentFlags; 6386c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu try { 6396c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (parentCursor.moveToFirst()) { 6406c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu parentId = parentCursor.getLong(FIXUP_PARENT_ID_COLUMN); 6416c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu parentFlags = parentCursor.getInt(FIXUP_PARENT_FLAGS_COLUMN); 6426c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } else { 6436c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // TODO: Error handling. 64492c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank continue; 645e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 6466c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } finally { 6476c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu parentCursor.close(); 648e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 64992c9d37d883eaafdbe7d9428a5de017eee9f3d2bMarc Blank 6506c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Fix any children for this parent. 6516c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final Cursor childCursor = mContentResolver.query(Mailbox.CONTENT_URI, 6526c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu FIXUP_CHILD_PROJECTION, WHERE_PARENT_SERVER_ID_AND_ACCOUNT, bindArguments, 6536c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu null); 6546c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu boolean hasChildren = false; 6556c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (childCursor != null) { 656e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank try { 6576c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Clear the results of the last iteration. 6586c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.clear(); 6596c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // All children in this loop share the same parentId. 6606c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.PARENT_KEY, parentId); 6616c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu while (childCursor.moveToNext()) { 6626c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final long childId = childCursor.getLong(FIXUP_CHILD_ID_COLUMN); 6636c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add(ContentProviderOperation.newUpdate( 6646c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu ContentUris.withAppendedId(Mailbox.CONTENT_URI, childId)). 6656c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu withValues(cv).build()); 6666c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu hasChildren = true; 667e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 668e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } finally { 6696c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu childCursor.close(); 670e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 671e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank } 672e6c2456aa6c00ef78c6d1d1621511d7ef8507f83Marc Blank 6736c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Fix the parent's flags based on whether it now has children. 6746c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final int newFlags; 6756c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 6766c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (hasChildren) { 6776c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu newFlags = parentFlags | HAS_CHILDREN_FLAGS; 6786c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } else { 6796c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu newFlags = parentFlags & ~HAS_CHILDREN_FLAGS; 6806c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 6816c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (newFlags != parentFlags) { 6826c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.clear(); 6836c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(MailboxColumns.FLAGS, newFlags); 6846c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add(ContentProviderOperation.newUpdate(ContentUris.withAppendedId( 6856c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu Mailbox.CONTENT_URI, parentId)).withValues(cv).build()); 6866c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 687ab4fe820cb8e1fa3781485ab2e44ec458ce0669eTony Mantler flushOperations(); 6889f551ed0c2794a4ebb775df0dc5f714cf07f29b7Marc Blank } 689ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank } 690ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank 6910a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank @Override 6920a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank public void commandsParser() throws IOException { 6930a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank } 6940a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank 69548af7392c82262d17700e3fbdccf3a582809d449Marc Blank @Override 69648af7392c82262d17700e3fbdccf3a582809d449Marc Blank public void commit() throws IOException { 6976c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Set the account sync key. 6986c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu if (mSyncKeyChanged) { 6996c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu final ContentValues cv = new ContentValues(1); 7006c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey); 7016c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu mOperations.add( 7026c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu ContentProviderOperation.newUpdate(mAccount.getUri()).withValues(cv).build()); 7036c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 7046c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 7055586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu // If this is the initial sync, make sure we have all the required folder types. 7065586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (mInitialSync) { 7075586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu for (final int requiredType : Mailbox.REQUIRED_FOLDER_TYPES) { 7085586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu if (!mCreatedFolderTypes.get(requiredType)) { 7095586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu addMailboxOp(Mailbox.getSystemMailboxName(mContext, requiredType), 7105586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu null, null, requiredType, false); 7115586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } 7125586f9f5ab654ca93d797fa2a8cbc78a8d6970a4Yu Ping Hu } 7136c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu } 7146c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 7156c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Send all operations so far. 7166c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu flushOperations(); 7176c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 7186c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu // Now that new mailboxes are committed, let's do parent fixups. 7196c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu doParentFixups(); 7206c4767d056fc1ad6bb3986d8e54bf7dfcbd61b06Yu Ping Hu 721f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank // Look for sync issues and its children and delete them 722f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank // I'm not aware of any other way to deal with this properly 723f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mBindArguments[0] = "Sync Issues"; 724f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mBindArguments[1] = mAccountIdAsString; 725f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank Cursor c = mContentResolver.query(Mailbox.CONTENT_URI, 726f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank MAILBOX_ID_COLUMNS_PROJECTION, WHERE_DISPLAY_NAME_AND_ACCOUNT, 727f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mBindArguments, null); 728f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank String parentServerId = null; 729f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank long id = 0; 730f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank try { 731f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank if (c.moveToFirst()) { 732e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank id = c.getLong(MAILBOX_ID_COLUMNS_ID); 733e1358075882e5abfb37f8f3ff2266e5a0fabbcfcMarc Blank parentServerId = c.getString(MAILBOX_ID_COLUMNS_SERVER_ID); 734f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank } 735f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank } finally { 736f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank c.close(); 737f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank } 738f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank if (parentServerId != null) { 739f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mContentResolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, id), 740f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank null, null); 741f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mBindArguments[0] = parentServerId; 742f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mContentResolver.delete(Mailbox.CONTENT_URI, WHERE_PARENT_SERVER_ID_AND_ACCOUNT, 743f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank mBindArguments); 744f2465b983215c848d2082b1421af0d5b523d23d0Marc Blank } 745f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank 746f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank // If we have saved options, restore them now 747f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank if (mInitialSync) { 748f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank restoreMailboxSyncOptions(); 749f80dd6855e64091ccac83f1bf37cd808ef2f3e71Marc Blank } 75048af7392c82262d17700e3fbdccf3a582809d449Marc Blank } 75148af7392c82262d17700e3fbdccf3a582809d449Marc Blank 7520a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank @Override 75348af7392c82262d17700e3fbdccf3a582809d449Marc Blank public void responsesParser() throws IOException { 75448af7392c82262d17700e3fbdccf3a582809d449Marc Blank } 75548af7392c82262d17700e3fbdccf3a582809d449Marc Blank 75628f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon @Override 75728f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon protected void wipe() { 75828f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon EasCalendarSyncHandler.wipeAccountFromContentProvider(mContext, 75928f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mAccount.mEmailAddress); 76028f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon EasContactsSyncHandler.wipeAccountFromContentProvider(mContext, 76128f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mAccount.mEmailAddress); 76228f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon 76328f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon // Save away any mailbox sync information that is NOT default 76428f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon saveMailboxSyncOptions(); 76528f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon // And only then, delete mailboxes 76628f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mContentResolver.delete(Mailbox.CONTENT_URI, WHERE_ACCOUNT_KEY, 76728f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon new String[] {mAccountIdAsString}); 76828f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon // Reset the sync key and save. 76928f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mAccount.mSyncKey = "0"; 77028f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon ContentValues cv = new ContentValues(); 77128f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey); 77228f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI, 77328f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon mAccount.mId), cv, null, null); 77428f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon } 775ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank} 776