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
20680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blankimport android.content.ContentResolver;
21680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blankimport android.content.ContentValues;
22680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blankimport android.content.Context;
2336e181376b06c8905af2d22bf494a2423f50aa65Alon Albertimport android.content.OperationApplicationException;
24f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Huimport android.os.Bundle;
2536e181376b06c8905af2d22bf494a2423f50aa65Alon Albertimport android.os.RemoteException;
26680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank
277372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.Account;
28f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Huimport com.android.emailcommon.provider.EmailContent;
29c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns;
304d8774462ace9a45154b2df418b9f2fe7a9c685dBen Komaloimport com.android.emailcommon.provider.Mailbox;
3177186bb1a174432ef272584374942d8b9228e39cMarc Blankimport com.android.exchange.CommandStatusException;
3277186bb1a174432ef272584374942d8b9228e39cMarc Blankimport com.android.exchange.CommandStatusException.CommandStatus;
33110837ebff288a75f9bda067c38e2c46797d99b5Alon Albertimport com.android.exchange.Eas;
3436e181376b06c8905af2d22bf494a2423f50aa65Alon Albertimport com.android.mail.utils.LogUtils;
35ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
3667698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport java.io.IOException;
3767698e240187c902bed123bf18d342ff25ec75c7Marc Blankimport java.io.InputStream;
38ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
39ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank/**
40ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Base class for the Email and PIM sync parsers
41ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Handles the basic flow of syncKeys, looping to get more data, handling errors, etc.
42ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank * Each subclass must implement a handful of methods that relate specifically to the data type
43ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank *
44ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank */
45368adeb5779fed5d64770d2131125dd93e43ab78Marc Blankpublic abstract class AbstractSyncParser extends Parser {
46110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert    private static final String TAG = Eas.LOG_TAG;
4736e181376b06c8905af2d22bf494a2423f50aa65Alon Albert
481b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank    protected Mailbox mMailbox;
491b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank    protected Account mAccount;
501b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank    protected Context mContext;
511b06024587a4499bcf3f9005337e8f7cae5ffa26Marc Blank    protected ContentResolver mContentResolver;
52ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
538efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank    private boolean mLooping;
548efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank
55c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    public AbstractSyncParser(final Context context, final ContentResolver resolver,
56c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final InputStream in, final Mailbox mailbox, final Account account) throws IOException {
57c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        super(in);
58c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        init(context, resolver, mailbox, account);
59c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
60c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
6148af7392c82262d17700e3fbdccf3a582809d449Marc Blank    public AbstractSyncParser(InputStream in, AbstractSyncAdapter adapter) throws IOException {
62ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        super(in);
6326d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank        init(adapter);
6426d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank    }
6526d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank
6626d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank    public AbstractSyncParser(Parser p, AbstractSyncAdapter adapter) throws IOException {
6726d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank        super(p);
6826d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank        init(adapter);
6926d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank    }
7026d9677a1eb48553241897b63a77bbd33daa9f92Marc Blank
710756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon    public AbstractSyncParser(final Parser p, final Context context, final ContentResolver resolver,
720756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon        final Mailbox mailbox, final Account account) throws IOException {
730756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon        super(p);
740756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon        init(context, resolver, mailbox, account);
750756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon    }
760756a9ff8e69b8cc52374fa68efb2e81971ee5c4Martin Hibdon
77c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private void init(final AbstractSyncAdapter adapter) {
78c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        init(adapter.mContext, adapter.mContext.getContentResolver(), adapter.mMailbox,
79c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                adapter.mAccount);
80c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    }
81c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu
82c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu    private void init(final Context context, final ContentResolver resolver, final Mailbox mailbox,
83c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu            final Account account) {
84c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mContext = context;
85c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mContentResolver = resolver;
86c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mMailbox = mailbox;
87c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        mAccount = account;
88ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
89ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
90ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    /**
91ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * Read, parse, and act on incoming commands from the Exchange server
92ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * @throws IOException if the connection is broken
9377186bb1a174432ef272584374942d8b9228e39cMarc Blank     * @throws CommandStatusException
94ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     */
9577186bb1a174432ef272584374942d8b9228e39cMarc Blank    public abstract void commandsParser() throws IOException, CommandStatusException;
96ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
97ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    /**
98ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * Read, parse, and act on server responses
99ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * @throws IOException
100ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     */
10148af7392c82262d17700e3fbdccf3a582809d449Marc Blank    public abstract void responsesParser() throws IOException;
10248af7392c82262d17700e3fbdccf3a582809d449Marc Blank
10348af7392c82262d17700e3fbdccf3a582809d449Marc Blank    /**
10448af7392c82262d17700e3fbdccf3a582809d449Marc Blank     * Commit any changes found during parsing
10548af7392c82262d17700e3fbdccf3a582809d449Marc Blank     * @throws IOException
10648af7392c82262d17700e3fbdccf3a582809d449Marc Blank     */
10736e181376b06c8905af2d22bf494a2423f50aa65Alon Albert    public abstract void commit() throws IOException, RemoteException,
10836e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            OperationApplicationException;
109ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
1108efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank    public boolean isLooping() {
1118efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank        return mLooping;
1128efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank    }
1138efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank
114ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    /**
11577186bb1a174432ef272584374942d8b9228e39cMarc Blank     * Skip through tags until we reach the specified end tag
11677186bb1a174432ef272584374942d8b9228e39cMarc Blank     * @param endTag the tag we end with
11777186bb1a174432ef272584374942d8b9228e39cMarc Blank     * @throws IOException
11877186bb1a174432ef272584374942d8b9228e39cMarc Blank     */
11977186bb1a174432ef272584374942d8b9228e39cMarc Blank    public void skipParser(int endTag) throws IOException {
12077186bb1a174432ef272584374942d8b9228e39cMarc Blank        while (nextTag(endTag) != END) {
12177186bb1a174432ef272584374942d8b9228e39cMarc Blank            skipTag();
12277186bb1a174432ef272584374942d8b9228e39cMarc Blank        }
12377186bb1a174432ef272584374942d8b9228e39cMarc Blank    }
12477186bb1a174432ef272584374942d8b9228e39cMarc Blank
12577186bb1a174432ef272584374942d8b9228e39cMarc Blank    /**
126ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * Loop through the top-level structure coming from the Exchange server
127ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * Sync keys and the more available flag are handled here, whereas specific data parsing
128ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     * is handled by abstract methods implemented for each data class (e.g. Email, Contacts, etc.)
12977186bb1a174432ef272584374942d8b9228e39cMarc Blank     * @throws CommandStatusException
130ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank     */
1317c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank    @Override
13277186bb1a174432ef272584374942d8b9228e39cMarc Blank    public boolean parse() throws IOException, CommandStatusException {
133ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        int status;
134ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        boolean moreAvailable = false;
135da7f22d3a76dca40eaa95243288cea576852864cMarc Blank        boolean newSyncKey = false;
1368efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank        mLooping = false;
137ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // If we're not at the top of the xml tree, throw an exception
1387c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank        if (nextTag(START_DOCUMENT) != Tags.SYNC_SYNC) {
1391431215b5fc40d0d6498b0fe602ad4d1b8a66ff3Marc Blank            throw new EasParserException();
140ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
141a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank
142a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank        boolean mailboxUpdated = false;
143a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank        ContentValues cv = new ContentValues();
144a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank
145ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // Loop here through the remaining xml
146ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
1477c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            if (tag == Tags.SYNC_COLLECTION || tag == Tags.SYNC_COLLECTIONS) {
148ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                // Ignore these tags, since we've only got one collection syncing in this loop
1497c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            } else if (tag == Tags.SYNC_STATUS) {
150ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                // Status = 1 is success; everything else is a failure
151ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                status = getValueInt();
152ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                if (status != 1) {
15377186bb1a174432ef272584374942d8b9228e39cMarc Blank                    if (status == 3 || CommandStatus.isBadSyncKey(status)) {
154ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        // Must delete all of the data and start over with syncKey of "0"
155c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                        mMailbox.mSyncKey = "0";
1565cc7ea3e24f1c05f71a3223ac6fa8b69d211735cYu Ping Hu                        newSyncKey = true;
157722006c7b116240d9383c84d5e76ee69796dd571Alon Albert                        wipe();
158ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        // Indicate there's more so that we'll start syncing again
159ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                        moreAvailable = true;
160f7b0fd783fa0eec52473e0d0b832bc5adee1d69bMarc Blank                    } else if (status == 16 || status == 5) {
161f7b0fd783fa0eec52473e0d0b832bc5adee1d69bMarc Blank                        // Status 16 indicates a transient server error (indeterminate state)
162f7b0fd783fa0eec52473e0d0b832bc5adee1d69bMarc Blank                        // Status 5 indicates "server error"; this tends to loop for a while so
163f7b0fd783fa0eec52473e0d0b832bc5adee1d69bMarc Blank                        // throwing IOException will at least provide backoff behavior
1645ec3d0587c18603167f7a751c9b8974ba7a19758Marc Blank                        throw new IOException();
165680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                    } else if (status == 8 || status == 12) {
166680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        // Status 8 is Bad; it means the server doesn't recognize the serverId it
167680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        // sent us.  12 means that we're being asked to refresh the folder list.
168680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        // We'll do that with 8 also...
169f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                        // TODO: Improve this -- probably best to do this synchronously and then
170f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                        // immediately retry the current sync.
171f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                        final Bundle extras = new Bundle(1);
172f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                        extras.putBoolean(Mailbox.SYNC_EXTRA_ACCOUNT_ONLY, true);
173f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                        ContentResolver.requestSync(new android.accounts.Account(
174f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                                mAccount.mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
175f7773165a611f7cdf97aa9c289e41cfcaa28f7aeYu Ping Hu                                EmailContent.AUTHORITY, extras);
176680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        // We don't have any provision for telling the user "wait a minute while
177680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        // we sync folders"...
178680e59f477fe2221ffa6d5bb6b3c8fe64c1f5a74Marc Blank                        throw new IOException();
179376260021db980af284f824f0c918b203e965407Marc Blank                    } else if (status == 7) {
1807d35f61afc910b8f21d3225762c251df10dc76eaYu Ping Hu                        // TODO: Fix this. The handling here used to be pretty bogus, and it's not
1817d35f61afc910b8f21d3225762c251df10dc76eaYu Ping Hu                        // obvious that simply forcing another resync makes sense here.
18261c48abf43082f3094f21fd4c645ad9cf4dfbd74Marc Blank                        moreAvailable = true;
18377186bb1a174432ef272584374942d8b9228e39cMarc Blank                    } else {
1849cdb8c8219349c654101ee5fc71e2986a6cebc3bAlon Albert                        LogUtils.e(LogUtils.TAG, "Sync: Unknown status: " + status);
18577186bb1a174432ef272584374942d8b9228e39cMarc Blank                        // Access, provisioning, transient, etc.
18677186bb1a174432ef272584374942d8b9228e39cMarc Blank                        throw new CommandStatusException(status);
187ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    }
188ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                }
1897c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            } else if (tag == Tags.SYNC_COMMANDS) {
190ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                commandsParser();
1917c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            } else if (tag == Tags.SYNC_RESPONSES) {
192ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                responsesParser();
1937c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            } else if (tag == Tags.SYNC_MORE_AVAILABLE) {
194ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                moreAvailable = true;
1957c582a7fb883b3be728f270fbe5277676fe37cf9Marc Blank            } else if (tag == Tags.SYNC_SYNC_KEY) {
196c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                if (mMailbox.mSyncKey.equals("0")) {
197ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                    moreAvailable = true;
1989d4ac93efbba01afe668f9406feec69b3a2374ebMarc Blank                }
199ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                String newKey = getValue();
2000a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank                userLog("Parsed key for ", mMailbox.mDisplayName, ": ", newKey);
201a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank                if (!newKey.equals(mMailbox.mSyncKey)) {
202c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu                    mMailbox.mSyncKey = newKey;
203a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank                    cv.put(MailboxColumns.SYNC_KEY, newKey);
204a05c26d8d2cce3faa152096cb8116fce375c6d81Marc Blank                    mailboxUpdated = true;
205da7f22d3a76dca40eaa95243288cea576852864cMarc Blank                    newSyncKey = true;
206da7f22d3a76dca40eaa95243288cea576852864cMarc Blank                }
207ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank           } else {
208ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank                skipTag();
209ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank           }
210ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        }
211ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
212da7f22d3a76dca40eaa95243288cea576852864cMarc Blank        // If we don't have a new sync key, ignore moreAvailable (or we'll loop)
213da7f22d3a76dca40eaa95243288cea576852864cMarc Blank        if (moreAvailable && !newSyncKey) {
21438ebc3d89a3c82589cf7bb413dc26c1a70b1a802Alon Albert            LogUtils.e(TAG, "Looping detected");
2158efd25be4e1db3c0c79aae2ca1b4664b21bb410bMarc Blank            mLooping = true;
216da7f22d3a76dca40eaa95243288cea576852864cMarc Blank        }
217da7f22d3a76dca40eaa95243288cea576852864cMarc Blank
21848af7392c82262d17700e3fbdccf3a582809d449Marc Blank        // Commit any changes
21936e181376b06c8905af2d22bf494a2423f50aa65Alon Albert        try {
22036e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            commit();
22136e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            if (mailboxUpdated) {
22236e181376b06c8905af2d22bf494a2423f50aa65Alon Albert                mMailbox.update(mContext, cv);
22336e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            }
22436e181376b06c8905af2d22bf494a2423f50aa65Alon Albert        } catch (RemoteException e) {
22536e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            LogUtils.e(TAG, "Failed to commit changes", e);
22636e181376b06c8905af2d22bf494a2423f50aa65Alon Albert        } catch (OperationApplicationException e) {
22736e181376b06c8905af2d22bf494a2423f50aa65Alon Albert            LogUtils.e(TAG, "Failed to commit changes", e);
22827cf341571fac3d8dbe866f503c34fc31e02bf85Marc Blank        }
229ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        // Let the caller know that there's more to do
2300638c5ede5fc97b32e4b48d40c431c007860d0f6Marc Blank        if (moreAvailable) {
2310638c5ede5fc97b32e4b48d40c431c007860d0f6Marc Blank            userLog("MoreAvailable");
2320638c5ede5fc97b32e4b48d40c431c007860d0f6Marc Blank        }
233ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank        return moreAvailable;
234ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank    }
235ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
23628f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon    abstract protected void wipe();
237722006c7b116240d9383c84d5e76ee69796dd571Alon Albert
2380a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank    void userLog(String ...strings) {
239c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // TODO: Convert to other logging types?
240c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        //mService.userLog(strings);
2410a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank    }
242ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank
2430a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank    void userLog(String string, int num, String string2) {
244c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        // TODO: Convert to other logging types?
245c9e47f85203da0ea3b6e9a49aa2007d1fc6f0814Yu Ping Hu        //mService.userLog(string, num, string2);
2460a4d05f0d8753c67364f7167e62cea82aef9a81eMarc Blank    }
247ab30d429e0c6069604aead9b5e6845b6b91b6a02Marc Blank}
248