summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2014-08-28 20:00:38 -0700
committerAlan Viverette <alanv@google.com>2014-08-29 19:54:59 +0000
commitfdbb98e56d4668c7bfa8de59c3c438c0cb69a535 (patch)
tree3dead24dddde879054028fbb82de383552e56e72 /graphics
parent6a6a8f00946f963191612f64238bd706c2188dd8 (diff)
downloadframeworks_base-fdbb98e56d4668c7bfa8de59c3c438c0cb69a535.zip
frameworks_base-fdbb98e56d4668c7bfa8de59c3c438c0cb69a535.tar.gz
frameworks_base-fdbb98e56d4668c7bfa8de59c3c438c0cb69a535.tar.bz2
Fix disappearing ripple background, treat active ripple separately
There is only a single background, and it did not correctly handle enter() being called while exit() was busy animating. We now cancel all animations when starting an enter or exit. Also separates the active ripple from the list of animating (exiting) ripples. BUG: 17042060 BUG: 17281011 Change-Id: I4d4e33560867c7c71c1bdb72b17d52d6fbd86f68
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/drawable/Ripple.java28
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java27
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java145
3 files changed, 115 insertions, 85 deletions
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 063ac09..cd919a6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -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() {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 49862bc..bcf6afe 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -106,6 +106,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.
*/
@@ -283,6 +286,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_VELOCITY_MIN);
@@ -320,7 +325,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.
@@ -403,9 +408,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() {
@@ -436,6 +447,8 @@ class RippleBackground {
mPendingAnimations.clear();
removeSelf();
}
+
+ mHardwareAnimating = false;
}
private Paint getTempPaint() {
@@ -508,11 +521,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() {
@@ -543,13 +559,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() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 7402bdb..b90fd81 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -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;
@@ -156,12 +156,6 @@ public class RippleDrawable extends LayerDrawable {
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.
*/
RippleDrawable() {
@@ -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);