Loading core/java/android/widget/AbsListView.java +24 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. Loading Loading @@ -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; } Loading core/java/android/widget/ListPopupWindow.java +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading core/java/android/widget/ListView.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()) { Loading graphics/java/android/graphics/drawable/Ripple.java +79 −63 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() { Loading @@ -299,19 +319,17 @@ 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 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); Loading @@ -320,26 +338,36 @@ class Ripple { 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; } /** Loading @@ -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) { } }; } graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +10 −3 Original line number Diff line number Diff line Loading @@ -380,11 +380,18 @@ public class TouchFeedbackDrawable extends LayerDrawable { @Override public void clearHotspots() { if (mRipples == null) { return; if (mRipples != null) { mRipples.clear(); } mRipples.clear(); final int count = mAnimatingRipplesCount; final Ripple[] ripples = mAnimatingRipples; for (int i = 0; i < count; i++) { ripples[i].cancel(); ripples[i] = null; } mAnimatingRipplesCount = 0; invalidateSelf(); } Loading Loading
core/java/android/widget/AbsListView.java +24 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. Loading Loading @@ -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; } Loading
core/java/android/widget/ListPopupWindow.java +1 −1 Original line number Diff line number Diff line Loading @@ -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. Loading
core/java/android/widget/ListView.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()) { Loading
graphics/java/android/graphics/drawable/Ripple.java +79 −63 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() { Loading @@ -299,19 +319,17 @@ 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 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); Loading @@ -320,26 +338,36 @@ class Ripple { 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; } /** Loading @@ -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) { } }; }
graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +10 −3 Original line number Diff line number Diff line Loading @@ -380,11 +380,18 @@ public class TouchFeedbackDrawable extends LayerDrawable { @Override public void clearHotspots() { if (mRipples == null) { return; if (mRipples != null) { mRipples.clear(); } mRipples.clear(); final int count = mAnimatingRipplesCount; final Ripple[] ripples = mAnimatingRipples; for (int i = 0; i < count; i++) { ripples[i].cancel(); ripples[i] = null; } mAnimatingRipplesCount = 0; invalidateSelf(); } Loading