diff options
-rw-r--r-- | core/java/android/widget/AbsListView.java | 24 | ||||
-rw-r--r-- | core/java/android/widget/ListPopupWindow.java | 2 | ||||
-rw-r--r-- | core/java/android/widget/ListView.java | 2 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/Ripple.java | 142 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java | 13 |
5 files changed, 115 insertions, 68 deletions
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index becda67..0966be3 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -110,6 +110,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @see #setTranscriptMode(int) */ public static final int TRANSCRIPT_MODE_DISABLED = 0; + /** * The list will automatically scroll to the bottom when a data set change * notification is received and only if the last item is already visible @@ -118,6 +119,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @see #setTranscriptMode(int) */ public static final int TRANSCRIPT_MODE_NORMAL = 1; + /** * The list will automatically scroll to the bottom, no matter what items * are currently visible. @@ -2489,8 +2491,30 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + /** + * Positions the selector in a way that mimics keyboard focus. If the + * selector drawable supports hotspots, this manages the focus hotspot. + */ + void positionSelectorLikeFocus(int position, View sel) { + positionSelector(position, sel); + + final Drawable selector = mSelector; + if (selector != null && selector.supportsHotspots() && position != INVALID_POSITION) { + final Rect bounds = mSelectorRect; + final float x = bounds.exactCenterX(); + final float y = bounds.exactCenterY(); + selector.setHotspot(R.attr.state_focused, x, y); + } + } + void positionSelector(int position, View sel) { if (position != INVALID_POSITION) { + if (mSelectorPosition != position) { + final Drawable selector = mSelector; + if (selector != null && selector.supportsHotspots()) { + selector.clearHotspots(); + } + } mSelectorPosition = position; } diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index b47177a..10ec105 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -1565,7 +1565,7 @@ public class ListPopupWindow { // Ensure that keyboard focus starts from the last touched position. setSelectedPositionInt(position); - positionSelector(position, child); + positionSelectorLikeFocus(position, child); // Refresh the drawable state to reflect the new pressed state, // which will also update the selector state. diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 5de67c8..eeb8015 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -2564,7 +2564,7 @@ public class ListView extends AbsListView { if (needToRedraw) { if (selectedView != null) { - positionSelector(selectedPos, selectedView); + positionSelectorLikeFocus(selectedPos, selectedView); mSelectedTop = selectedView.getTop(); } if (!awakenScrollBars()) { diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index 207834a..3446000 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -18,6 +18,7 @@ package android.graphics.drawable; import android.animation.Animator; import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.graphics.Canvas; @@ -85,8 +86,9 @@ class Ripple { /** Configured maximum ripple radius. */ private final int mMaxInsideRadius; - private ObjectAnimator mEnter; - private ObjectAnimator mExit; + private ObjectAnimator mOuter; + private ObjectAnimator mInner; + private ObjectAnimator mAlpha; /** Maximum ripple radius. */ private int mMaxRadius; @@ -267,28 +269,46 @@ class Ripple { public void exit() { mExitFinished = false; - final ObjectAnimator exit = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius); - exit.setAutoCancel(true); - exit.setDuration(EXIT_DURATION); - exit.setInterpolator(INTERPOLATOR); - exit.addListener(mAnimationListener); + final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius); + inner.setAutoCancel(true); + inner.setDuration(EXIT_DURATION); + inner.setInterpolator(INTERPOLATOR); + inner.addListener(mAnimationListener); - if (mEnter != null && mEnter.isStarted()) { + if (mOuter != null && mOuter.isStarted()) { // If we haven't been running the enter animation for long enough, // delay the exit animator. - final int elapsed = (int) (mEnter.getAnimatedFraction() * mEnter.getDuration()); + final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration()); final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed); - exit.setStartDelay(delay); + inner.setStartDelay(delay); } - exit.start(); + inner.start(); - final ObjectAnimator fade = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0); - fade.setAutoCancel(true); - fade.setDuration(EXIT_DURATION); - fade.start(); + final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0); + alpha.setAutoCancel(true); + alpha.setDuration(EXIT_DURATION); + alpha.start(); - mExit = exit; + mInner = inner; + mAlpha = alpha; + } + + /** + * Cancel all animations. + */ + public void cancel() { + if (mInner != null) { + mInner.end(); + } + + if (mOuter != null) { + mOuter.cancel(); + } + + if (mAlpha != null) { + mAlpha.end(); + } } private void invalidateSelf() { @@ -299,47 +319,55 @@ class Ripple { * Starts the enter animation. */ private void enter() { - final ObjectAnimator enter = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius); - enter.setAutoCancel(true); - enter.setDuration(ENTER_DURATION); - enter.setInterpolator(INTERPOLATOR); - enter.start(); - - final ObjectAnimator fade = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1); - fade.setAutoCancel(true); - fade.setDuration(FADE_DURATION); - fade.start(); - - // TODO: Starting with a delay will still cancel the fade in. - if (false && mPulseEnabled) { - final ObjectAnimator pulse = ObjectAnimator.ofFloat( - this, "alphaMultiplier", 1, PULSE_MIN_ALPHA); - pulse.setAutoCancel(true); - pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL); - pulse.setRepeatCount(ObjectAnimator.INFINITE); - pulse.setRepeatMode(ObjectAnimator.REVERSE); - pulse.setStartDelay(PULSE_DELAY); - pulse.start(); + final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius); + outer.setAutoCancel(true); + outer.setDuration(ENTER_DURATION); + outer.setInterpolator(INTERPOLATOR); + outer.start(); + + final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1); + if (mPulseEnabled) { + alpha.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + final ObjectAnimator pulse = ObjectAnimator.ofFloat( + this, "alphaMultiplier", 1, PULSE_MIN_ALPHA); + pulse.setAutoCancel(true); + pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL); + pulse.setRepeatCount(ObjectAnimator.INFINITE); + pulse.setRepeatMode(ObjectAnimator.REVERSE); + pulse.setStartDelay(PULSE_DELAY); + pulse.start(); + + mAlpha = pulse; + } + }); } + alpha.setAutoCancel(true); + alpha.setDuration(FADE_DURATION); + alpha.start(); - mEnter = enter; + mOuter = outer; + mAlpha = alpha; } /** * Starts the outside transition animation. */ private void outside() { - final float targetRadius = mMaxOutsideRadius; - final ObjectAnimator outside = ObjectAnimator.ofFloat(this, "outerRadius", targetRadius); - outside.setAutoCancel(true); - outside.setDuration(OUTSIDE_DURATION); - outside.setInterpolator(INTERPOLATOR); - outside.start(); - - final ObjectAnimator fade = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1); - fade.setAutoCancel(true); - fade.setDuration(FADE_DURATION); - fade.start(); + final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius); + outer.setAutoCancel(true); + outer.setDuration(OUTSIDE_DURATION); + outer.setInterpolator(INTERPOLATOR); + outer.start(); + + final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1); + alpha.setAutoCancel(true); + alpha.setDuration(FADE_DURATION); + alpha.start(); + + mOuter = outer; + mAlpha = alpha; } /** @@ -358,27 +386,15 @@ class Ripple { } } - private final AnimatorListener mAnimationListener = new AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - + private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (animation == mExit) { + if (animation == mInner) { mExitFinished = true; mOuterRadius = 0; mInnerRadius = 0; mAlphaMultiplier = 1; } } - - @Override - public void onAnimationCancel(Animator animation) { - } }; } diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 9000e5a..0097183 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -380,11 +380,18 @@ public class TouchFeedbackDrawable extends LayerDrawable { @Override public void clearHotspots() { - if (mRipples == null) { - return; + if (mRipples != null) { + mRipples.clear(); + } + + final int count = mAnimatingRipplesCount; + final Ripple[] ripples = mAnimatingRipples; + for (int i = 0; i < count; i++) { + ripples[i].cancel(); + ripples[i] = null; } - mRipples.clear(); + mAnimatingRipplesCount = 0; invalidateSelf(); } |