Updated logic of animation code by defining default implementations of onStart, onComplete, and onCancel. Modified existing widget animations to take advantage of the new code.
Patch by: jlabanca, scottb
Review by: jat, kelly
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2900 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
index 73d6619..9122ee9 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/other/CwAnimation.java
@@ -68,26 +68,21 @@
private int radius = 100;
@Override
- public void onCancel() {
- onComplete();
- }
-
- @Override
- public void onComplete() {
- onUpdate(1.0);
+ protected void onComplete() {
+ super.onComplete();
startButton.setEnabled(true);
cancelButton.setEnabled(false);
}
@Override
- public void onStart() {
- onUpdate(1.0);
+ protected void onStart() {
+ super.onStart();
startButton.setEnabled(false);
cancelButton.setEnabled(true);
}
@Override
- public void onUpdate(double progress) {
+ protected void onUpdate(double progress) {
double radian = 2 * Math.PI * progress;
updatePosition(animateeLeft, radian, 0);
updatePosition(animateeBottom, radian, 0.5 * Math.PI);
diff --git a/user/src/com/google/gwt/animation/client/Animation.java b/user/src/com/google/gwt/animation/client/Animation.java
index 9e55db7..b90fa72 100644
--- a/user/src/com/google/gwt/animation/client/Animation.java
+++ b/user/src/com/google/gwt/animation/client/Animation.java
@@ -32,7 +32,7 @@
private static final int DEFAULT_FRAME_DELAY = 25;
/**
- * The {@link Animation}s that are currently in progress.
+ * The {@link Animation Animations} that are currently in progress.
*/
private static List<Animation> animations = null;
@@ -42,7 +42,7 @@
private static Timer animationTimer = null;
/**
- * Update all {@link Animation}s.
+ * Update all {@link Animation Animations}.
*/
private static void updateAnimations() {
// Iterator through the animations
@@ -77,19 +77,20 @@
private double startTime = -1;
/**
- * Immediately cancel this animation.
+ * Immediately cancel this animation. If the animation is running or is
+ * scheduled to run, {@link #onCancel()} will be called.
*/
public void cancel() {
- // No animations available
+ // Ignore if no animations are running
if (animations == null) {
return;
}
- // Remove the animation
- started = false;
+ // Remove this animation from the list
if (animations.remove(this)) {
onCancel();
}
+ started = false;
}
/**
@@ -155,27 +156,38 @@
}
/**
- * Called immediately after the animation is canceled.
+ * Called immediately after the animation is canceled. The default
+ * implementation of this method calls {@link #onComplete()} only if the
+ * animation has actually started running.
*/
- protected abstract void onCancel();
+ protected void onCancel() {
+ if (started) {
+ started = false;
+ onComplete();
+ }
+ }
/**
* Called immediately after the animation completes.
*/
- protected abstract void onComplete();
+ protected void onComplete() {
+ onUpdate(interpolate(1.0));
+ }
/**
* Called immediately before the animation starts.
*/
- protected abstract void onStart();
+ protected void onStart() {
+ onUpdate(interpolate(0.0));
+ }
/**
* Called when the animation should be updated.
*
- * The value of progress is between 0.0 and 1.0 inclusively, but it is not
- * safe to assume that either 0.0 or 1.0 will be passed in. Use
- * {@link #onStart()} and {@link #onComplete()} to do setup and tear down
- * procedures.
+ * The value of progress is between 0.0 and 1.0 inclusively (unless you
+ * override the {@link #interpolate(double)} method to provide a wider range
+ * of values). You can override {@link #onStart()} and {@link #onComplete()}
+ * to perform setup and tear down procedures.
*/
protected abstract void onUpdate(double progress);
@@ -186,21 +198,24 @@
* @return true if the animation is complete, false if still running
*/
private boolean update(double curTime) {
- // Start the animation
+ boolean finished = curTime >= startTime + duration;
+ if (started && !finished) {
+ // Animation is in progress.
+ double progress = (curTime - startTime) / duration;
+ onUpdate(interpolate(progress));
+ return false;
+ }
if (!started && curTime >= startTime) {
+ // Start the animation.
started = true;
onStart();
+ // Intentional fall through to possibly end the animation.
}
-
- if (curTime >= startTime + duration) {
- // Animation is complete
+ if (finished) {
+ // Animation is complete.
started = false;
onComplete();
return true;
- } else if (curTime >= startTime) {
- // Animation is in progress
- double progress = (curTime - startTime) / duration;
- onUpdate(interpolate(progress));
}
return false;
}
diff --git a/user/src/com/google/gwt/user/client/ui/DeckPanel.java b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
index 8861888..4ee7274 100644
--- a/user/src/com/google/gwt/user/client/ui/DeckPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
@@ -33,6 +33,11 @@
*/
public class DeckPanel extends ComplexPanel implements HasAnimation {
/**
+ * The duration of the animation.
+ */
+ private static final int ANIMATION_DURATION = 350;
+
+ /**
* An {@link Animation} used to slide in the new content.
*/
private static class SlideAnimation extends Animation {
@@ -57,94 +62,6 @@
*/
private int fixedHeight = -1;
- @Override
- public void onCancel() {
- onComplete();
- }
-
- @Override
- public void onComplete() {
- if (growing) {
- onUpdate(1.0);
- DOM.setStyleAttribute(container1, "height", "100%");
- UIObject.setVisible(container1, true);
- UIObject.setVisible(container2, false);
- DOM.setStyleAttribute(container2, "height", "100%");
- } else {
- UIObject.setVisible(container1, false);
- DOM.setStyleAttribute(container1, "height", "100%");
- DOM.setStyleAttribute(container2, "height", "100%");
- UIObject.setVisible(container2, true);
- }
- DOM.setStyleAttribute(container1, "overflow", "visible");
- DOM.setStyleAttribute(container2, "overflow", "visible");
- container1 = null;
- container2 = null;
- }
-
- public void onInstantaneousRun() {
- UIObject.setVisible(container1, growing);
- UIObject.setVisible(container2, !growing);
- container1 = null;
- container2 = null;
- }
-
- @Override
- public void onStart() {
- // Figure out if the deck panel has a fixed height
- com.google.gwt.dom.client.Element deckElem = container1.getParentElement();
- int deckHeight = deckElem.getOffsetHeight();
- if (growing) {
- fixedHeight = container2.getOffsetHeight();
- container2.getStyle().setPropertyPx("height", fixedHeight - 1);
- } else {
- fixedHeight = container1.getOffsetHeight();
- container1.getStyle().setPropertyPx("height", fixedHeight - 1);
- }
- if (deckElem.getOffsetHeight() != deckHeight) {
- fixedHeight = -1;
- }
-
- // Start the animation
- DOM.setStyleAttribute(container1, "overflow", "hidden");
- DOM.setStyleAttribute(container2, "overflow", "hidden");
- onUpdate(0.0);
- UIObject.setVisible(container1, true);
- UIObject.setVisible(container2, true);
- }
-
- @Override
- public void onUpdate(double progress) {
- if (!growing) {
- progress = 1.0 - progress;
- }
-
- // Container1 expands (shrinks) to its target height
- int height1;
- int height2;
- if (fixedHeight == -1) {
- height1 = (int) (progress * DOM.getElementPropertyInt(container1,
- "scrollHeight"));
- height2 = (int) ((1.0 - progress) * DOM.getElementPropertyInt(
- container2, "scrollHeight"));
- } else {
- height1 = (int) (progress * fixedHeight);
- height2 = fixedHeight - height1;
- }
-
- // Issue 2339: If the height is 0px, IE7 will display the entire content
- // widget instead of hiding it completely.
- if (height1 == 0) {
- height1 = 1;
- height2 = Math.max(1, height2 - 1);
- } else if (height2 == 0) {
- height2 = 1;
- height1 = Math.max(1, height1 - 1);
- }
- DOM.setStyleAttribute(container1, "height", height1 + "px");
- DOM.setStyleAttribute(container2, "height", height2 + "px");
- }
-
/**
* Switch to a new {@link Widget}.
*
@@ -185,11 +102,93 @@
// Start the animation
if (animate) {
- run(350);
+ run(ANIMATION_DURATION);
} else {
onInstantaneousRun();
}
}
+
+ @Override
+ protected void onComplete() {
+ if (growing) {
+ DOM.setStyleAttribute(container1, "height", "100%");
+ UIObject.setVisible(container1, true);
+ UIObject.setVisible(container2, false);
+ DOM.setStyleAttribute(container2, "height", "100%");
+ } else {
+ UIObject.setVisible(container1, false);
+ DOM.setStyleAttribute(container1, "height", "100%");
+ DOM.setStyleAttribute(container2, "height", "100%");
+ UIObject.setVisible(container2, true);
+ }
+ DOM.setStyleAttribute(container1, "overflow", "visible");
+ DOM.setStyleAttribute(container2, "overflow", "visible");
+ container1 = null;
+ container2 = null;
+ }
+
+ @Override
+ protected void onStart() {
+ // Figure out if the deck panel has a fixed height
+ com.google.gwt.dom.client.Element deckElem = container1.getParentElement();
+ int deckHeight = deckElem.getOffsetHeight();
+ if (growing) {
+ fixedHeight = container2.getOffsetHeight();
+ container2.getStyle().setPropertyPx("height", fixedHeight - 1);
+ } else {
+ fixedHeight = container1.getOffsetHeight();
+ container1.getStyle().setPropertyPx("height", fixedHeight - 1);
+ }
+ if (deckElem.getOffsetHeight() != deckHeight) {
+ fixedHeight = -1;
+ }
+
+ // Start the animation
+ DOM.setStyleAttribute(container1, "overflow", "hidden");
+ DOM.setStyleAttribute(container2, "overflow", "hidden");
+ onUpdate(0.0);
+ UIObject.setVisible(container1, true);
+ UIObject.setVisible(container2, true);
+ }
+
+ @Override
+ protected void onUpdate(double progress) {
+ if (!growing) {
+ progress = 1.0 - progress;
+ }
+
+ // Container1 expands (shrinks) to its target height
+ int height1;
+ int height2;
+ if (fixedHeight == -1) {
+ height1 = (int) (progress * DOM.getElementPropertyInt(container1,
+ "scrollHeight"));
+ height2 = (int) ((1.0 - progress) * DOM.getElementPropertyInt(
+ container2, "scrollHeight"));
+ } else {
+ height1 = (int) (progress * fixedHeight);
+ height2 = fixedHeight - height1;
+ }
+
+ // Issue 2339: If the height is 0px, IE7 will display the entire content
+ // widget instead of hiding it completely.
+ if (height1 == 0) {
+ height1 = 1;
+ height2 = Math.max(1, height2 - 1);
+ } else if (height2 == 0) {
+ height2 = 1;
+ height1 = Math.max(1, height1 - 1);
+ }
+ DOM.setStyleAttribute(container1, "height", height1 + "px");
+ DOM.setStyleAttribute(container2, "height", height2 + "px");
+ }
+
+ private void onInstantaneousRun() {
+ UIObject.setVisible(container1, growing);
+ UIObject.setVisible(container2, !growing);
+ container1 = null;
+ container2 = null;
+ }
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
index 89ff7e6..6e7b243 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
@@ -50,6 +50,11 @@
public final class DisclosurePanel extends Composite implements
FiresDisclosureEvents, HasWidgets, HasAnimation {
/**
+ * The duration of the animation.
+ */
+ private static final int ANIMATION_DURATION = 350;
+
+ /**
* An {@link Animation} used to open the content.
*/
private static class ContentAnimation extends Animation {
@@ -63,44 +68,6 @@
*/
private DisclosurePanel curPanel;
- @Override
- public void onCancel() {
- onComplete();
- }
-
- @Override
- public void onComplete() {
- if (!opening) {
- curPanel.contentWrapper.setVisible(false);
- }
- DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height",
- "auto");
- curPanel = null;
- }
-
- @Override
- public void onStart() {
- onUpdate(0.0);
- if (opening) {
- curPanel.contentWrapper.setVisible(true);
- }
- }
-
- @Override
- public void onUpdate(double progress) {
- int scrollHeight = DOM.getElementPropertyInt(
- curPanel.contentWrapper.getElement(), "scrollHeight");
- int height = (int) (progress * scrollHeight);
- if (!opening) {
- height = scrollHeight - height;
- }
- height = Math.max(height, 1);
- DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height",
- height + "px");
- DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "width",
- "auto");
- }
-
/**
* Open or close the content.
*
@@ -115,11 +82,44 @@
if (animate) {
curPanel = panel;
opening = panel.isOpen;
- run(350);
+ run(ANIMATION_DURATION);
} else {
panel.contentWrapper.setVisible(panel.isOpen);
}
}
+
+ @Override
+ protected void onComplete() {
+ if (!opening) {
+ curPanel.contentWrapper.setVisible(false);
+ }
+ DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height",
+ "auto");
+ curPanel = null;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (opening) {
+ curPanel.contentWrapper.setVisible(true);
+ }
+ }
+
+ @Override
+ protected void onUpdate(double progress) {
+ int scrollHeight = DOM.getElementPropertyInt(
+ curPanel.contentWrapper.getElement(), "scrollHeight");
+ int height = (int) (progress * scrollHeight);
+ if (!opening) {
+ height = scrollHeight - height;
+ }
+ height = Math.max(height, 1);
+ DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height",
+ height + "px");
+ DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "width",
+ "auto");
+ }
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index eefc1b1..30be11d 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -49,6 +49,11 @@
public class PopupPanel extends SimplePanel implements SourcesPopupEvents,
EventPreview, HasAnimation {
/**
+ * The duration of the animation.
+ */
+ private static final int ANIMATION_DURATION = 200;
+
+ /**
* The type of animation to use when opening the popup.
*
* <ul>
@@ -57,7 +62,7 @@
* hiding</li>
* </ul>
*/
- public static enum AnimationType {
+ static enum AnimationType {
CENTER, ONE_WAY_CORNER
}
@@ -80,13 +85,35 @@
*/
private boolean showing = false;
- @Override
- public void onCancel() {
- onComplete();
+ /**
+ * Open or close the content. This method always called immediately after
+ * the PopupPanel showing state has changed, so we base the animation on the
+ * current state.
+ *
+ * @param panel the panel to open or close
+ */
+ public void setOpen(final PopupPanel panel) {
+ // Immediately complete previous open/close animation
+ cancel();
+
+ // Determine if we need to animate
+ boolean animate = panel.isAnimationEnabled;
+ if (panel.animType == AnimationType.ONE_WAY_CORNER && !panel.showing) {
+ animate = false;
+ }
+
+ // Open the new item
+ showing = panel.showing;
+ curPanel = panel;
+ if (animate) {
+ run(ANIMATION_DURATION);
+ } else {
+ onInstantaneousRun();
+ }
}
@Override
- public void onComplete() {
+ protected void onComplete() {
if (!showing) {
RootPanel.get().remove(curPanel);
impl.onHide(curPanel.getElement());
@@ -96,27 +123,8 @@
curPanel = null;
}
- public void onInstantaneousRun() {
- if (showing) {
- // Set the position attribute, and then attach to the DOM. Otherwise,
- // the PopupPanel will appear to 'jump' from its static/relative
- // position to its absolute position (issue #1231).
- DOM.setStyleAttribute(curPanel.getElement(), "position", "absolute");
- if (curPanel.topPosition != -1) {
- curPanel.setPopupPosition(curPanel.leftPosition, curPanel.topPosition);
- }
- RootPanel.get().add(curPanel);
- impl.onShow(curPanel.getElement());
- } else {
- RootPanel.get().remove(curPanel);
- impl.onHide(curPanel.getElement());
- }
- DOM.setStyleAttribute(curPanel.getElement(), "overflow", "visible");
- curPanel = null;
- }
-
@Override
- public void onStart() {
+ protected void onStart() {
// Attach to the page
if (showing) {
// Set the position attribute, and then attach to the DOM. Otherwise,
@@ -133,11 +141,11 @@
offsetHeight = curPanel.getOffsetHeight();
offsetWidth = curPanel.getOffsetWidth();
DOM.setStyleAttribute(curPanel.getElement(), "overflow", "hidden");
- onUpdate(0.0);
+ super.onStart();
}
@Override
- public void onUpdate(double progress) {
+ protected void onUpdate(double progress) {
if (!showing) {
progress = 1.0 - progress;
}
@@ -166,39 +174,31 @@
}
/**
- * Open or close the content. This method always called immediately after
- * the PopupPanel showing state has changed, so we base the animation on the
- * current state.
- *
- * @param panel the panel to open or close
- */
- public void setOpen(final PopupPanel panel) {
- // Immediately complete previous open/close animation
- cancel();
-
- // Determine if we need to animate
- boolean animate = panel.isAnimationEnabled;
- if (panel.animType == AnimationType.ONE_WAY_CORNER && !panel.showing) {
- animate = false;
- }
-
- // Open the new item
- showing = panel.showing;
- curPanel = panel;
- if (animate) {
- run(200);
- } else {
- onInstantaneousRun();
- }
- }
-
- /**
* @return a rect string
*/
private String getRectString(int top, int right, int bottom, int left) {
return "rect(" + top + "px, " + right + "px, " + bottom + "px, " + left
+ "px)";
}
+
+ private void onInstantaneousRun() {
+ if (showing) {
+ // Set the position attribute, and then attach to the DOM. Otherwise,
+ // the PopupPanel will appear to 'jump' from its static/relative
+ // position to its absolute position (issue #1231).
+ DOM.setStyleAttribute(curPanel.getElement(), "position", "absolute");
+ if (curPanel.topPosition != -1) {
+ curPanel.setPopupPosition(curPanel.leftPosition, curPanel.topPosition);
+ }
+ RootPanel.get().add(curPanel);
+ impl.onShow(curPanel.getElement());
+ } else {
+ RootPanel.get().remove(curPanel);
+ impl.onHide(curPanel.getElement());
+ }
+ DOM.setStyleAttribute(curPanel.getElement(), "overflow", "visible");
+ curPanel = null;
+ }
}
/**
@@ -658,15 +658,6 @@
}
/**
- * Enable or disable animation of the {@link PopupPanel}.
- *
- * @param type the type of animation to use
- */
- protected void setAnimationType(AnimationType type) {
- animType = type;
- }
-
- /**
* We control size by setting our child widget's size. However, if we don't
* currently have a child, we record the size the user wanted so that when we
* do get a child, we can set it correctly. Until size is explicitly cleared,
@@ -693,6 +684,15 @@
}
/**
+ * Enable or disable animation of the {@link PopupPanel}.
+ *
+ * @param type the type of animation to use
+ */
+ void setAnimationType(AnimationType type) {
+ animType = type;
+ }
+
+ /**
* Remove focus from an Element.
*
* @param elt The Element on which <code>blur()</code> will be invoked
diff --git a/user/src/com/google/gwt/user/client/ui/TreeItem.java b/user/src/com/google/gwt/user/client/ui/TreeItem.java
index 9c033dc..511a67d7 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeItem.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeItem.java
@@ -36,7 +36,6 @@
* </p>
*/
public class TreeItem extends UIObject implements HasHTML {
-
/**
* An {@link Animation} used to open the child elements. If a {@link TreeItem}
* is in the process of opening, it will immediately be opened and the new
@@ -54,13 +53,29 @@
*/
private boolean opening = true;
- @Override
- public void onCancel() {
- onComplete();
+ /**
+ * Open the specified {@link TreeItem}.
+ *
+ * @param item the {@link TreeItem} to open
+ * @param animate true to animate, false to open instantly
+ */
+ public void setItemState(TreeItem item, boolean animate) {
+ // Immediately complete previous open
+ cancel();
+
+ // Open the new item
+ if (animate) {
+ curItem = item;
+ opening = item.open;
+ run(Math.min(ANIMATION_DURATION, ANIMATION_DURATION_PER_ITEM
+ * curItem.getChildCount()));
+ } else {
+ UIObject.setVisible(item.childSpanElem, item.open);
+ }
}
@Override
- public void onComplete() {
+ protected void onComplete() {
if (curItem != null) {
if (opening) {
UIObject.setVisible(curItem.childSpanElem, true);
@@ -76,16 +91,16 @@
}
@Override
- public void onStart() {
+ protected void onStart() {
DOM.setStyleAttribute(curItem.childSpanElem, "overflow", "hidden");
- onUpdate(0.0);
+ super.onStart();
if (opening) {
UIObject.setVisible(curItem.childSpanElem, true);
}
}
@Override
- public void onUpdate(double progress) {
+ protected void onUpdate(double progress) {
int scrollHeight = DOM.getElementPropertyInt(curItem.childSpanElem,
"scrollHeight");
@@ -105,26 +120,6 @@
"scrollWidth");
DOM.setStyleAttribute(curItem.childSpanElem, "width", scrollWidth + "px");
}
-
- /**
- * Open the specified {@link TreeItem}.
- *
- * @param item the {@link TreeItem} to open
- * @param animate true to animate, false to open instantly
- */
- public void setItemState(TreeItem item, boolean animate) {
- // Immediately complete previous open
- cancel();
-
- // Open the new item
- if (animate) {
- curItem = item;
- opening = item.open;
- run(Math.min(200, 75 * curItem.getChildCount()));
- } else {
- UIObject.setVisible(item.childSpanElem, item.open);
- }
- }
}
// By not overwriting the default tree padding and spacing, we traditionally
@@ -135,7 +130,19 @@
static final int IMAGE_PAD = 7;
/**
- * The static animation used to open {@link TreeItem}s.
+ * The duration of the animation.
+ */
+ private static final int ANIMATION_DURATION = 200;
+
+ /**
+ * The duration of the animation per child {@link TreeItem}. If the per item
+ * duration times the number of child items is less than the duration above,
+ * the smaller duration will be used.
+ */
+ private static final int ANIMATION_DURATION_PER_ITEM = 75;
+
+ /**
+ * The static animation used to open {@link TreeItem TreeItems}.
*/
private static TreeItemAnimation itemAnimation = new TreeItemAnimation();
diff --git a/user/test/com/google/gwt/animation/client/AnimationTest.java b/user/test/com/google/gwt/animation/client/AnimationTest.java
index 874fb29..1ed09cf 100644
--- a/user/test/com/google/gwt/animation/client/AnimationTest.java
+++ b/user/test/com/google/gwt/animation/client/AnimationTest.java
@@ -24,32 +24,53 @@
*/
public class AnimationTest extends GWTTestCase {
/**
- * A customer {@link Animation} used for testing.
+ * Increase this multiplier to increase the duration of the tests, reducing
+ * the potential of an error caused by timing issues.
*/
- private static class TestAnimation extends Animation {
- public boolean cancelled = false;
- public boolean completed = false;
- public double curProgress = -1.0;
- public boolean started = false;
+ private static int DELAY_MULTIPLIER = 100;
- @Override
- public void onCancel() {
- cancelled = true;
+ /**
+ * A default implementation of {@link Animation} used for testing.
+ */
+ private static class DefaultAnimation extends Animation {
+ protected boolean cancelled = false;
+ protected boolean completed = false;
+ protected boolean started = false;
+ protected double curProgress = -1.0;
+
+ /**
+ * Assert the value of canceled.
+ */
+ public void assertCancelled(boolean expected) {
+ assertEquals(expected, cancelled);
}
- @Override
- public void onComplete() {
- completed = true;
+ /**
+ * Assert the value of completed.
+ */
+ public void assertCompleted(boolean expected) {
+ assertEquals(expected, completed);
}
- @Override
- public void onStart() {
- started = true;
+ /**
+ * Assert that the progress equals the specified value.
+ */
+ public void assertProgress(double expected) {
+ assertEquals(expected, curProgress);
}
- @Override
- public void onUpdate(double progress) {
- curProgress = progress;
+ /**
+ * Assert that the progress falls between min and max, inclusively.
+ */
+ public void assertProgressRange(double min, double max) {
+ assertTrue(curProgress >= min && curProgress <= max);
+ }
+
+ /**
+ * Assert the value of started.
+ */
+ public void assertStarted(boolean expected) {
+ assertEquals(expected, started);
}
public void reset() {
@@ -58,6 +79,55 @@
started = false;
curProgress = -1.0;
}
+
+ @Override
+ protected void onUpdate(double progress) {
+ curProgress = progress;
+ }
+
+ @Override
+ protected void onCancel() {
+ super.onCancel();
+ cancelled = true;
+ }
+
+ @Override
+ protected void onComplete() {
+ super.onComplete();
+ completed = true;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ started = true;
+ }
+ }
+
+ /**
+ * A custom {@link Animation} used for testing.
+ */
+ private static class TestAnimation extends DefaultAnimation {
+ /*
+ * TODO: Consider timing issues for test system. Specifically, onUpdate is
+ * not guaranteed to be called in the Animation timer if we miss our
+ * deadline.
+ */
+
+ @Override
+ protected void onCancel() {
+ cancelled = true;
+ }
+
+ @Override
+ protected void onComplete() {
+ completed = true;
+ }
+
+ @Override
+ protected void onStart() {
+ started = true;
+ }
}
@Override
@@ -71,36 +141,36 @@
public void testCancelBeforeStarted() {
final TestAnimation anim = new TestAnimation();
double curTime = Duration.currentTimeMillis();
- anim.run(100, curTime + 200);
+ anim.run(10 * DELAY_MULTIPLIER, curTime + 10 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertFalse(anim.started);
- assertFalse(anim.completed);
- assertEquals(-1.0, anim.curProgress);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertProgress(-1.0);
anim.cancel();
- assertTrue(anim.cancelled);
- assertFalse(anim.started);
- assertFalse(anim.completed);
+ anim.assertStarted(false);
+ anim.assertCancelled(true);
+ anim.assertCompleted(false);
anim.reset();
}
- }.schedule(50);
+ }.schedule(5 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertFalse(anim.started);
- assertFalse(anim.completed);
- assertEquals(-1.0, anim.curProgress);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertProgress(-1.0);
finishTest();
}
- }.schedule(100);
+ }.schedule(15 * DELAY_MULTIPLIER);
// Wait for test to finish
- delayTestFinish(150);
+ delayTestFinish(20 * DELAY_MULTIPLIER);
}
/**
@@ -108,35 +178,35 @@
*/
public void testCancelWhenComplete() {
final TestAnimation anim = new TestAnimation();
- anim.run(100);
+ anim.run(10 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertTrue(anim.started);
- assertTrue(anim.completed);
- assertTrue(anim.curProgress > 0.0 && anim.curProgress <= 1.0);
+ anim.assertStarted(true);
+ anim.assertCompleted(true);
+ anim.assertProgressRange(0.0, 1.0);
anim.cancel();
- assertFalse(anim.cancelled);
- assertTrue(anim.completed);
+ anim.assertCancelled(false);
+ anim.assertCompleted(true);
anim.reset();
}
- }.schedule(150);
+ }.schedule(15 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertFalse(anim.started);
- assertFalse(anim.completed);
- assertEquals(-1.0, anim.curProgress);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertProgress(-1.0);
finishTest();
}
- }.schedule(200);
+ }.schedule(20 * DELAY_MULTIPLIER);
// Wait for test to finish
- delayTestFinish(250);
+ delayTestFinish(25 * DELAY_MULTIPLIER);
}
/**
@@ -144,35 +214,34 @@
*/
public void testCancelWhileRunning() {
final TestAnimation anim = new TestAnimation();
- anim.run(500);
+ anim.run(50 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertTrue(anim.started);
- assertFalse(anim.completed);
- assertTrue(anim.curProgress > 0.0 && anim.curProgress <= 1.0);
+ anim.assertStarted(true);
+ anim.assertCompleted(false);
anim.cancel();
- assertTrue(anim.cancelled);
- assertFalse(anim.completed);
+ anim.assertCancelled(true);
+ anim.assertCompleted(false);
anim.reset();
}
- }.schedule(50);
+ }.schedule(5 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertFalse(anim.started);
- assertFalse(anim.completed);
- assertEquals(-1.0, anim.curProgress);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertProgress(-1.0);
finishTest();
}
- }.schedule(150);
+ }.schedule(15 * DELAY_MULTIPLIER);
// Wait for test to finish
- delayTestFinish(200);
+ delayTestFinish(20 * DELAY_MULTIPLIER);
}
/**
@@ -186,21 +255,69 @@
// Run animations
double curTime = Duration.currentTimeMillis();
animNow.run(0);
- animPast.run(0, curTime - 150);
- animFuture.run(0, curTime + 150);
+ animPast.run(0, curTime - 15 * DELAY_MULTIPLIER);
+ animFuture.run(0, curTime + 15 * DELAY_MULTIPLIER);
// Test synchronous start
- assertTrue(animNow.started);
- assertTrue(animNow.completed);
- assertEquals(-1.0, animNow.curProgress);
+ animNow.assertStarted(true);
+ animNow.assertCompleted(true);
+ animNow.assertProgress(-1.0);
- assertTrue(animPast.started);
- assertTrue(animPast.completed);
- assertEquals(-1.0, animFuture.curProgress);
+ animPast.assertStarted(true);
+ animPast.assertCompleted(true);
+ animPast.assertProgress(-1.0);
- assertFalse(animFuture.started);
- assertFalse(animFuture.completed);
- assertEquals(-1.0, animFuture.curProgress);
+ animFuture.assertStarted(false);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgress(-1.0);
+ }
+
+ /**
+ * Test the default implementations of events in {@link Animation}.
+ */
+ public void testDefaultAnimation() {
+ // Verify initial state
+ final DefaultAnimation anim = new DefaultAnimation();
+ anim.assertProgress(-1.0);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertCancelled(false);
+
+ // Starting an animation calls onUpdate(interpolate(0.0))
+ anim.reset();
+ anim.onStart();
+ anim.assertProgress(0.0);
+ anim.assertStarted(true);
+ anim.assertCompleted(false);
+ anim.assertCancelled(false);
+
+ // Completing an animation calls onUpdate(interpolate(1.0))
+ anim.reset();
+ anim.onComplete();
+ anim.assertProgress(1.0);
+ anim.assertStarted(false);
+ anim.assertCompleted(true);
+ anim.assertCancelled(false);
+
+ // Canceling an animation that is not running does not call onStart or
+ // onComplete
+ anim.reset();
+ anim.onCancel();
+ anim.assertProgress(-1.0);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertCancelled(true);
+
+ // Canceling an animation before it starts does not call onStart or
+ // onComplete
+ anim.reset();
+ anim.run(20 * DELAY_MULTIPLIER, Duration.currentTimeMillis() + 100
+ * DELAY_MULTIPLIER);
+ anim.cancel();
+ anim.assertProgress(-1.0);
+ anim.assertStarted(false);
+ anim.assertCompleted(false);
+ anim.assertCancelled(true);
}
/**
@@ -213,62 +330,118 @@
// Run animations
double curTime = Duration.currentTimeMillis();
- animNow.run(300);
- animPast.run(300, curTime - 150);
- animFuture.run(300, curTime + 150);
+ animNow.run(30 * DELAY_MULTIPLIER);
+ animPast.run(30 * DELAY_MULTIPLIER, curTime - 10 * DELAY_MULTIPLIER);
+ animFuture.run(30 * DELAY_MULTIPLIER, curTime + 10 * DELAY_MULTIPLIER);
// Test synchronous start
- assertTrue(animNow.started);
- assertFalse(animNow.completed);
- assertTrue(animNow.curProgress >= 0.0 && animNow.curProgress <= 2.0);
+ animNow.assertStarted(true);
+ animNow.assertCompleted(false);
+ animNow.assertProgress(-1.0);
- assertTrue(animPast.started);
- assertFalse(animPast.completed);
- assertTrue(animPast.curProgress > 0.0 && animPast.curProgress <= 1.0);
+ animPast.assertStarted(true);
+ animPast.assertCompleted(false);
+ animPast.assertProgress(-1.0);
- assertFalse(animFuture.started);
- assertFalse(animFuture.completed);
- assertEquals(-1.0, animFuture.curProgress);
+ animFuture.assertStarted(false);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgress(-1.0);
// Check progress
new Timer() {
@Override
public void run() {
- assertTrue(animNow.started);
- assertFalse(animNow.completed);
- assertTrue(animNow.curProgress > 0.0 && animNow.curProgress <= 2.0);
+ animNow.assertStarted(true);
+ animNow.assertCompleted(false);
+ animNow.assertProgressRange(0.0, 1.0);
- assertTrue(animPast.started);
- assertFalse(animPast.completed);
- assertTrue(animPast.curProgress > 0.0 && animPast.curProgress <= 1.0);
+ animPast.assertStarted(true);
+ animPast.assertCompleted(false);
+ animPast.assertProgressRange(0.0, 1.0);
- assertFalse(animFuture.started);
- assertFalse(animFuture.completed);
- assertEquals(-1.0, animFuture.curProgress);
+ animFuture.assertStarted(false);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgress(-1.0);
}
- }.schedule(50);
+ }.schedule(5 * DELAY_MULTIPLIER);
// Check progress
new Timer() {
@Override
public void run() {
- assertTrue(animNow.started);
- assertTrue(animNow.completed);
- assertTrue(animNow.curProgress > 0.0 && animNow.curProgress <= 1.0);
+ animNow.assertStarted(true);
+ animNow.assertCompleted(false);
+ animNow.assertProgressRange(0.0, 1.0);
- assertTrue(animPast.started);
- assertTrue(animPast.completed);
- assertTrue(animPast.curProgress > 0.0 && animPast.curProgress <= 1.0);
+ animPast.assertStarted(true);
+ animPast.assertCompleted(false);
+ animPast.assertProgressRange(0.0, 1.0);
- assertTrue(animFuture.started);
- assertFalse(animFuture.completed);
- assertTrue(animFuture.curProgress > 0.0
- && animFuture.curProgress <= 1.0);
+ animFuture.assertStarted(true);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgressRange(0.0, 1.0);
+ }
+ }.schedule(15 * DELAY_MULTIPLIER);
+
+ // Check progress
+ new Timer() {
+ @Override
+ public void run() {
+ animNow.assertStarted(true);
+ animNow.assertCompleted(false);
+ animNow.assertProgressRange(0.0, 1.0);
+
+ animPast.assertStarted(true);
+ animPast.assertCompleted(true);
+ animPast.assertProgressRange(0.0, 1.0);
+
+ animFuture.assertStarted(true);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgressRange(0.0, 1.0);
+ }
+ }.schedule(25 * DELAY_MULTIPLIER);
+
+ // Check progress
+ new Timer() {
+ @Override
+ public void run() {
+ animNow.assertStarted(true);
+ animNow.assertCompleted(true);
+ animNow.assertProgressRange(0.0, 1.0);
+
+ animPast.assertStarted(true);
+ animPast.assertCompleted(true);
+ animPast.assertProgressRange(0.0, 1.0);
+
+ animFuture.assertStarted(true);
+ animFuture.assertCompleted(false);
+ animFuture.assertProgressRange(0.0, 1.0);
+
finishTest();
}
- }.schedule(350);
+ }.schedule(35 * DELAY_MULTIPLIER);
+
+ // Check progress
+ new Timer() {
+ @Override
+ public void run() {
+ animNow.assertStarted(true);
+ animNow.assertCompleted(true);
+ animNow.assertProgressRange(0.0, 1.0);
+
+ animPast.assertStarted(true);
+ animPast.assertCompleted(true);
+ animPast.assertProgressRange(0.0, 1.0);
+
+ animFuture.assertStarted(true);
+ animFuture.assertCompleted(true);
+ animFuture.assertProgressRange(0.0, 1.0);
+
+ finishTest();
+ }
+ }.schedule(45 * DELAY_MULTIPLIER);
// Wait for the test to finish
- delayTestFinish(500);
+ delayTestFinish(50 * DELAY_MULTIPLIER);
}
}