Add ability to parse HTTP-format moratorium times
(since pretty much every user wants this).
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index 71b22ce..c7b12d3 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -192,7 +192,6 @@
 
     /**
      * Forbid any operations until after a certain (absolute) time.
-     * Commonly used when a server returns a "Retry-After:" type directive.
      * Limited by {@link #Options.maxMoratoriumMillis}.
      *
      * @param millis wall clock time ({@link System#currentTimeMillis()}) to
@@ -206,6 +205,29 @@
     }
 
     /**
+     * Forbid any operations until after a certain time, as specified in
+     * the format used by the HTTP "Retry-After" header.
+     * Limited by {@link #Options.maxMoratoriumMillis}.
+     *
+     * @param retryAfter moratorium time in HTTP format
+     * @return true if a time was successfully parsed
+     */
+    public boolean setMoratoriumTimeHttp(String retryAfter) {
+        try {
+            long ms = Long.valueOf(retryAfter) * 1000;
+            setMoratoriumTimeMillis(ms + System.currentTimeMillis());
+            return true;
+        } catch (NumberFormatException nfe) {
+            try {
+                setMoratoriumTimeMillis(HttpDateTime.parse(retryAfter));
+                return true;
+            } catch (IllegalArgumentException iae) {
+                return false;
+            }
+        }
+    }
+
+    /**
      * Enable or disable all operations.  When disabled, all calls to
      * {@link #getNextTimeMillis()} return {@link Long#MAX_VALUE}.
      * Commonly used when data network availability goes up and down.
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
index 13f710d..28178b5 100644
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -113,4 +113,32 @@
                 "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
                  OperationScheduler.parseOptions("", options).toString());
     }
+
+    public void testMoratoriumWithHttpDate() throws Exception {
+        String name = "OperationSchedulerTest.testMoratoriumWithHttpDate";
+        SharedPreferences storage = getContext().getSharedPreferences(name, 0);
+        storage.edit().clear().commit();
+
+        OperationScheduler scheduler = new OperationScheduler(storage);
+        OperationScheduler.Options options = new OperationScheduler.Options();
+
+        long beforeTrigger = System.currentTimeMillis();
+        scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
+        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+
+        scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000);
+        assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options));
+
+        long beforeMoratorium = System.currentTimeMillis();
+        assertTrue(scheduler.setMoratoriumTimeHttp("3000"));
+        long afterMoratorium = System.currentTimeMillis();
+        assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options));
+        assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options));
+
+        options.maxMoratoriumMillis = Long.MAX_VALUE / 2;
+        assertTrue(scheduler.setMoratoriumTimeHttp("Fri, 31 Dec 2030 23:59:59 GMT"));
+        assertEquals(1924991999000L, scheduler.getNextTimeMillis(options));
+
+        assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date"));
+    }
 }