Update AnimationScheduler to use modern APIs

Change AnimationScheduler to start using requestAnimationFrame
on IE10, IE11, and any future browsers that have an unprefixed
requestAnimationFrame.
Chrome 24, Firefox 23 and IE10 already have a unprefixed versions.
Updated implementation to try unprefixed versions first,
then falling back to a polyfill using window.setTimeout.
Removed the need for rebinding due to the polyfill.

Change-Id: Ie00d1020285ce41c571054709bbe19aeef348975
diff --git a/user/src/com/google/gwt/animation/Animation.gwt.xml b/user/src/com/google/gwt/animation/Animation.gwt.xml
index da4be54..2f6ba62 100644
--- a/user/src/com/google/gwt/animation/Animation.gwt.xml
+++ b/user/src/com/google/gwt/animation/Animation.gwt.xml
@@ -24,23 +24,4 @@
   <inherits name="com.google.gwt.user.User"/>
   <source path="client" />
   <public path="public" />
-
-  <!-- Fallback implementation, based on a timer -->
-  <replace-with class="com.google.gwt.animation.client.AnimationSchedulerImplTimer">
-    <when-type-is class="com.google.gwt.animation.client.AnimationScheduler"/>
-  </replace-with>
-
-  <!-- Implementation based on mozRequestAnimationFrame -->
-  <replace-with class="com.google.gwt.animation.client.AnimationSchedulerImplMozilla">
-    <when-type-is class="com.google.gwt.animation.client.AnimationScheduler"/>
-    <when-property-is name="user.agent" value="gecko1_8"/>
-    <when-property-is name="webApiUsage" value="modern"/>
-  </replace-with>
-
-  <!-- Implementation based on webkitRequestAnimationFrame -->
-  <replace-with class="com.google.gwt.animation.client.AnimationSchedulerImplWebkit">
-    <when-type-is class="com.google.gwt.animation.client.AnimationScheduler"/>
-    <when-property-is name="user.agent" value="safari"/>
-    <when-property-is name="webApiUsage" value="modern"/>
-  </replace-with>
 </module>
diff --git a/user/src/com/google/gwt/animation/client/AnimationScheduler.java b/user/src/com/google/gwt/animation/client/AnimationScheduler.java
index 1432ce8..64df638 100644
--- a/user/src/com/google/gwt/animation/client/AnimationScheduler.java
+++ b/user/src/com/google/gwt/animation/client/AnimationScheduler.java
@@ -49,11 +49,17 @@
     public abstract void cancel();
   }
 
