diff options
Diffstat (limited to 'graphics/java/android/graphics/drawable/RippleBackground.java')
| -rw-r--r-- | graphics/java/android/graphics/drawable/RippleBackground.java | 148 |
1 files changed, 77 insertions, 71 deletions
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index faa89bf..fae4902 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -24,7 +24,6 @@ import android.graphics.Canvas; import android.graphics.CanvasProperty; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Paint.Style; import android.graphics.Rect; import android.util.MathUtils; import android.view.HardwareCanvas; @@ -43,26 +42,23 @@ class RippleBackground { private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_ENTER_VELOCITY = 10.0f * GLOBAL_SPEED; private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; + private static final int ENTER_DURATION = 667; + private static final int ENTER_DURATION_FAST = 100; + // Hardware animators. private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>(); - private final ArrayList<RenderNodeAnimator> mPendingAnimations = - new ArrayList<RenderNodeAnimator>(); private final RippleDrawable mOwner; /** Bounds used for computing max radius. */ private final Rect mBounds; - /** Full-opacity color for drawing this ripple. */ - private int mColorOpaque; - - /** Maximum alpha value for drawing this ripple. */ - private int mColorAlpha; + /** ARGB color for drawing this ripple. */ + private int mColor; /** Maximum ripple radius. */ private float mOuterRadius; @@ -96,6 +92,11 @@ class RippleBackground { /** Whether we have an explicit maximum radius. */ private boolean mHasMaxRadius; + private boolean mHasPendingHardwareExit; + private int mPendingOpacityDuration; + private int mPendingInflectionDuration; + private int mPendingInflectionOpacity; + /** * Creates a new ripple. */ @@ -104,10 +105,7 @@ class RippleBackground { mBounds = bounds; } - public void setup(int maxRadius, int color, float density) { - mColorOpaque = color | 0xFF000000; - mColorAlpha = Color.alpha(color) / 2; - + public void setup(int maxRadius, float density) { if (maxRadius != RippleDrawable.RADIUS_AUTO) { mHasMaxRadius = true; mOuterRadius = maxRadius; @@ -122,10 +120,6 @@ class RippleBackground { mDensity = density; } - public boolean isHardwareAnimating() { - return mHardwareAnimating; - } - public void onHotspotBoundsChanged() { if (!mHasMaxRadius) { final float halfWidth = mBounds.width() / 2.0f; @@ -149,6 +143,8 @@ class RippleBackground { * Draws the ripple centered at (0,0) using the specified paint. */ public boolean draw(Canvas c, Paint p) { + mColor = p.getColor(); + final boolean canUseHardware = c.isHardwareAccelerated(); if (mCanUseHardware != canUseHardware && mCanUseHardware) { // We've switched from hardware to non-hardware mode. Panic. @@ -157,8 +153,8 @@ class RippleBackground { mCanUseHardware = canUseHardware; final boolean hasContent; - if (canUseHardware && mHardwareAnimating) { - hasContent = drawHardware((HardwareCanvas) c); + if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) { + hasContent = drawHardware((HardwareCanvas) c, p); } else { hasContent = drawSoftware(c, p); } @@ -167,28 +163,13 @@ class RippleBackground { } public boolean shouldDraw() { - final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f); - return mCanUseHardware && mHardwareAnimating || outerAlpha > 0 && mOuterRadius > 0; + return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0); } - private boolean drawHardware(HardwareCanvas c) { - // If we have any pending hardware animations, cancel any running - // animations and start those now. - final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations; - final int N = pendingAnimations.size(); - if (N > 0) { + private boolean drawHardware(HardwareCanvas c, Paint p) { + if (mHasPendingHardwareExit) { cancelHardwareAnimations(false); - - // We canceled old animations, but we're about to run new ones. - mHardwareAnimating = true; - - for (int i = 0; i < N; i++) { - pendingAnimations.get(i).setTarget(c); - pendingAnimations.get(i).start(); - } - - mRunningAnimations.addAll(pendingAnimations); - pendingAnimations.clear(); + startPendingHardwareExit(c, p); } c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint); @@ -199,12 +180,13 @@ class RippleBackground { private boolean drawSoftware(Canvas c, Paint p) { boolean hasContent = false; - p.setColor(mColorOpaque); - final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f); - if (outerAlpha > 0 && mOuterRadius > 0) { - p.setAlpha(outerAlpha); - p.setStyle(Style.FILL); - c.drawCircle(mOuterX, mOuterY, mOuterRadius, p); + final int paintAlpha = p.getAlpha(); + final int alpha = (int) (paintAlpha * mOuterOpacity + 0.5f); + final float radius = mOuterRadius; + if (alpha > 0 && radius > 0) { + p.setAlpha(alpha); + c.drawCircle(mOuterX, mOuterY, radius, p); + p.setAlpha(paintAlpha); hasContent = true; } @@ -224,21 +206,20 @@ class RippleBackground { /** * Starts the enter animation. */ - public void enter() { + public void enter(boolean fast) { cancel(); - final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY); - final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); - outer.setAutoCancel(true); - outer.setDuration(outerDuration); - outer.setInterpolator(LINEAR_INTERPOLATOR); + final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); + opacity.setAutoCancel(true); + opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION); + opacity.setInterpolator(LINEAR_INTERPOLATOR); - mAnimOuterOpacity = outer; + mAnimOuterOpacity = opacity; // Enter animations always run on the UI thread, since it's unlikely // that anything interesting is happening until the user lifts their // finger. - outer.start(); + opacity.start(); } /** @@ -261,24 +242,36 @@ class RippleBackground { // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000 final int inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity) / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f)); - final int inflectionOpacity = (int) (mColorAlpha * (mOuterOpacity + final int inflectionOpacity = (int) (Color.alpha(mColor) * (mOuterOpacity + inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f); if (mCanUseHardware) { - exitHardware(opacityDuration, inflectionDuration, inflectionOpacity); + createPendingHardwareExit(opacityDuration, inflectionDuration, inflectionOpacity); } else { exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity); } } - private void exitHardware(int opacityDuration, int inflectionDuration, int inflectionOpacity) { - mPendingAnimations.clear(); + private void createPendingHardwareExit( + int opacityDuration, int inflectionDuration, int inflectionOpacity) { + mHasPendingHardwareExit = true; + mPendingOpacityDuration = opacityDuration; + mPendingInflectionDuration = inflectionDuration; + mPendingInflectionOpacity = inflectionOpacity; + + // The animation will start on the next draw(). + invalidateSelf(); + } + + private void startPendingHardwareExit(HardwareCanvas c, Paint p) { + mHasPendingHardwareExit = false; + + final int opacityDuration = mPendingOpacityDuration; + final int inflectionDuration = mPendingInflectionDuration; + final int inflectionOpacity = mPendingInflectionOpacity; - final Paint outerPaint = getTempPaint(); - outerPaint.setAntiAlias(true); - outerPaint.setColor(mColorOpaque); - outerPaint.setAlpha((int) (mColorAlpha * mOuterOpacity + 0.5f)); - outerPaint.setStyle(Style.FILL); + final Paint outerPaint = getTempPaint(p); + outerPaint.setAlpha((int) (outerPaint.getAlpha() * mOuterOpacity + 0.5f)); mPropOuterPaint = CanvasProperty.createPaint(outerPaint); mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius); mPropOuterX = CanvasProperty.createFloat(mOuterX); @@ -302,8 +295,10 @@ class RippleBackground { outerFadeOutAnim.setStartDelay(inflectionDuration); outerFadeOutAnim.setStartValue(inflectionOpacity); outerFadeOutAnim.addListener(mAnimationListener); + outerFadeOutAnim.setTarget(c); + outerFadeOutAnim.start(); - mPendingAnimations.add(outerFadeOutAnim); + mRunningAnimations.add(outerFadeOutAnim); } else { outerOpacityAnim.addListener(mAnimationListener); } @@ -315,14 +310,15 @@ class RippleBackground { outerOpacityAnim.addListener(mAnimationListener); } - mPendingAnimations.add(outerOpacityAnim); + outerOpacityAnim.setTarget(c); + outerOpacityAnim.start(); + + mRunningAnimations.add(outerOpacityAnim); mHardwareAnimating = true; // Set up the software values to match the hardware end values. mOuterOpacity = 0; - - invalidateSelf(); } /** @@ -341,10 +337,11 @@ class RippleBackground { } } - private Paint getTempPaint() { + private Paint getTempPaint(Paint original) { if (mTempPaint == null) { mTempPaint = new Paint(); } + mTempPaint.set(original); return mTempPaint; } @@ -402,7 +399,7 @@ class RippleBackground { */ public void cancel() { cancelSoftwareAnimations(); - cancelHardwareAnimations(true); + cancelHardwareAnimations(false); } private void cancelSoftwareAnimations() { @@ -415,16 +412,25 @@ class RippleBackground { /** * Cancels any running hardware animations. */ - private void cancelHardwareAnimations(boolean cancelPending) { + private void cancelHardwareAnimations(boolean jumpToEnd) { final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; final int N = runningAnimations.size(); for (int i = 0; i < N; i++) { - runningAnimations.get(i).cancel(); + if (jumpToEnd) { + runningAnimations.get(i).end(); + } else { + runningAnimations.get(i).cancel(); + } } runningAnimations.clear(); - if (cancelPending && !mPendingAnimations.isEmpty()) { - mPendingAnimations.clear(); + if (mHasPendingHardwareExit) { + // If we had a pending hardware exit, jump to the end state. + mHasPendingHardwareExit = false; + + if (jumpToEnd) { + mOuterOpacity = 0; + } } mHardwareAnimating = false; |
