Handle "responses" properly in Email sync

* We need to parse our way through the Responses tag (this was
  never used before EAS 14) and retry those updates that fail
* Also, small tweaks to improve Parser logging

Bug: 5123688
Change-Id: I78ae35145d85fd14413dadcc69388dfc619ae416
diff --git a/src/com/android/exchange/adapter/EmailSyncAdapter.java b/src/com/android/exchange/adapter/EmailSyncAdapter.java
index 1f8aee9..e951cfc 100644
--- a/src/com/android/exchange/adapter/EmailSyncAdapter.java
+++ b/src/com/android/exchange/adapter/EmailSyncAdapter.java
@@ -47,6 +47,7 @@
 import com.android.emailcommon.provider.EmailContent.SyncColumns;
 import com.android.emailcommon.provider.Mailbox;
 import com.android.emailcommon.provider.Policy;
+import com.android.emailcommon.provider.ProviderUnavailableException;
 import com.android.emailcommon.service.SyncWindow;
 import com.android.emailcommon.utility.AttachmentUtilities;
 import com.android.emailcommon.utility.ConversionUtilities;
@@ -841,8 +842,10 @@
         private Cursor getServerIdCursor(String serverId, String[] projection) {
             mBindArguments[0] = serverId;
             mBindArguments[1] = mMailboxIdAsString;
-            return mContentResolver.query(Message.CONTENT_URI, projection,
+            Cursor c = mContentResolver.query(Message.CONTENT_URI, projection,
                     WHERE_SERVER_ID_AND_MAILBOX_KEY, mBindArguments, null);
+            if (c == null) throw new ProviderUnavailableException();
+            return c;
         }
 
         @VisibleForTesting
@@ -974,11 +977,43 @@
             }
         }
 
+        /**
+         * Removed any messages with status 7 (mismatch) from the updatedIdList
+         * @param endTag the tag we end with
+         * @throws IOException
+         */
+        public void failedUpdateParser(int endTag) throws IOException {
+            // We get serverId and status in the responses
+            String serverId = null;
+            while (nextTag(endTag) != END) {
+                if (tag == Tags.SYNC_STATUS) {
+                    int status = getValueInt();
+                    if (status == 7 && serverId != null) {
+                        Cursor c = getServerIdCursor(serverId, Message.ID_COLUMN_PROJECTION);
+                        try {
+                            if (c.moveToFirst()) {
+                                Long id = c.getLong(Message.ID_PROJECTION_COLUMN);
+                                mService.userLog("Update of " + serverId + " failed; will retry");
+                                mUpdatedIdList.remove(id);
+                                mService.mUpsyncFailed = true;
+                            }
+                        } finally {
+                            c.close();
+                        }
+                    }
+                } else if (tag == Tags.SYNC_SERVER_ID) {
+                    serverId = getValue();
+                } else {
+                    skipTag();
+                }
+            }
+        }
+
         @Override
         public void responsesParser() throws IOException {
             while (nextTag(Tags.SYNC_RESPONSES) != END) {
                 if (tag == Tags.SYNC_ADD || tag == Tags.SYNC_CHANGE || tag == Tags.SYNC_DELETE) {
-                    // We can ignore all of these
+                    failedUpdateParser(tag);
                 } else if (tag == Tags.SYNC_FETCH) {
                     try {
                         fetchedEmails.add(addParser());
diff --git a/src/com/android/exchange/adapter/Parser.java b/src/com/android/exchange/adapter/Parser.java
index dd11290..3b89863 100644
--- a/src/com/android/exchange/adapter/Parser.java
+++ b/src/com/android/exchange/adapter/Parser.java
@@ -38,6 +38,8 @@
  *
  */
 public abstract class Parser {
+    private static final boolean LOG_VERBOSE = false;
+
     // The following constants are Wbxml standard
     public static final int START_DOCUMENT = 0;
     public static final int DONE = 1;
@@ -403,6 +405,7 @@
     private void pop() {
         if (logging) {
             name = nameArray[depth];
+            log("</" + name + '>');
         }
         // Retrieve the now-current startTag from our stack
         startTag = endTag = startTagArray[depth];
@@ -418,9 +421,7 @@
         if (logging) {
             name = tagTable[startTag - TAG_BASE];
             nameArray[depth] = name;
-            if (noContent) {
-                log("<" + name + "/>");
-            }
+            log("<" + name + (noContent ? '/' : "") + '>');
         }
         // Save the startTag to our stack
         startTagArray[depth] = startTag;
@@ -453,6 +454,9 @@
             int pg = readByte();
             // Save the shifted page to add into the startTag in nextTag
             page = pg << Tags.PAGE_SHIFT;
+            if (LOG_VERBOSE) {
+                log("Page: " + page);
+            }
             // Retrieve the current tag table
             tagTable = tagTables[pg];
             id = nextId();
@@ -519,6 +523,9 @@
         if (capture) {
             captureArray.add(i);
         }
+        if (LOG_VERBOSE) {
+            log("Byte: " + i);
+        }
         return i;
     }