+  private static AnimationScheduler instance;
+
   /**
    * Returns the default implementation of the AnimationScheduler API.
    */
   public static AnimationScheduler get() {
-    return AnimationSchedulerImpl.INSTANCE;
+    if (instance == null) {
+      instance = AnimationSchedulerImplStandard.isNativelySupported()
+              ? new AnimationSchedulerImplStandard() : new AnimationSchedulerImplTimer();
+    }
+    return instance;
   }
 
   /**
diff --git a/user/src/com/google/gwt/animation/client/AnimationSchedulerImpl.java b/user/src/com/google/gwt/animation/client/AnimationSchedulerImpl.java
deleted file mode 100644
index fc36fc9..0000000
--- a/user/src/com/google/gwt/animation/client/AnimationSchedulerImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.animation.client;
-
-import com.google.gwt.core.client.GWT;
-
-/**
- * Base class for animation implementations.
- */
-abstract class AnimationSchedulerImpl extends AnimationScheduler {
-
-  /**
-   * The singleton instance of animation scheduler.
-   */
-  static final AnimationScheduler INSTANCE;
-
-  static {
-    AnimationScheduler impl = GWT.create(AnimationScheduler.class);
-
-    /*
-     * If the implementation isn't natively supported, revert back to the timer
-     * based implementation.
-     * 
-     * If impl==null (such as with GWTMockUitlities.disarm()), use null. We
-     * don't want to create a new AnimationSchedulerImplTimer in this case.
-     */
-    if (impl instanceof AnimationSchedulerImpl) {
-      if (!((AnimationSchedulerImpl) impl).isNativelySupported()) {
-        impl = new AnimationSchedulerImplTimer();
-      }
-    }
-
-    INSTANCE = impl;
-  }
-
-  /**
-   * Check if the implementation is natively supported.
-   * 
-   * @return true if natively supported, false if not
-   */
-  protected abstract boolean isNativelySupported();
-}
diff --git a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplMozilla.java b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplMozilla.java
deleted file mode 100644
index 157a53e..0000000
--- a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplMozilla.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.animation.client;
-
-import com.google.gwt.dom.client.Element;
-
-/**
- * Implementation using <code>mozRequestAnimationFrame</code>.
- * 
- * @see <a
- *      href="https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame">
- *      Documentation on the MDN</a>
- */
-class AnimationSchedulerImplMozilla extends AnimationSchedulerImpl {
-
-  /**
-   * Mozilla implementation of {@link AnimationScheduler.AnimationHandle}.
-   * Mozilla does not provide a request ID, so we mark a boolean in the handle
-   * and check it in the callback wrapper.
-   */
-  private class AnimationHandleImpl extends AnimationHandle {
-    @SuppressWarnings("unused")
-    private boolean canceled;
-
-    @Override
-    public void cancel() {
-      canceled = true;
-    }
-  }
-
-  @Override
-  public AnimationHandle requestAnimationFrame(AnimationCallback callback, Element element) {
-    AnimationHandleImpl handle = new AnimationHandleImpl();
-    requestAnimationFrameImpl(callback, handle);
-    return handle;
-  }
-
-  @Override
-  protected native boolean isNativelySupported() /*-{
-    return !!$wnd.mozRequestAnimationFrame;
-  }-*/;
-
-  /**
-   * Request an animation frame. Firefox does not return a request ID, so we
-   * create a JavaScriptObject and add an expando named "canceled" to inidicate
-   * if the request was canceled. The callback wrapper checks the expando before
-   * executing the user callback.
-   * 
-   * @param callback the user callback to execute
-   * @param handle the handle object
-   */
-  private native void requestAnimationFrameImpl(AnimationCallback callback,
-      AnimationHandleImpl handle) /*-{
-    var wrapper = $entry(function() {
-      if (!handle.@com.google.gwt.animation.client.AnimationSchedulerImplMozilla.AnimationHandleImpl::canceled) {
-        // Older versions of firefox pass the current timestamp, but the spec has changed to pass a
-        // high resolution timer instead, and newer versions of Firefox will eventually change.
-        var now = @com.google.gwt.core.client.Duration::currentTimeMillis()();
-        callback.@com.google.gwt.animation.client.AnimationScheduler.AnimationCallback::execute(D)(now);
-      }
-    });
-    $wnd.mozRequestAnimationFrame(wrapper);
-  }-*/;
-}
diff --git a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplStandard.java b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplStandard.java
new file mode 100644
index 0000000..83dd063
--- /dev/null
+++ b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplStandard.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.animation.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.dom.client.Element;
+
+/**
+ * {@link AnimationScheduler} implementation that uses standard {@code requestAnimationFrame} API.
+ */
+class AnimationSchedulerImplStandard extends AnimationScheduler {
+
+  /**
+   * Check if the implementation is natively supported.
+   *
+   * @return {@code true} if natively supported, {@code false} if not
+   */
+  static native boolean isNativelySupported() /*-{
+    return !!$wnd.requestAnimationFrame && !!$wnd.cancelAnimationFrame;
+  }-*/;
+
+  @Override
+  public AnimationHandle requestAnimationFrame(AnimationCallback callback, Element element) {
+    final JavaScriptObject handle = requestImpl(callback, element);
+    return new AnimationHandle() {
+      @Override public void cancel() {
+        cancelImpl(handle);
+      }
+    };
+  }
+
+  private static native JavaScriptObject requestImpl(AnimationCallback cb, Element element) /*-{
+    var callback = $entry(function(time) {
+      cb.@com.google.gwt.animation.client.AnimationScheduler.AnimationCallback::execute(D)(time);
+    });
+
+    var handle = $wnd.requestAnimationFrame(callback, element);
+
+    // We can not treat handle as JSO in dev-mode if it is a number. Ensure that it is not:
+    return {id: handle};
+  }-*/;
+
+  private static native void cancelImpl(JavaScriptObject holder) /*-{
+    $wnd.cancelAnimationFrame(holder.id);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplTimer.java b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplTimer.java
index ef2ef05..26b1f74 100644
--- a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplTimer.java
+++ b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplTimer.java
@@ -26,7 +26,7 @@
  * Implementation using a timer for browsers that do not support animation
  * frames.
  */
-class AnimationSchedulerImplTimer extends AnimationSchedulerImpl {
+class AnimationSchedulerImplTimer extends AnimationScheduler {
 
   /**
    * Timer based implementation of {@link AnimationScheduler.AnimationHandle}.
@@ -89,11 +89,6 @@
     return requestId;
   }
 
-  @Override
-  protected boolean isNativelySupported() {
-    return true;
-  }
-
   private void cancelAnimationFrame(AnimationHandle requestId) {
     // Remove the request from the list.
     animationRequests.remove(requestId);
diff --git a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplWebkit.java b/user/src/com/google/gwt/animation/client/AnimationSchedulerImplWebkit.java
deleted file mode 100644
index ed02124..0000000
--- a/user/src/com/google/gwt/animation/client/AnimationSchedulerImplWebkit.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.animation.client;
-
-import com.google.gwt.dom.client.Element;
-
-/**
- * Implementation using <code>webkitRequestAnimationFrame</code> and
- * <code>webkitCancelRequestAnimationFrame</code>.
- * 
- * @see <a
- *      href="http://www.chromium.org/developers/web-platform-status#TOC-requestAnimationFrame">
- *      Chromium Web Platform Status</a>
- * @see <a href="http://webstuff.nfshost.com/anim-timing/Overview.html"> webkit
- *      draft spec</a>
- */
-class AnimationSchedulerImplWebkit extends AnimationSchedulerImpl {
-
-  /**
-   * Webkit implementation of {@link AnimationScheduler.AnimationHandle}. Webkit
-   * provides the request ID as a double.
-   */
-  private class AnimationHandleImpl extends AnimationHandle {
-    private final double requestId;
-
-    public AnimationHandleImpl(double requestId) {
-      this.requestId = requestId;
-    }
-
-    @Override
-    public void cancel() {
-      cancelAnimationFrameImpl(requestId);
-    }
-  }
-
-  @Override
-  public AnimationHandle requestAnimationFrame(AnimationCallback callback, Element element) {
-    double requestId = requestAnimationFrameImpl(callback, element);
-    return new AnimationHandleImpl(requestId);
-  }
-
-  @Override
-  protected native boolean isNativelySupported() /*-{
-    return !!($wnd.webkitRequestAnimationFrame && $wnd.webkitCancelRequestAnimationFrame);
-  }-*/;
-
-  private native void cancelAnimationFrameImpl(double requestId) /*-{
-    $wnd.webkitCancelRequestAnimationFrame(requestId);
-  }-*/;
-
-  private native double requestAnimationFrameImpl(AnimationCallback callback, Element element) /*-{
-    var _callback = callback;
-    var wrapper = $entry(function() {
-      // Older versions of Chrome pass the current timestamp, but newer versions pass a
-      // high resolution timer. We normalize on the current timestamp.
-      var now = @com.google.gwt.core.client.Duration::currentTimeMillis()();
-      _callback.@com.google.gwt.animation.client.AnimationScheduler.AnimationCallback::execute(D)(now);
-    });
-    return $wnd.webkitRequestAnimationFrame(wrapper, element);
-  }-*/;
-}
diff --git a/user/test/com/google/gwt/animation/AnimationApiUsage.gwt.xml b/user/test/com/google/gwt/animation/AnimationApiUsage.gwt.xml
deleted file mode 100644
index 3c0c4d5..0000000
--- a/user/test/com/google/gwt/animation/AnimationApiUsage.gwt.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--                                                                        -->
-<!-- Copyright 2013 Google Inc.                                             -->
-<!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
-<!-- may not use this file except in compliance with the License. You may   -->
-<!-- may obtain a copy of the License at                                    -->
-<!--                                                                        -->
-<!-- http://www.apache.org/licenses/LICENSE-2.0                             -->
-<!--                                                                        -->
-<!-- Unless required by applicable law or agreed to in writing, software    -->
-<!-- distributed under the License is distributed on an "AS IS" BASIS,      -->
-<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        -->
-<!-- implied. License for the specific language governing permissions and   -->
-<!-- limitations under the License.                                         -->
-
-<!-- Module used to test Animation API usage.                               -->
-<module type="fileset">
-  <inherits name="com.google.gwt.animation.Animation"/>
-  <set-property name="webApiUsage" value="stable"/>
-</module>
diff --git a/user/test/com/google/gwt/animation/AnimationSuite.java b/user/test/com/google/gwt/animation/AnimationSuite.java
index 8302101..ef8551f 100644
--- a/user/test/com/google/gwt/animation/AnimationSuite.java
+++ b/user/test/com/google/gwt/animation/AnimationSuite.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.animation;
 
-import com.google.gwt.animation.client.AnimationApiUsageTest;
 import com.google.gwt.animation.client.AnimationSchedulerImplTimerTest;
 import com.google.gwt.animation.client.AnimationTest;
 
@@ -29,7 +28,6 @@
   public static Test suite() {
     TestSuite suite = new TestSuite("Tests of the animation package");
 
-    suite.addTestSuite(AnimationApiUsageTest.class);
     suite.addTestSuite(AnimationSchedulerImplTimerTest.class);
     suite.addTestSuite(AnimationTest.class);
 
diff --git a/user/test/com/google/gwt/animation/client/AnimationApiUsageTest.java b/user/test/com/google/gwt/animation/client/AnimationApiUsageTest.java
deleted file mode 100644
index 27a6c64..0000000
--- a/user/test/com/google/gwt/animation/client/AnimationApiUsageTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.animation.client;
-
-import com.google.gwt.junit.client.GWTTestCase;
-
-/**
- * Verifies that we always use timers in 'resistance' mode.
- */
-public class AnimationApiUsageTest extends GWTTestCase {
-  @Override
-  public String getModuleName() {
-    return "com.google.gwt.animation.AnimationApiUsage";
-  }
-
-  public void testAnimationSchedulerUsesTimer() {
-    AnimationScheduler scheduler = AnimationScheduler.get();
-    assertEquals("Expected timer implementation but got: " + scheduler.getClass().getName(),
-        AnimationSchedulerImplTimer.class, scheduler.getClass());
-  }
-}