diff options
author | Arnaud Berry <arnaudberry@google.com> | 2011-02-08 11:19:10 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-02-08 11:19:10 -0800 |
commit | f88df948fc7821e33b3165bb969b2b9cb38a8b49 (patch) | |
tree | ce487df3b942abbfeb67660d1c4b7edc529e33b0 /carousel | |
parent | b2bc02c2fcd71d6d971e772a3d9dba0d1b065223 (diff) | |
parent | 8debeb8a0a785f0ad66bc75200cdb47c137602bc (diff) | |
download | android_frameworks_ex-f88df948fc7821e33b3165bb969b2b9cb38a8b49.tar.gz android_frameworks_ex-f88df948fc7821e33b3165bb969b2b9cb38a8b49.tar.bz2 android_frameworks_ex-f88df948fc7821e33b3165bb969b2b9cb38a8b49.zip |
Merge "Added a way to trigger an interpolated rotation of the carousel"
Diffstat (limited to 'carousel')
4 files changed, 148 insertions, 1 deletions
diff --git a/carousel/java/com/android/ex/carousel/CarouselController.java b/carousel/java/com/android/ex/carousel/CarouselController.java index 7516250..cd29f68 100644 --- a/carousel/java/com/android/ex/carousel/CarouselController.java +++ b/carousel/java/com/android/ex/carousel/CarouselController.java @@ -606,6 +606,29 @@ public class CarouselController { } } + /** + * Triggers a rotation of the carousel. All angles are in card units, see: + * {@link CarouselController#setCarouselRotationAngle(float)}) for more details. + * + * @param endAngle the card unit to which the carousel should rotate to + * @param milliseconds the length of the animation + * @param interpolationMode three modes are currently supported : + * {@link CarouselView.InterpolationMode#LINEAR} + * {@link CarouselView.InterpolationMode#DECELERATE_QUADRATIC} + * {@link CarouselView.InterpolationMode#ACCELERATE_DECELERATE_CUBIC} + * @param maxAnimatedArc the maximum angular distance over which the transition will be + * animated. + * If the current position is further away, it is set at maxAnimatedArc from endAngle. + * This parameter is ignored when <= 0. + */ + public void setCarouselRotationAngle(float endAngle, int milliseconds, int interpolationMode, + float maxAnimatedArc) { + if (mRenderScript != null) { + mRenderScript.setCarouselRotationAngle(endAngle, milliseconds, + interpolationMode, maxAnimatedArc); + } + } + public void setRadius(float radius) { mRadius = radius; if (mRenderScript != null) { diff --git a/carousel/java/com/android/ex/carousel/CarouselRS.java b/carousel/java/com/android/ex/carousel/CarouselRS.java index 4467fb3..6ab4811 100644 --- a/carousel/java/com/android/ex/carousel/CarouselRS.java +++ b/carousel/java/com/android/ex/carousel/CarouselRS.java @@ -631,6 +631,12 @@ public class CarouselRS { mScript.invoke_setCarouselRotationAngle(theta); } + public void setCarouselRotationAngle(float endAngle, int milliseconds, int interpolationMode, + float maxAnimatedArc) { + mScript.invoke_setCarouselRotationAngle2(endAngle, milliseconds, interpolationMode, + maxAnimatedArc); + } + public void setCallback(CarouselCallback callback) { mCallback = callback; diff --git a/carousel/java/com/android/ex/carousel/CarouselView.java b/carousel/java/com/android/ex/carousel/CarouselView.java index 6fd0f20..235387b 100644 --- a/carousel/java/com/android/ex/carousel/CarouselView.java +++ b/carousel/java/com/android/ex/carousel/CarouselView.java @@ -62,6 +62,18 @@ public abstract class CarouselView extends RSSurfaceView { public static final int FILL_DIRECTION_CW = CarouselRS.FILL_DIRECTION_CW; // Note: remember to update carousel.rs when changing the values below + public static class InterpolationMode { + /** y= x **/ + public static final int LINEAR = 0; + /** The quadratic curve y= 1 - (1 - x)^2 moves quickly towards the target + * while decelerating constantly. **/ + public static final int DECELERATE_QUADRATIC = 1; + /** The cubic curve y= (3-2x)*x^2 gradually accelerates at the origin, + * and decelerates near the target. **/ + public static final int ACCELERATE_DECELERATE_CUBIC = 2; + } + + // Note: remember to update carousel.rs when changing the values below public static class DetailAlignment { /** Detail is centered vertically with respect to the card **/ public static final int CENTER_VERTICAL = 1; diff --git a/carousel/java/com/android/ex/carousel/carousel.rs b/carousel/java/com/android/ex/carousel/carousel.rs index 1646ba1..772e775 100644 --- a/carousel/java/com/android/ex/carousel/carousel.rs +++ b/carousel/java/com/android/ex/carousel/carousel.rs @@ -84,6 +84,13 @@ enum { STATE_LOADED // item was delivered }; +// Interpolation modes ** THIS LIST MUST MATCH THOSE IN CarouselView.java *** +enum { + INTERPOLATION_LINEAR = 0, + INTERPOLATION_DECELERATE_QUADRATIC = 1, + INTERPOLATION_ACCELERATE_DECELERATE_CUBIC = 2, +}; + // Detail texture alignments ** THIS LIST MUST MATCH THOSE IN CarouselView.java *** enum { /** Detail is centered vertically with respect to the card **/ @@ -215,6 +222,7 @@ static float touchBias = 0.0f; // bias on first touch static float2 touchPosition; // position of first touch, as defined by last call to doStart(x,y) static float velocity = 0.0f; // angular velocity in radians/s static bool overscroll = false; // whether we're in the overscroll animation +static bool autoscrolling = false; // whether we're in the autoscroll animation static bool isDragging = false; // true while the user is dragging the carousel static float selectionRadius = 50.0f; // movement greater than this will result in no selection static bool enableSelection = false; // enabled until the user drags outside of selectionRadius @@ -266,6 +274,7 @@ static bool __attribute__((overloadable)) static float deltaTimeInSeconds(int64_t current); static bool rayPlaneIntersect(Ray* ray, Plane* plane, float* tout); static bool rayCylinderIntersect(Ray* ray, Cylinder* cylinder, float* tout); +static void stopAutoscroll(); void init() { // initializers currently have a problem when the variables are exported, so initialize @@ -1090,6 +1099,7 @@ void doStart(float x, float y, long eventTime) isDragging = true; overscroll = false; animatedSelection = doSelection(x, y); // used to provide visual feedback on touch + stopAutoscroll(); } void doStop(float x, float y, long eventTime) @@ -1175,6 +1185,100 @@ void doMotion(float x, float y, long eventTime) } //////////////////////////////////////////////////////////////////////////////////////////////////// +// Autoscroll Interpolation +//////////////////////////////////////////////////////////////////////////////////////////////////// +static int64_t autoscrollStartTime = 0L; //tracks when we actually started interpolating +static int64_t autoscrollDuration = 0L; //in milli seconds +static int autoscrollInterpolationMode = INTERPOLATION_LINEAR; + +static float autoscrollStopAngle = 0.0f; +static float autoscrollStartAngle = 0.0f; + +void setCarouselRotationAngle2( + float endAngle, + int milliseconds, + int interpolationMode, + float maxAnimatedArc) +{ + float actualStart = radiansToCarouselRotationAngle(bias); + + if (maxAnimatedArc > 0) { + //snap the current position to keep end - start under maxAnimatedArc + if (actualStart <= endAngle) { + if (actualStart < endAngle - maxAnimatedArc) { + actualStart = endAngle - maxAnimatedArc; + } + } + else { + if (actualStart > endAngle + maxAnimatedArc) { + actualStart = endAngle + maxAnimatedArc; + } + } + } + + animating = true; + autoscrolling = true; + autoscrollDuration = milliseconds; + autoscrollInterpolationMode = interpolationMode; + autoscrollStartAngle = carouselRotationAngleToRadians(actualStart); + autoscrollStopAngle = carouselRotationAngleToRadians(endAngle); + + //Make sure the start and stop angles are in the allowed range + const float highBias = maximumBias(); + const float lowBias = minimumBias(); + autoscrollStartAngle = clamp(autoscrollStartAngle, lowBias, highBias); + autoscrollStopAngle = clamp(autoscrollStopAngle, lowBias, highBias); + + //stop other animation kinds + overscroll = false; + velocity = 0.0f; +} + +static void stopAutoscroll() +{ + autoscrolling = false; + autoscrollStartTime = 0L; //reset for next time +} + +// This method computes the position of all the cards by updating bias based on a +// simple interpolation model. If the cards are still in motion, returns true. +static bool doAutoscroll(float currentTime) +{ + if (autoscrollDuration == 0L) { + return false; + } + + if (autoscrollStartTime == 0L) { + autoscrollStartTime = currentTime; + } + + const int64_t interpolationEndTime = autoscrollStartTime + autoscrollDuration; + + float timePos = (currentTime - autoscrollStartTime) / (float)autoscrollDuration; + if (timePos > 1.0f) { + timePos = 1.0f; + } + + float lambda = timePos; //default to linear + if (autoscrollInterpolationMode == INTERPOLATION_DECELERATE_QUADRATIC) { + lambda = 1.0f - (1.0f - timePos) * (1.0f - timePos); + } + else if (autoscrollInterpolationMode == INTERPOLATION_ACCELERATE_DECELERATE_CUBIC) { + lambda = timePos * timePos * (3 - 2 * timePos); + } + + bias = lambda * autoscrollStopAngle + (1.0 - lambda) * autoscrollStartAngle; + + if (currentTime > interpolationEndTime) { + stopAutoscroll(); + return false; + } + else { + return true; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// // Hit detection using ray casting. //////////////////////////////////////////////////////////////////////////////////////////////////// static const float EPSILON = 1.0e-6f; @@ -1424,7 +1528,7 @@ static float easeOut(float x) return x; } -// Computes the next value for bias using the current animation (physics or overscroll) +// Computes the next value for bias using the current animation (physics/overscroll/autoscrolling) static bool updateNextPosition(int64_t currentTime) { static const float biasMin = 1e-4f; // close enough if we're within this margin of result @@ -1457,6 +1561,8 @@ static bool updateNextPosition(int64_t currentTime) } else { overscroll = false; } + } else if (autoscrolling) { + stillAnimating = doAutoscroll(currentTime); } else { stillAnimating = doPhysics(dt); overscroll = bias > highBias || bias < lowBias; |