Fields Summary |
---|
private static final android.animation.TimeInterpolator | LINEAR_INTERPOLATOR |
private static final android.animation.TimeInterpolator | DECEL_INTERPOLATOR |
private static final float | GLOBAL_SPEED |
private static final float | WAVE_TOUCH_DOWN_ACCELERATION |
private static final float | WAVE_TOUCH_UP_ACCELERATION |
private static final float | WAVE_OPACITY_DECAY_VELOCITY |
private static final long | RIPPLE_ENTER_DELAY |
private final ArrayList | mRunningAnimations |
private final RippleDrawable | mOwner |
private final android.graphics.Rect | mBoundsBounds used for computing max radius. |
private float | mOuterRadiusMaximum ripple radius. |
private float | mDensityScreen density used to adjust pixel-based velocities. |
private float | mStartingX |
private float | mStartingY |
private float | mClampedStartingX |
private float | mClampedStartingY |
private android.graphics.CanvasProperty | mPropPaint |
private android.graphics.CanvasProperty | mPropRadius |
private android.graphics.CanvasProperty | mPropX |
private android.graphics.CanvasProperty | mPropY |
private android.animation.ObjectAnimator | mAnimRadius |
private android.animation.ObjectAnimator | mAnimOpacity |
private android.animation.ObjectAnimator | mAnimX |
private android.animation.ObjectAnimator | mAnimY |
private android.graphics.Paint | mTempPaint |
private float | mOpacity |
private float | mOuterX |
private float | mOuterY |
private float | mTweenRadius |
private float | mTweenX |
private float | mTweenY |
private boolean | mHardwareAnimatingWhether we should be drawing hardware animations. |
private boolean | mCanUseHardwareWhether we can use hardware acceleration for the exit animation. |
private boolean | mHasMaxRadiusWhether we have an explicit maximum radius. |
private boolean | mCanceledWhether we were canceled externally and should avoid self-removal. |
private boolean | mHasPendingHardwareExit |
private int | mPendingRadiusDuration |
private int | mPendingOpacityDuration |
private final android.animation.AnimatorListenerAdapter | mAnimationListener |
Methods Summary |
---|
public void | cancel()Cancels all animations. The caller is responsible for removing
the ripple from the list of animating ripples.
mCanceled = true;
cancelSoftwareAnimations();
cancelHardwareAnimations(false);
mCanceled = false;
|
private void | cancelHardwareAnimations(boolean jumpToEnd)Cancels any running hardware animations.
final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
final int N = runningAnimations.size();
for (int i = 0; i < N; i++) {
if (jumpToEnd) {
runningAnimations.get(i).end();
} else {
runningAnimations.get(i).cancel();
}
}
runningAnimations.clear();
if (mHasPendingHardwareExit) {
// If we had a pending hardware exit, jump to the end state.
mHasPendingHardwareExit = false;
if (jumpToEnd) {
mOpacity = 0;
mTweenX = 1;
mTweenY = 1;
mTweenRadius = 1;
}
}
mHardwareAnimating = false;
|
private void | cancelSoftwareAnimations()
if (mAnimRadius != null) {
mAnimRadius.cancel();
mAnimRadius = null;
}
if (mAnimOpacity != null) {
mAnimOpacity.cancel();
mAnimOpacity = null;
}
if (mAnimX != null) {
mAnimX.cancel();
mAnimX = null;
}
if (mAnimY != null) {
mAnimY.cancel();
mAnimY = null;
}
|
private void | clampStartingPosition()
final float cX = mBounds.exactCenterX();
final float cY = mBounds.exactCenterY();
final float dX = mStartingX - cX;
final float dY = mStartingY - cY;
final float r = mOuterRadius;
if (dX * dX + dY * dY > r * r) {
// Point is outside the circle, clamp to the circumference.
final double angle = Math.atan2(dY, dX);
mClampedStartingX = cX + (float) (Math.cos(angle) * r);
mClampedStartingY = cY + (float) (Math.sin(angle) * r);
} else {
mClampedStartingX = mStartingX;
mClampedStartingY = mStartingY;
}
|
private void | createPendingHardwareExit(int radiusDuration, int opacityDuration)
mHasPendingHardwareExit = true;
mPendingRadiusDuration = radiusDuration;
mPendingOpacityDuration = opacityDuration;
// The animation will start on the next draw().
invalidateSelf();
|
public boolean | draw(android.graphics.Canvas c, android.graphics.Paint p)Draws the ripple centered at (0,0) using the specified paint.
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
cancelHardwareAnimations(true);
}
mCanUseHardware = canUseHardware;
final boolean hasContent;
if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) {
hasContent = drawHardware((HardwareCanvas) c, p);
} else {
hasContent = drawSoftware(c, p);
}
return hasContent;
|
private boolean | drawHardware(android.view.HardwareCanvas c, android.graphics.Paint p)
if (mHasPendingHardwareExit) {
cancelHardwareAnimations(false);
startPendingHardwareExit(c, p);
}
c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
return true;
|
private boolean | drawSoftware(android.graphics.Canvas c, android.graphics.Paint p)
boolean hasContent = false;
final int paintAlpha = p.getAlpha();
final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
if (alpha > 0 && radius > 0) {
final float x = MathUtils.lerp(
mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
final float y = MathUtils.lerp(
mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
p.setAlpha(alpha);
c.drawCircle(x, y, radius, p);
p.setAlpha(paintAlpha);
hasContent = true;
}
return hasContent;
|
private void | endSoftwareAnimations()
if (mAnimRadius != null) {
mAnimRadius.end();
mAnimRadius = null;
}
if (mAnimOpacity != null) {
mAnimOpacity.end();
mAnimOpacity = null;
}
if (mAnimX != null) {
mAnimX.end();
mAnimX = null;
}
if (mAnimY != null) {
mAnimY.end();
mAnimY = null;
}
|
public void | enter()Starts the enter animation.
cancel();
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
radius.setAutoCancel(true);
radius.setDuration(radiusDuration);
radius.setInterpolator(LINEAR_INTERPOLATOR);
radius.setStartDelay(RIPPLE_ENTER_DELAY);
final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1);
cX.setAutoCancel(true);
cX.setDuration(radiusDuration);
cX.setInterpolator(LINEAR_INTERPOLATOR);
cX.setStartDelay(RIPPLE_ENTER_DELAY);
final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1);
cY.setAutoCancel(true);
cY.setDuration(radiusDuration);
cY.setInterpolator(LINEAR_INTERPOLATOR);
cY.setStartDelay(RIPPLE_ENTER_DELAY);
mAnimRadius = radius;
mAnimX = cX;
mAnimY = cY;
// Enter animations always run on the UI thread, since it's unlikely
// that anything interesting is happening until the user lifts their
// finger.
radius.start();
cX.start();
cY.start();
|
public void | exit()Starts the exit animation.
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final float remaining;
if (mAnimRadius != null && mAnimRadius.isRunning()) {
remaining = mOuterRadius - radius;
} else {
remaining = mOuterRadius;
}
cancel();
final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+ WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
if (mCanUseHardware) {
createPendingHardwareExit(radiusDuration, opacityDuration);
} else {
exitSoftware(radiusDuration, opacityDuration);
}
|
private void | exitSoftware(int radiusDuration, int opacityDuration)
final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
radiusAnim.setAutoCancel(true);
radiusAnim.setDuration(radiusDuration);
radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1);
xAnim.setAutoCancel(true);
xAnim.setDuration(radiusDuration);
xAnim.setInterpolator(DECEL_INTERPOLATOR);
final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1);
yAnim.setAutoCancel(true);
yAnim.setDuration(radiusDuration);
yAnim.setInterpolator(DECEL_INTERPOLATOR);
final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0);
opacityAnim.setAutoCancel(true);
opacityAnim.setDuration(opacityDuration);
opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
opacityAnim.addListener(mAnimationListener);
mAnimRadius = radiusAnim;
mAnimOpacity = opacityAnim;
mAnimX = xAnim;
mAnimY = yAnim;
radiusAnim.start();
opacityAnim.start();
xAnim.start();
yAnim.start();
|
public void | getBounds(android.graphics.Rect bounds)Returns the maximum bounds of the ripple relative to the ripple center.
final int outerX = (int) mOuterX;
final int outerY = (int) mOuterY;
final int r = (int) mOuterRadius + 1;
bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
|
public float | getOpacity()
return mOpacity;
|
public float | getRadiusGravity()
return mTweenRadius;
|
private android.graphics.Paint | getTempPaint(android.graphics.Paint original)
if (mTempPaint == null) {
mTempPaint = new Paint();
}
mTempPaint.set(original);
return mTempPaint;
|
public float | getXGravity()
return mTweenX;
|
public float | getYGravity()
return mTweenY;
|
private void | invalidateSelf()
mOwner.invalidateSelf();
|
public boolean | isHardwareAnimating()
return mHardwareAnimating;
|
public void | jump()Jump all animations to their end state. The caller is responsible for
removing the ripple from the list of animating ripples.
mCanceled = true;
endSoftwareAnimations();
cancelHardwareAnimations(true);
mCanceled = false;
|
public void | move(float x, float y)Specifies the starting position relative to the drawable bounds. No-op if
the ripple has already entered.
mStartingX = x;
mStartingY = y;
clampStartingPosition();
|
public void | onHotspotBoundsChanged()
if (!mHasMaxRadius) {
final float halfWidth = mBounds.width() / 2.0f;
final float halfHeight = mBounds.height() / 2.0f;
mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
clampStartingPosition();
}
|
private void | removeSelf()
// The owner will invalidate itself.
if (!mCanceled) {
mOwner.removeRipple(this);
}
|
public void | setOpacity(float a)
mOpacity = a;
invalidateSelf();
|
public void | setRadiusGravity(float r)
mTweenRadius = r;
invalidateSelf();
|
public void | setXGravity(float x)
mTweenX = x;
invalidateSelf();
|
public void | setYGravity(float y)
mTweenY = y;
invalidateSelf();
|
public void | setup(int maxRadius, float density)
if (maxRadius != RippleDrawable.RADIUS_AUTO) {
mHasMaxRadius = true;
mOuterRadius = maxRadius;
} else {
final float halfWidth = mBounds.width() / 2.0f;
final float halfHeight = mBounds.height() / 2.0f;
mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
}
mOuterX = 0;
mOuterY = 0;
mDensity = density;
clampStartingPosition();
|
private void | startPendingHardwareExit(android.view.HardwareCanvas c, android.graphics.Paint p)
mHasPendingHardwareExit = false;
final int radiusDuration = mPendingRadiusDuration;
final int opacityDuration = mPendingOpacityDuration;
final float startX = MathUtils.lerp(
mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
final float startY = MathUtils.lerp(
mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final Paint paint = getTempPaint(p);
paint.setAlpha((int) (paint.getAlpha() * mOpacity + 0.5f));
mPropPaint = CanvasProperty.createPaint(paint);
mPropRadius = CanvasProperty.createFloat(startRadius);
mPropX = CanvasProperty.createFloat(startX);
mPropY = CanvasProperty.createFloat(startY);
final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius);
radiusAnim.setDuration(radiusDuration);
radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
radiusAnim.setTarget(c);
radiusAnim.start();
final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX);
xAnim.setDuration(radiusDuration);
xAnim.setInterpolator(DECEL_INTERPOLATOR);
xAnim.setTarget(c);
xAnim.start();
final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY);
yAnim.setDuration(radiusDuration);
yAnim.setInterpolator(DECEL_INTERPOLATOR);
yAnim.setTarget(c);
yAnim.start();
final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint,
RenderNodeAnimator.PAINT_ALPHA, 0);
opacityAnim.setDuration(opacityDuration);
opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
opacityAnim.addListener(mAnimationListener);
opacityAnim.setTarget(c);
opacityAnim.start();
mRunningAnimations.add(radiusAnim);
mRunningAnimations.add(opacityAnim);
mRunningAnimations.add(xAnim);
mRunningAnimations.add(yAnim);
mHardwareAnimating = true;
// Set up the software values to match the hardware end values.
mOpacity = 0;
mTweenX = 1;
mTweenY = 1;
mTweenRadius = 1;
|