Handle redirect errors in Ping.

Change-Id: I2fa5ebe04106f51d699c927ae41a265aaec1cedb
diff --git a/src/com/android/exchange/adapter/PingParser.java b/src/com/android/exchange/adapter/PingParser.java
index ad0a7fe..8c923ed 100644
--- a/src/com/android/exchange/adapter/PingParser.java
+++ b/src/com/android/exchange/adapter/PingParser.java
@@ -37,6 +37,8 @@
     // Values less than STATUS_FAILED are never actually returned by the PingParser. They detect
     // error statuses that happen outside the actual parsing, but since they are used in the same
     // context as parsing statuses, it's convenient to have them here.
+    /** Indicates that the ping returned a redirect error. */
+    public static final int STATUS_REDIRECT = -6;
     /** Indicates that the ping terminated due to an exception while making the POST. */
     public static final int STATUS_NETWORK_EXCEPTION = -5;
     /** Indicates that the ping was interrupted by a sync request. */
@@ -136,14 +138,22 @@
      * @return Whether we should send another ping immediately.
      */
     public static boolean shouldPingAgain(final int pingStatus) {
-        // We only want to ping again if the previous ping timed out, or got a server response
-        // that indicates a new ping is warranted.
-        return pingStatus == STATUS_EXPIRED ||
-                pingStatus == STATUS_REQUEST_INCOMPLETE ||
-                pingStatus == STATUS_REQUEST_MALFORMED ||
+        // Explanation for why we ping again for each case:
+        // - Redirect errors have already been processed by updating the HostAuth to reflect the
+        //   new address, so we just ping again for those.
+        // - If the ping expired we should keep looping with pings.
+        // - The EAS spec says to handle incomplete and malformed request errors by pinging again
+        //   with corrected request data. Since we always send a complete request, we simply
+        //   repeat (and assume that some sort of network error is what caused the corruption).
+        // - Heartbeat errors are handled by pinging with a better heartbeat value.
+        // - Other server errors are considered transient and therefore we just reping for those.
+        return pingStatus == STATUS_REDIRECT
+                || pingStatus == STATUS_EXPIRED
+                || pingStatus == STATUS_REQUEST_INCOMPLETE
+                || pingStatus == STATUS_REQUEST_MALFORMED
                 // TODO: Implement heartbeat adjusting and re-enable this.
-                //pingStatus == STATUS_REQUEST_HEARTBEAT_OUT_OF_BOUNDS ||
-                pingStatus == STATUS_SERVER_ERROR;
+                // || pingStatus == STATUS_REQUEST_HEARTBEAT_OUT_OF_BOUNDS
+                || pingStatus == STATUS_SERVER_ERROR;
     }
 
     /**
diff --git a/src/com/android/exchange/service/EasPingSyncHandler.java b/src/com/android/exchange/service/EasPingSyncHandler.java
index 1ddaacd..5dff931 100644
--- a/src/com/android/exchange/service/EasPingSyncHandler.java
+++ b/src/com/android/exchange/service/EasPingSyncHandler.java
@@ -318,6 +318,10 @@
                 LogUtils.i(TAG, "Auth Error for account %d", mAccount.mId);
                 return PingParser.STATUS_FAILED;
             }
+            if (EasResponse.isRedirectError(code)) {
+                redirectHostAuth(resp.getRedirectAddress());
+                return PingParser.STATUS_REDIRECT;
+            }
             if (code != HttpStatus.SC_OK || resp.isEmpty()) {
                 LogUtils.e(TAG, "Bad response (%d) for account %d", code, mAccount.mId);
                 return PingParser.STATUS_FAILED;