Fields Summary |
---|
private static final android.animation.TimeInterpolator | LINEAR_INTERPOLATOR |
private static final float | GLOBAL_SPEED |
private static final float | WAVE_OPACITY_DECAY_VELOCITY |
private static final float | WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX |
private static final float | WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN |
private static final float | WAVE_OUTER_SIZE_INFLUENCE_MAX |
private static final float | WAVE_OUTER_SIZE_INFLUENCE_MIN |
private static final int | ENTER_DURATION |
private static final int | ENTER_DURATION_FAST |
private final ArrayList | mRunningAnimations |
private final RippleDrawable | mOwner |
private final android.graphics.Rect | mBoundsBounds used for computing max radius. |
private int | mColorARGB color for drawing this ripple. |
private float | mOuterRadiusMaximum ripple radius. |
private float | mDensityScreen density used to adjust pixel-based velocities. |
private android.graphics.CanvasProperty | mPropOuterPaint |
private android.graphics.CanvasProperty | mPropOuterRadius |
private android.graphics.CanvasProperty | mPropOuterX |
private android.graphics.CanvasProperty | mPropOuterY |
private android.animation.ObjectAnimator | mAnimOuterOpacity |
private android.graphics.Paint | mTempPaint |
private float | mOuterOpacity |
private float | mOuterX |
private float | mOuterY |
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 | mHasPendingHardwareExit |
private int | mPendingOpacityDuration |
private int | mPendingInflectionDuration |
private int | mPendingInflectionOpacity |
private final android.animation.AnimatorListenerAdapter | mAnimationListener |
Methods Summary |
---|
public void | cancel()Cancel all animations. The caller is responsible for removing
the ripple from the list of animating ripples.
cancelSoftwareAnimations();
cancelHardwareAnimations(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) {
mOuterOpacity = 0;
}
}
mHardwareAnimating = false;
|
private void | cancelSoftwareAnimations()
if (mAnimOuterOpacity != null) {
mAnimOuterOpacity.cancel();
mAnimOuterOpacity = null;
}
|
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();
|
public boolean | draw(android.graphics.Canvas c, android.graphics.Paint p)Draws the ripple centered at (0,0) using the specified paint.
mColor = p.getColor();
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(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
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 * 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;
}
return hasContent;
|
private void | endSoftwareAnimations()
if (mAnimOuterOpacity != null) {
mAnimOuterOpacity.end();
mAnimOuterOpacity = null;
}
|
public void | enter(boolean fast)Starts the enter animation.
cancel();
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 = opacity;
// Enter animations always run on the UI thread, since it's unlikely
// that anything interesting is happening until the user lifts their
// finger.
opacity.start();
|
public void | exit()Starts the exit animation.
cancel();
// Scale the outer max opacity and opacity velocity based
// on the size of the outer radius.
final int opacityDuration = (int) (1000 / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
final float outerSizeInfluence = MathUtils.constrain(
(mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
/ (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN,
WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX, outerSizeInfluence);
// Determine at what time the inner and outer opacity intersect.
// inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
// 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) (Color.alpha(mColor) * (mOuterOpacity
+ inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
if (mCanUseHardware) {
createPendingHardwareExit(opacityDuration, inflectionDuration, inflectionOpacity);
} else {
exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity);
}
|
private void | exitSoftware(int opacityDuration, int inflectionDuration, int inflectionOpacity)
final ObjectAnimator outerOpacityAnim;
if (inflectionDuration > 0) {
// Outer opacity continues to increase for a bit.
outerOpacityAnim = ObjectAnimator.ofFloat(this,
"outerOpacity", inflectionOpacity / 255.0f);
outerOpacityAnim.setAutoCancel(true);
outerOpacityAnim.setDuration(inflectionDuration);
outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
// Chain the outer opacity exit animation.
final int outerDuration = opacityDuration - inflectionDuration;
if (outerDuration > 0) {
outerOpacityAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat(
RippleBackground.this, "outerOpacity", 0);
outerFadeOutAnim.setAutoCancel(true);
outerFadeOutAnim.setDuration(outerDuration);
outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
outerFadeOutAnim.addListener(mAnimationListener);
mAnimOuterOpacity = outerFadeOutAnim;
outerFadeOutAnim.start();
}
@Override
public void onAnimationCancel(Animator animation) {
animation.removeListener(this);
}
});
} else {
outerOpacityAnim.addListener(mAnimationListener);
}
} else {
outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
outerOpacityAnim.setAutoCancel(true);
outerOpacityAnim.setDuration(opacityDuration);
outerOpacityAnim.addListener(mAnimationListener);
}
mAnimOuterOpacity = outerOpacityAnim;
outerOpacityAnim.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 | getOuterOpacity()
return mOuterOpacity;
|
private android.graphics.Paint | getTempPaint(android.graphics.Paint original)
if (mTempPaint == null) {
mTempPaint = new Paint();
}
mTempPaint.set(original);
return mTempPaint;
|
private void | invalidateSelf()
mOwner.invalidateSelf();
|
public void | jump()Jump all animations to their end state. The caller is responsible for
removing the ripple from the list of animating ripples.
endSoftwareAnimations();
cancelHardwareAnimations(true);
|
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);
}
|
public void | setOuterOpacity(float a)
mOuterOpacity = a;
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;
|
public boolean | shouldDraw()
return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0);
|
private void | startPendingHardwareExit(android.view.HardwareCanvas c, android.graphics.Paint p)
mHasPendingHardwareExit = false;
final int opacityDuration = mPendingOpacityDuration;
final int inflectionDuration = mPendingInflectionDuration;
final int inflectionOpacity = mPendingInflectionOpacity;
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);
mPropOuterY = CanvasProperty.createFloat(mOuterY);
final RenderNodeAnimator outerOpacityAnim;
if (inflectionDuration > 0) {
// Outer opacity continues to increase for a bit.
outerOpacityAnim = new RenderNodeAnimator(mPropOuterPaint,
RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
outerOpacityAnim.setDuration(inflectionDuration);
outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
// Chain the outer opacity exit animation.
final int outerDuration = opacityDuration - inflectionDuration;
if (outerDuration > 0) {
final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
outerFadeOutAnim.setDuration(outerDuration);
outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
outerFadeOutAnim.setStartDelay(inflectionDuration);
outerFadeOutAnim.setStartValue(inflectionOpacity);
outerFadeOutAnim.addListener(mAnimationListener);
outerFadeOutAnim.setTarget(c);
outerFadeOutAnim.start();
mRunningAnimations.add(outerFadeOutAnim);
} else {
outerOpacityAnim.addListener(mAnimationListener);
}
} else {
outerOpacityAnim = new RenderNodeAnimator(
mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
outerOpacityAnim.setDuration(opacityDuration);
outerOpacityAnim.addListener(mAnimationListener);
}
outerOpacityAnim.setTarget(c);
outerOpacityAnim.start();
mRunningAnimations.add(outerOpacityAnim);
mHardwareAnimating = true;
// Set up the software values to match the hardware end values.
mOuterOpacity = 0;
|