package carbon.drawable.ripple; import android.animation.Animator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; /** * Abstract class that handles hardware/software hand-off and lifecycle for * animated ripple foreground and background components. */ abstract class RippleComponent { private final RippleDrawableICS mOwner; /** * Bounds used for computing max radius. May be modified by the owner. */ protected final Rect mBounds; private Animator mSoftwareAnimator; /** * Whether we have an explicit maximum radius. */ private boolean mHasMaxRadius; /** * How big this ripple should be when fully entered. */ protected float mTargetRadius; /** * Screen density used to adjust pixel-based constants. */ protected float mDensity; public RippleComponent(RippleDrawableICS owner, Rect bounds) { mOwner = owner; mBounds = bounds; } public void onBoundsChange() { if (!mHasMaxRadius) { mTargetRadius = getTargetRadius(mBounds); onTargetRadiusChanged(mTargetRadius); } } public final void setup(float maxRadius, float density) { if (maxRadius >= 0) { mHasMaxRadius = true; mTargetRadius = maxRadius; } else { mTargetRadius = getTargetRadius(mBounds); } mDensity = density; onTargetRadiusChanged(mTargetRadius); } private static float getTargetRadius(Rect bounds) { final float halfWidth = bounds.width() / 2.0f; final float halfHeight = bounds.height() / 2.0f; return (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); } /** * Starts a ripple enter animation. * * @param fast whether the ripple should enter quickly */ public final void enter(boolean fast) { cancel(); mSoftwareAnimator = createSoftwareEnter(fast); if (mSoftwareAnimator != null) { mSoftwareAnimator.start(); } } /** * Starts a ripple exit animation. */ public final void exit() { cancel(); mSoftwareAnimator = createSoftwareExit(); mSoftwareAnimator.start(); } /** * Cancels all animations. Software animation values are left in the * current state, while hardware animation values jump to the end state. */ public void cancel() { cancelSoftwareAnimations(); } /** * Ends all animations, jumping values to the end state. */ public void end() { endSoftwareAnimations(); } /** * Draws the ripple to the canvas, inheriting the paint's color and alpha * properties. * * @param c the canvas to which the ripple should be drawn * @param p the paint used to draw the ripple * @return {@code true} if something was drawn, {@code false} otherwise */ public boolean draw(Canvas c, Paint p) { return drawSoftware(c, p); } /** * Populates {@code bounds} with the maximum drawing bounds of the ripple * relative to its center. The resulting bounds should be translated into * parent drawable coordinates before use. * * @param bounds the rect to populate with drawing bounds */ public void getBounds(Rect bounds) { final int r = (int) Math.ceil(mTargetRadius); bounds.set(-r, -r, r, r); } /** * Cancels any current software animations, leaving the values in their * current state. */ private void cancelSoftwareAnimations() { if (mSoftwareAnimator != null) { mSoftwareAnimator.cancel(); mSoftwareAnimator = null; } } /** * Ends any current software animations, jumping the values to their end * state. */ private void endSoftwareAnimations() { if (mSoftwareAnimator != null) { mSoftwareAnimator.end(); mSoftwareAnimator = null; } } protected final void invalidateSelf() { mOwner.invalidateSelf(false); } protected final void onHotspotBoundsChanged() { if (!mHasMaxRadius) { final float halfWidth = mBounds.width() / 2.0f; final float halfHeight = mBounds.height() / 2.0f; final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); onTargetRadiusChanged(targetRadius); } } /** * Called when the target radius changes. * * @param targetRadius the new target radius */ protected void onTargetRadiusChanged(float targetRadius) { // Stub. } protected abstract Animator createSoftwareEnter(boolean fast); protected abstract Animator createSoftwareExit(); protected abstract boolean drawSoftware(Canvas c, Paint p); /** * Called when the hardware exit is cancelled. Jumps software values to end * state to ensure that software and hardware values are synchronized. */ protected abstract void jumpValuesToExit(); }