From b996d809bf10a9ad1f6f6be790d0261fe1565f3b Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 4 Jun 2014 14:35:42 -0700 Subject: [PATCH] Update ripple spec, fix ripple mask, rotate progress drawable Change-Id: I4fc155bf2f12d9f324c354dee81479f9cddafac4 --- core/res/res/values/colors_quantum.xml | 6 ++-- .../graphics/drawable/QuantumProgressDrawable.java | 37 +++++++++++++++++++--- .../java/android/graphics/drawable/Ripple.java | 27 ++++++++++------ .../android/graphics/drawable/RippleDrawable.java | 30 ++++++++++-------- 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml index dffc9b0902c2..f49861a517cc 100644 --- a/core/res/res/values/colors_quantum.xml +++ b/core/res/res/values/colors_quantum.xml @@ -19,10 +19,8 @@ #ff212121 #fffafafa - - #45000000 - - #30ffffff + #20444444 + #20ffffff #ff5a595b #ffd6d7d7 diff --git a/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java b/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java index d756eb13eff2..675355c581af 100644 --- a/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java +++ b/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java @@ -54,6 +54,12 @@ class QuantumProgressDrawable extends Drawable implements Animatable { private static final TimeInterpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator(); private static final TimeInterpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator(); + /** The duration of a single progress spin in milliseconds. */ + private static final int ANIMATION_DURATION = 1000 * 80 / 60; + + /** The number of points in the progress "star". */ + private static final int NUM_POINTS = 5; + /** The list of animators operating on this drawable. */ private final ArrayList mAnimators = new ArrayList(); @@ -62,6 +68,9 @@ class QuantumProgressDrawable extends Drawable implements Animatable { private QuantumProgressState mState; + /** Canvas rotation in degrees. */ + private float mRotation; + private boolean mMutated; public QuantumProgressDrawable() { @@ -187,7 +196,11 @@ class QuantumProgressDrawable extends Drawable implements Animatable { @Override public void draw(Canvas c) { - mRing.draw(c, getBounds()); + final Rect bounds = getBounds(); + final int saveCount = c.save(); + c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY()); + mRing.draw(c, bounds); + c.restoreToCount(saveCount); } @Override @@ -210,6 +223,15 @@ class QuantumProgressDrawable extends Drawable implements Animatable { return mRing.getColorFilter(); } + private void setRotation(float rotation) { + mRotation = rotation; + invalidateSelf(); + } + + private float getRotation() { + return mRotation; + } + @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; @@ -256,26 +278,33 @@ class QuantumProgressDrawable extends Drawable implements Animatable { final Ring ring = mRing; final ObjectAnimator endTrim = ObjectAnimator.ofFloat(ring, "endTrim", 0, 0.75f); - endTrim.setDuration(1000 * 80 / 60); + endTrim.setDuration(ANIMATION_DURATION); endTrim.setInterpolator(START_CURVE_INTERPOLATOR); endTrim.setRepeatCount(ObjectAnimator.INFINITE); endTrim.setRepeatMode(ObjectAnimator.RESTART); final ObjectAnimator startTrim = ObjectAnimator.ofFloat(ring, "startTrim", 0.0f, 0.75f); - startTrim.setDuration(1000 * 80 / 60); + startTrim.setDuration(ANIMATION_DURATION); startTrim.setInterpolator(END_CURVE_INTERPOLATOR); startTrim.setRepeatCount(ObjectAnimator.INFINITE); startTrim.setRepeatMode(ObjectAnimator.RESTART); final ObjectAnimator rotation = ObjectAnimator.ofFloat(ring, "rotation", 0.0f, 0.25f); - rotation.setDuration(1000 * 80 / 60); + rotation.setDuration(ANIMATION_DURATION); rotation.setInterpolator(LINEAR_INTERPOLATOR); rotation.setRepeatCount(ObjectAnimator.INFINITE); rotation.setRepeatMode(ObjectAnimator.RESTART); + final ObjectAnimator groupRotation = ObjectAnimator.ofFloat(this, "rotation", 0.0f, 360.0f); + groupRotation.setDuration(NUM_POINTS * ANIMATION_DURATION); + groupRotation.setInterpolator(LINEAR_INTERPOLATOR); + groupRotation.setRepeatCount(ObjectAnimator.INFINITE); + groupRotation.setRepeatMode(ObjectAnimator.RESTART); + mAnimators.add(endTrim); mAnimators.add(startTrim); mAnimators.add(rotation); + mAnimators.add(groupRotation); } private final Callback mCallback = new Callback() { diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index 55d01ed2e5b8..096e5546da86 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.util.MathUtils; import android.view.HardwareCanvas; import android.view.RenderNodeAnimator; +import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import java.util.ArrayList; @@ -37,13 +38,16 @@ import java.util.ArrayList; */ class Ripple { private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + private static final TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator(4); private static final float GLOBAL_SPEED = 1.0f; - private static final float WAVE_TOUCH_DOWN_ACCELERATION = 512.0f * GLOBAL_SPEED; - private static final float WAVE_TOUCH_UP_ACCELERATION = 1024.0f * GLOBAL_SPEED; - private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.6f / GLOBAL_SPEED; + private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; + private static final float WAVE_TOUCH_UP_ACCELERATION = 3096.0f * GLOBAL_SPEED; + private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.9f / GLOBAL_SPEED; private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED; + private static final long RIPPLE_ENTER_DELAY = 100; + // Hardware animators. private final ArrayList mRunningAnimations = new ArrayList<>(); private final ArrayList mPendingAnimations = new ArrayList<>(); @@ -287,14 +291,19 @@ class Ripple { 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); final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); outer.setAutoCancel(true); @@ -377,15 +386,15 @@ class Ripple { final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius); radiusAnim.setDuration(radiusDuration); - radiusAnim.setInterpolator(LINEAR_INTERPOLATOR); + radiusAnim.setInterpolator(DECEL_INTERPOLATOR); final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX); xAnim.setDuration(radiusDuration); - xAnim.setInterpolator(LINEAR_INTERPOLATOR); + xAnim.setInterpolator(DECEL_INTERPOLATOR); final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY); yAnim.setDuration(radiusDuration); - yAnim.setInterpolator(LINEAR_INTERPOLATOR); + yAnim.setInterpolator(DECEL_INTERPOLATOR); final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0); @@ -439,17 +448,17 @@ class Ripple { final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1); radiusAnim.setAutoCancel(true); radiusAnim.setDuration(radiusDuration); - radiusAnim.setInterpolator(LINEAR_INTERPOLATOR); + radiusAnim.setInterpolator(DECEL_INTERPOLATOR); final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1); xAnim.setAutoCancel(true); xAnim.setDuration(radiusDuration); - xAnim.setInterpolator(LINEAR_INTERPOLATOR); + xAnim.setInterpolator(DECEL_INTERPOLATOR); final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1); yAnim.setAutoCancel(true); yAnim.setDuration(radiusDuration); - yAnim.setInterpolator(LINEAR_INTERPOLATOR); + yAnim.setInterpolator(DECEL_INTERPOLATOR); final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0); opacityAnim.setAutoCancel(true); diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 6f2982568d14..58f6eaa53773 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -95,6 +95,9 @@ public class RippleDrawable extends LayerDrawable { private final RippleState mState; + /** The masking layer, e.g. the layer with id R.id.mask. */ + private Drawable mMask; + /** The current hotspot. May be actively animating or pending entry. */ private Ripple mHotspot; @@ -261,21 +264,14 @@ public class RippleDrawable extends LayerDrawable { super.inflate(r, parser, attrs, theme); setTargetDensity(r.getDisplayMetrics()); - - // Find the mask - final int N = getNumberOfLayers(); - for (int i = 0; i < N; i++) { - if (mLayerState.mChildren[i].mId == R.id.mask) { - mState.mMask = mLayerState.mChildren[i].mDrawable; - } - } + initializeFromState(); } @Override public boolean setDrawableByLayerId(int id, Drawable drawable) { if (super.setDrawableByLayerId(id, drawable)) { if (id == R.id.mask) { - mState.mMask = drawable; + mMask = drawable; } return true; @@ -361,6 +357,8 @@ public class RippleDrawable extends LayerDrawable { } finally { a.recycle(); } + + initializeFromState(); } @Override @@ -527,7 +525,7 @@ public class RippleDrawable extends LayerDrawable { private int drawContentLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) { final int count = mLayerState.mNum; - if (count == 0 || (mState.mMask != null && count == 1)) { + if (count == 0 || (mMask != null && count == 1)) { return -1; } @@ -611,7 +609,7 @@ public class RippleDrawable extends LayerDrawable { } private int drawMaskingLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) { - final Drawable mask = mState.mMask; + final Drawable mask = mMask; if (mask == null) { return -1; } @@ -667,7 +665,6 @@ public class RippleDrawable extends LayerDrawable { int[] mTouchThemeAttrs; ColorStateList mTint = null; PorterDuffXfermode mTintXfermode = SRC_ATOP; - Drawable mMask; int mMaxRadius = RADIUS_AUTO; boolean mPinned = false; @@ -763,8 +760,6 @@ public class RippleDrawable extends LayerDrawable { } mState = ns; - mState.mMask = findDrawableByLayerId(R.id.mask); - mLayerState = ns; if (ns.mNum > 0) { @@ -774,5 +769,12 @@ public class RippleDrawable extends LayerDrawable { if (needsTheme) { applyTheme(theme); } + + initializeFromState(); + } + + private void initializeFromState() { + // Initialize from constant state. + mMask = findDrawableByLayerId(R.id.mask); } } -- 2.11.0