Merge "Fix disappearing ripple background, treat active ripple separately" into lmp-dev

This commit is contained in:
Alan Viverette
2014-08-30 00:19:50 +00:00
committed by Android (Google) Code Review
3 changed files with 115 additions and 85 deletions

View File

@@ -105,6 +105,9 @@ class Ripple {
/** Whether we have an explicit maximum radius. */
private boolean mHasMaxRadius;
/** Whether we were canceled externally and should avoid self-removal. */
private boolean mCanceled;
/**
* Creates a new ripple.
*/
@@ -295,6 +298,8 @@ class Ripple {
* Starts the enter animation.
*/
public void enter() {
cancel();
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
@@ -332,7 +337,8 @@ class Ripple {
* Starts the exit animation.
*/
public void exit() {
cancelSoftwareAnimations();
cancel();
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final float remaining;
if (mAnimRadius != null && mAnimRadius.isRunning()) {
@@ -399,9 +405,15 @@ class Ripple {
invalidateSelf();
}
/**
* Jump all animations to their end state. The caller is responsible for
* removing the ripple from the list of animating ripples.
*/
public void jump() {
mCanceled = true;
endSoftwareAnimations();
endHardwareAnimations();
mCanceled = false;
}
private void endSoftwareAnimations() {
@@ -436,6 +448,8 @@ class Ripple {
mPendingAnimations.clear();
removeSelf();
}
mHardwareAnimating = false;
}
private Paint getTempPaint() {
@@ -479,11 +493,14 @@ class Ripple {
}
/**
* Cancel all animations.
* Cancels all animations. The caller is responsible for removing
* the ripple from the list of animating ripples.
*/
public void cancel() {
mCanceled = true;
cancelSoftwareAnimations();
cancelHardwareAnimations(true);
mCanceled = false;
}
private void cancelSoftwareAnimations() {
@@ -517,13 +534,16 @@ class Ripple {
if (cancelPending && !mPendingAnimations.isEmpty()) {
mPendingAnimations.clear();
removeSelf();
}
mHardwareAnimating = false;
}
private void removeSelf() {
// The owner will invalidate itself.
mOwner.removeRipple(this);
if (!mCanceled) {
mOwner.removeRipple(this);
}
}
private void invalidateSelf() {

View File

@@ -107,6 +107,9 @@ class RippleBackground {
/** Whether we have an explicit maximum radius. */
private boolean mHasMaxRadius;
/** Whether we were canceled externally and should avoid self-removal. */
private boolean mCanceled;
/**
* Creates a new ripple.
*/
@@ -284,6 +287,8 @@ class RippleBackground {
* Starts the enter animation.
*/
public void enter() {
cancel();
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY);
@@ -321,7 +326,7 @@ class RippleBackground {
* Starts the exit animation.
*/
public void exit() {
cancelSoftwareAnimations();
cancel();
// Scale the outer max opacity and opacity velocity based
// on the size of the outer radius.
@@ -404,9 +409,15 @@ class RippleBackground {
invalidateSelf();
}
/**
* Jump all animations to their end state. The caller is responsible for
* removing the ripple from the list of animating ripples.
*/
public void jump() {
mCanceled = true;
endSoftwareAnimations();
endHardwareAnimations();
mCanceled = false;
}
private void endSoftwareAnimations() {
@@ -437,6 +448,8 @@ class RippleBackground {
mPendingAnimations.clear();
removeSelf();
}
mHardwareAnimating = false;
}
private Paint getTempPaint() {
@@ -509,11 +522,14 @@ class RippleBackground {
}
/**
* Cancel all animations.
* Cancel all animations. The caller is responsible for removing
* the ripple from the list of animating ripples.
*/
public void cancel() {
mCanceled = true;
cancelSoftwareAnimations();
cancelHardwareAnimations(true);
mCanceled = false;
}
private void cancelSoftwareAnimations() {
@@ -544,13 +560,16 @@ class RippleBackground {
if (cancelPending && !mPendingAnimations.isEmpty()) {
mPendingAnimations.clear();
removeSelf();
}
mHardwareAnimating = false;
}
private void removeSelf() {
// The owner will invalidate itself.
mOwner.removeBackground(this);
if (!mCanceled) {
mOwner.removeBackground(this);
}
}
private void invalidateSelf() {

View File

@@ -140,8 +140,8 @@ public class RippleDrawable extends LayerDrawable {
* Lazily-created array of actively animating ripples. Inactive ripples are
* pruned during draw(). The locations of these will not change.
*/
private Ripple[] mAnimatingRipples;
private int mAnimatingRipplesCount = 0;
private Ripple[] mExitingRipples;
private int mExitingRipplesCount = 0;
/** Paint used to control appearance of ripples. */
private Paint mRipplePaint;
@@ -155,12 +155,6 @@ public class RippleDrawable extends LayerDrawable {
/** Whether bounds are being overridden. */
private boolean mOverrideBounds;
/**
* Whether hotspots are being cleared. Used to prevent re-entry by
* animation finish listeners.
*/
private boolean mClearingHotspots;
/**
* Constructor used for drawable inflation.
*/
@@ -209,19 +203,21 @@ public class RippleDrawable extends LayerDrawable {
mBackground.jump();
}
mClearingHotspots = true;
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mAnimatingRipples;
cancelExitingRipples();
invalidateSelf();
}
private void cancelExitingRipples() {
final int count = mExitingRipplesCount;
final Ripple[] ripples = mExitingRipples;
for (int i = 0; i < count; i++) {
ripples[i].jump();
ripples[i].cancel();
}
if (ripples != null) {
Arrays.fill(ripples, 0, count, null);
}
mAnimatingRipplesCount = 0;
mClearingHotspots = false;
invalidateSelf();
mExitingRipplesCount = 0;
}
@Override
@@ -287,9 +283,9 @@ public class RippleDrawable extends LayerDrawable {
if (mRippleActive != active) {
mRippleActive = active;
if (active) {
activateRipple();
tryRippleEnter();
} else {
removeRipple();
tryRippleExit();
}
}
}
@@ -298,9 +294,9 @@ public class RippleDrawable extends LayerDrawable {
if (mBackgroundActive != active) {
mBackgroundActive = active;
if (active) {
activateBackground();
tryBackgroundEnter();
} else {
removeBackground();
tryBackgroundExit();
}
}
}
@@ -327,11 +323,11 @@ public class RippleDrawable extends LayerDrawable {
// If we just became visible, ensure the background and ripple
// visibilities are consistent with their internal states.
if (mRippleActive) {
activateRipple();
tryRippleEnter();
}
if (mBackgroundActive) {
activateBackground();
tryBackgroundEnter();
}
}
@@ -491,7 +487,7 @@ public class RippleDrawable extends LayerDrawable {
/**
* Creates an active hotspot at the specified location.
*/
private void activateBackground() {
private void tryBackgroundEnter() {
if (mBackground == null) {
final float x;
final float y;
@@ -511,7 +507,7 @@ public class RippleDrawable extends LayerDrawable {
mBackground.enter();
}
private void removeBackground() {
private void tryBackgroundExit() {
if (mBackground != null) {
// Don't null out the background, we need it to draw!
mBackground.exit();
@@ -519,10 +515,11 @@ public class RippleDrawable extends LayerDrawable {
}
/**
* Creates an active hotspot at the specified location.
* Attempts to start an enter animation for the active hotspot. Fails if
* there are too many animating ripples.
*/
private void activateRipple() {
if (mAnimatingRipplesCount >= MAX_RIPPLES) {
private void tryRippleEnter() {
if (mExitingRipplesCount >= MAX_RIPPLES) {
// This should never happen unless the user is tapping like a maniac
// or there is a bug that's preventing ripples from being removed.
return;
@@ -545,29 +542,27 @@ public class RippleDrawable extends LayerDrawable {
final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
mRipple.setup(mState.mMaxRadius, color, mDensity);
mRipple.enter();
if (mAnimatingRipples == null) {
mAnimatingRipples = new Ripple[MAX_RIPPLES];
}
mAnimatingRipples[mAnimatingRipplesCount++] = mRipple;
}
@Override
public void invalidateSelf() {
// Don't invalidate when we're clearing hotspots. We'll handle that
// manually when we're done.
if (!mClearingHotspots) {
super.invalidateSelf();
}
}
private void removeRipple() {
/**
* Attempts to start an exit animation for the active hotspot. Fails if
* there is no active hotspot.
*/
private void tryRippleExit() {
if (mRipple != null) {
if (mExitingRipples == null) {
mExitingRipples = new Ripple[MAX_RIPPLES];
}
mExitingRipples[mExitingRipplesCount++] = mRipple;
mRipple.exit();
mRipple = null;
}
}
/**
* Cancels and removes the active ripple, all exiting ripples, and the
* background. Nothing will be drawn after this method is called.
*/
private void clearHotspots() {
if (mRipple != null) {
mRipple.cancel();
@@ -579,18 +574,7 @@ public class RippleDrawable extends LayerDrawable {
mBackground = null;
}
mClearingHotspots = true;
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mAnimatingRipples;
for (int i = 0; i < count; i++) {
ripples[i].cancel();
}
if (ripples != null) {
Arrays.fill(ripples, 0, count, null);
}
mAnimatingRipplesCount = 0;
mClearingHotspots = false;
cancelExitingRipples();
invalidateSelf();
}
@@ -612,8 +596,8 @@ public class RippleDrawable extends LayerDrawable {
* Notifies all the animating ripples that the hotspot bounds have changed.
*/
private void onHotspotBoundsChanged() {
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mAnimatingRipples;
final int count = mExitingRipplesCount;
final Ripple[] ripples = mExitingRipples;
for (int i = 0; i < count; i++) {
ripples[i].onHotspotBoundsChanged();
}
@@ -683,22 +667,21 @@ public class RippleDrawable extends LayerDrawable {
}
/**
* Removes a ripple from the animating ripple list.
* Removes a ripple from the exiting ripple list.
*
* @param ripple the ripple to remove
*/
void removeRipple(Ripple ripple) {
if (!mClearingHotspots) {
// Ripple ripple ripple ripple. Ripple ripple.
final Ripple[] ripples = mAnimatingRipples;
final int count = mAnimatingRipplesCount;
final int index = getRippleIndex(ripple);
if (index >= 0) {
System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
ripples[count - 1] = null;
mAnimatingRipplesCount--;
invalidateSelf();
}
// Ripple ripple ripple ripple. Ripple ripple.
final Ripple[] ripples = mExitingRipples;
final int count = mExitingRipplesCount;
final int index = getRippleIndex(ripple);
if (index >= 0) {
System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
ripples[count - 1] = null;
mExitingRipplesCount--;
invalidateSelf();
}
}
@@ -710,8 +693,8 @@ public class RippleDrawable extends LayerDrawable {
}
private int getRippleIndex(Ripple ripple) {
final Ripple[] ripples = mAnimatingRipples;
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mExitingRipples;
final int count = mExitingRipplesCount;
for (int i = 0; i < count; i++) {
if (ripples[i] == ripple) {
return i;
@@ -727,7 +710,7 @@ public class RippleDrawable extends LayerDrawable {
// We don't need a layer if we don't expect to draw any ripples, we have
// an explicit mask, or if the non-mask content is all opaque.
boolean needsLayer = false;
if ((mAnimatingRipplesCount > 0 || mBackground != null) && mMask == null) {
if ((mExitingRipplesCount > 0 || mBackground != null) && mMask == null) {
for (int i = 0; i < count; i++) {
if (array[i].mId != R.id.mask
&& array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
@@ -831,10 +814,17 @@ public class RippleDrawable extends LayerDrawable {
int restoreTranslate = -1;
// Draw ripples and update the animating ripples array.
final int count = mAnimatingRipplesCount;
final Ripple[] ripples = mAnimatingRipples;
for (int i = 0; i < count; i++) {
final Ripple ripple = ripples[i];
final int count = mExitingRipplesCount;
final Ripple[] ripples = mExitingRipples;
for (int i = 0; i <= count; i++) {
final Ripple ripple;
if (i < count) {
ripple = ripples[i];
} else if (mRipple != null) {
ripple = mRipple;
} else {
continue;
}
// If we're masking the ripple layer, make sure we have a layer
// first. This will merge SRC_OVER (directly) onto the canvas.
@@ -898,8 +888,9 @@ public class RippleDrawable extends LayerDrawable {
final int cX = (int) mHotspotBounds.exactCenterX();
final int cY = (int) mHotspotBounds.exactCenterY();
final Rect rippleBounds = mTempRect;
final Ripple[] activeRipples = mAnimatingRipples;
final int N = mAnimatingRipplesCount;
final Ripple[] activeRipples = mExitingRipples;
final int N = mExitingRipplesCount;
for (int i = 0; i < N; i++) {
activeRipples[i].getBounds(rippleBounds);
rippleBounds.offset(cX, cY);