Loading api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -34886,9 +34886,11 @@ package android.widget { ctor public EdgeEffect(android.content.Context); method public boolean draw(android.graphics.Canvas); method public void finish(); method public int getMaxHeight(); method public boolean isFinished(); method public void onAbsorb(int); method public void onPull(float); method public void onPull(float, float); method public void onRelease(); method public void setSize(int, int); } core/java/android/widget/AbsListView.java +41 −30 Original line number Diff line number Diff line Loading @@ -3267,7 +3267,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } private boolean startScrollIfNeeded(int y, MotionEvent vtev) { private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) { // Check if we have moved far enough that it looks more like a // scroll than a tap final int deltaY = y - mMotionY; Loading Loading @@ -3296,14 +3296,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } scrollIfNeeded(y, vtev); scrollIfNeeded(x, y, vtev); return true; } return false; } private void scrollIfNeeded(int y, MotionEvent vtev) { private void scrollIfNeeded(int x, int y, MotionEvent vtev) { int rawDeltaY = y - mMotionY; if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) { rawDeltaY -= mScrollConsumed[1]; Loading Loading @@ -3384,33 +3384,39 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te vtev.offsetLocation(0, mScrollOffset[1]); } } else { overScrollBy(0, overscroll, 0, mScrollY, 0, 0, 0, mOverscrollDistance, true); if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) { // Don't allow overfling if we're at the edge. if (mVelocityTracker != null) { final boolean atOverscrollEdge = overScrollBy(0, overscroll, 0, mScrollY, 0, 0, 0, mOverscrollDistance, true); if (atOverscrollEdge && mVelocityTracker != null) { // Don't allow overfling if we're at the edge mVelocityTracker.clear(); } } final int overscrollMode = getOverScrollMode(); if (overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { if (!atOverscrollEdge) { mDirection = 0; // Reset when entering overscroll. mTouchMode = TOUCH_MODE_OVERSCROLL; if (deltaY > 0) { mEdgeGlowTop.onPull((float) overscroll / getHeight()); } if (incrementalDeltaY > 0) { mEdgeGlowTop.onPull((float) overscroll / getHeight(), (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } invalidate(mEdgeGlowTop.getBounds(false)); } else if (deltaY < 0) { mEdgeGlowBottom.onPull((float) overscroll / getHeight()); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } else if (incrementalDeltaY < 0) { mEdgeGlowBottom.onPull((float) overscroll / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } } } Loading Loading @@ -3445,17 +3451,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { if (rawDeltaY > 0) { mEdgeGlowTop.onPull((float) overScrollDistance / getHeight()); mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(), (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } invalidate(mEdgeGlowTop.getBounds(false)); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } else if (rawDeltaY < 0) { mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight()); mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } } } Loading Loading @@ -3703,7 +3714,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te case TOUCH_MODE_DONE_WAITING: // Check if we have moved far enough that it looks more like a // scroll than a tap. If so, we'll enter scrolling mode. if (startScrollIfNeeded(y, vtev)) { if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) { break; } // Otherwise, check containment within list bounds. If we're Loading @@ -3723,7 +3734,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; case TOUCH_MODE_SCROLL: case TOUCH_MODE_OVERSCROLL: scrollIfNeeded(y, vtev); scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev); break; } } Loading Loading @@ -4022,8 +4033,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.translate(leftPadding, edgeY); mEdgeGlowTop.setSize(width, getHeight()); if (mEdgeGlowTop.draw(canvas)) { mEdgeGlowTop.setPosition(leftPadding, edgeY); invalidate(mEdgeGlowTop.getBounds(false)); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } canvas.restoreToCount(restoreCount); } Loading @@ -4040,9 +4051,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { // Account for the rotation mEdgeGlowBottom.setPosition(edgeX + width, edgeY); invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } canvas.restoreToCount(restoreCount); } Loading Loading @@ -4161,7 +4172,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int y = (int) ev.getY(pointerIndex); initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); if (startScrollIfNeeded(y, null)) { if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) { return true; } break; Loading core/java/android/widget/EdgeEffect.java +85 −136 Original line number Diff line number Diff line Loading @@ -16,7 +16,14 @@ package android.widget; import android.content.res.TypedArray; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Xfermode; import android.util.Log; import com.android.internal.R; import android.content.Context; Loading Loading @@ -59,12 +66,10 @@ public class EdgeEffect { private static final int PULL_DECAY_TIME = 1000; private static final float MAX_ALPHA = 1.f; private static final float HELD_EDGE_SCALE_Y = 0.5f; private static final float MAX_GLOW_HEIGHT = 4.f; private static final float MAX_GLOW_HEIGHT = 1.5f; private static final float PULL_GLOW_BEGIN = 1.f; private static final float PULL_EDGE_BEGIN = 0.6f; private static final float PULL_GLOW_BEGIN = 0.f; // Minimum velocity that will be absorbed private static final int MIN_VELOCITY = 100; Loading @@ -73,24 +78,11 @@ public class EdgeEffect { private static final float EPSILON = 0.001f; private final Drawable mEdge; private final Drawable mGlow; private int mWidth; private int mHeight; private int mX; private int mY; private static final int MIN_WIDTH = 300; private final int mMinWidth; private float mEdgeAlpha; private float mEdgeScaleY; private static final float SIN_45 = (float) Math.sin(Math.PI / 4); private float mGlowAlpha; private float mGlowScaleY; private float mEdgeAlphaStart; private float mEdgeAlphaFinish; private float mEdgeScaleYStart; private float mEdgeScaleYFinish; private float mGlowAlphaStart; private float mGlowAlphaFinish; private float mGlowScaleYStart; Loading @@ -107,16 +99,11 @@ public class EdgeEffect { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; // How much dragging should effect the height of the edge image. // Number determined by user testing. private static final int PULL_DISTANCE_EDGE_FACTOR = 7; // How much dragging should effect the height of the glow image. // Number determined by user testing. private static final int PULL_DISTANCE_GLOW_FACTOR = 7; private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; private static final int VELOCITY_EDGE_FACTOR = 8; private static final int VELOCITY_GLOW_FACTOR = 12; private int mState = STATE_IDLE; Loading @@ -124,30 +111,26 @@ public class EdgeEffect { private float mPullDistance; private final Rect mBounds = new Rect(); private final int mEdgeHeight; private final int mGlowHeight; private final int mGlowWidth; private final int mMaxEffectHeight; private final RectF mArcRect = new RectF(); private final Paint mPaint = new Paint(); private float mRadius; private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; /** * Construct a new EdgeEffect with a theme appropriate for the provided context. * @param context Context used to provide theming and resource information for the EdgeEffect */ public EdgeEffect(Context context) { final Resources res = context.getResources(); mEdge = context.getDrawable(R.drawable.overscroll_edge); mGlow = context.getDrawable(R.drawable.overscroll_glow); mEdgeHeight = mEdge.getIntrinsicHeight(); mGlowHeight = mGlow.getIntrinsicHeight(); mGlowWidth = mGlow.getIntrinsicWidth(); mMaxEffectHeight = (int) (Math.min( mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f, mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f); mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f); mPaint.setAntiAlias(true); final TypedArray a = context.obtainStyledAttributes( com.android.internal.R.styleable.EdgeEffect); final int themeColor = a.getColor( com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666); a.recycle(); mPaint.setColor((themeColor & 0xffffff) | 0x66000000); mPaint.setStyle(Paint.Style.FILL); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); mInterpolator = new DecelerateInterpolator(); } Loading @@ -158,20 +141,12 @@ public class EdgeEffect { * @param height Effect height in pixels */ public void setSize(int width, int height) { mWidth = width; mHeight = height; } final float r = width * 0.5f / SIN_45; final float y = SIN_45 * r; final float h = r - y; mRadius = r; /** * Set the position of this edge effect in pixels. This position is * only used by {@link #getBounds(boolean)}. * * @param x The position of the edge effect on the X axis * @param y The position of the edge effect on the Y axis */ void setPosition(int x, int y) { mX = x; mY = y; mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); } /** Loading Loading @@ -199,17 +174,38 @@ public class EdgeEffect { * The host view should always {@link android.view.View#invalidate()} after this * and draw the results accordingly. * * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement * of the pull point is known.</p> * * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to * 1.f (full length of the view) or negative values to express change * back toward the edge reached to initiate the effect. */ public void onPull(float deltaDistance) { onPull(deltaDistance, 0.5f); } /** * A view should call this when content is pulled away from an edge by the user. * This will update the state of the current visual effect and its associated animation. * The host view should always {@link android.view.View#invalidate()} after this * and draw the results accordingly. * * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to * 1.f (full length of the view) or negative values to express change * back toward the edge reached to initiate the effect. * @param displacement The displacement from the starting side of the effect of the point * initiating the pull. In the case of touch this is the finger position. * Values may be from 0-1. */ public void onPull(float deltaDistance, float displacement) { final long now = AnimationUtils.currentAnimationTimeMillis(); mTargetDisplacement = displacement; if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { return; } if (mState != STATE_PULL) { mGlowScaleY = PULL_GLOW_BEGIN; mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY); } mState = STATE_PULL; Loading @@ -217,11 +213,6 @@ public class EdgeEffect { mDuration = PULL_TIME; mPullDistance += deltaDistance; float distance = Math.abs(mPullDistance); mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); mEdgeScaleY = mEdgeScaleYStart = Math.max( HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, mGlowAlpha + Loading @@ -239,8 +230,6 @@ public class EdgeEffect { mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); mEdgeAlphaFinish = mEdgeAlpha; mEdgeScaleYFinish = mEdgeScaleY; mGlowAlphaFinish = mGlowAlpha; mGlowScaleYFinish = mGlowScaleY; } Loading @@ -259,13 +248,9 @@ public class EdgeEffect { } mState = STATE_RECEDE; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; Loading @@ -290,30 +275,21 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = 0.15f + (velocity * 0.02f); // The edge should always be at least partially visible, regardless // of velocity. mEdgeAlphaStart = 0.f; mEdgeScaleY = mEdgeScaleYStart = 0.f; // The glow depends more on the velocity, and therefore starts out // nearly invisible. mGlowAlphaStart = 0.3f; mGlowScaleYStart = 0.f; mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); // Factor the velocity by 8. Testing on device shows this works best to // reflect the strength of the user's scrolling. mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); // Edge should never get larger than the size of its asset. mEdgeScaleYFinish = Math.max( HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); // Growth for the size of the glow should be quadratic to properly // respond // to a user's scrolling speed. The faster the scrolling speed, the more // intense the effect should be for both the size and the saturation. mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); // Alpha should change for the glow as well as size. mGlowAlphaFinish = Math.max( mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); mTargetDisplacement = 0.5f; } Loading @@ -330,52 +306,42 @@ public class EdgeEffect { public boolean draw(Canvas canvas) { update(); mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); int glowBottom = (int) Math.min( mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f, mGlowHeight * MAX_GLOW_HEIGHT); if (mWidth < mMinWidth) { // Center the glow and clip it. int glowLeft = (mWidth - mMinWidth)/2; mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); } else { // Stretch the glow to fit. mGlow.setBounds(0, 0, mWidth, glowBottom); } mGlow.draw(canvas); final int count = canvas.save(); mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); final float y = mBounds.height(); final float centerY = y - mRadius; final float centerX = mBounds.centerX(); mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius); canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0); int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY); if (mWidth < mMinWidth) { // Center the edge and clip it. int edgeLeft = (mWidth - mMinWidth)/2; mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); } else { // Stretch the edge to fit. mEdge.setBounds(0, 0, mWidth, edgeBottom); final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; float translateX = mBounds.width() * displacement; float translateY = 0; if (mGlowScaleY > 1.f) { translateY = (mGlowScaleY - 1.f) * mBounds.height(); } mEdge.draw(canvas); if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) { canvas.clipRect(Float.MIN_VALUE, mBounds.top, Float.MAX_VALUE, Float.MAX_VALUE); canvas.translate(translateX, translateY); canvas.drawArc(mArcRect, 0, 180, true, mPaint); canvas.restoreToCount(count); boolean oneLastFrame = false; if (mState == STATE_RECEDE && mGlowScaleY == 0) { mState = STATE_IDLE; oneLastFrame = true; } return mState != STATE_IDLE; return mState != STATE_IDLE || oneLastFrame; } /** * Returns the bounds of the edge effect. * * @hide * Return the maximum height that the edge effect will be drawn at given the original * {@link #setSize(int, int) input size}. * @return The maximum height of the edge effect */ public Rect getBounds(boolean reverse) { mBounds.set(0, 0, mWidth, mMaxEffectHeight); mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0)); return mBounds; public int getMaxHeight() { return (int) (mBounds.height() * MAX_GLOW_HEIGHT + 0.5f); } private void update() { Loading @@ -384,10 +350,9 @@ public class EdgeEffect { final float interp = mInterpolator.getInterpolation(t); mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; mDisplacement = (mDisplacement + mTargetDisplacement) / 2; if (t >= 1.f - EPSILON) { switch (mState) { Loading @@ -396,14 +361,10 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = RECEDE_TIME; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; // After absorb, the glow and edge should fade to nothing. mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; // After absorb, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; Loading @@ -412,26 +373,14 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = PULL_DECAY_TIME; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; // After pull, the glow and edge should fade to nothing. mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; // After pull, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: // When receding, we want edge to decrease more slowly // than the glow. float factor = mGlowScaleYFinish != 0 ? 1 / (mGlowScaleYFinish * mGlowScaleYFinish) : Float.MAX_VALUE; mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp * factor; mState = STATE_RECEDE; break; case STATE_RECEDE: Loading core/java/android/widget/HorizontalScrollView.java +4 −2 Original line number Diff line number Diff line Loading @@ -616,12 +616,14 @@ public class HorizontalScrollView extends FrameLayout { if (canOverscroll) { final int pulledToX = oldX + deltaX; if (pulledToX < 0) { mEdgeGlowLeft.onPull((float) deltaX / getWidth()); mEdgeGlowLeft.onPull((float) deltaX / getWidth(), 1.f - ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowRight.isFinished()) { mEdgeGlowRight.onRelease(); } } else if (pulledToX > range) { mEdgeGlowRight.onPull((float) deltaX / getWidth()); mEdgeGlowRight.onPull((float) deltaX / getWidth(), ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowLeft.isFinished()) { mEdgeGlowLeft.onRelease(); } Loading core/java/android/widget/ScrollView.java +4 −2 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -34886,9 +34886,11 @@ package android.widget { ctor public EdgeEffect(android.content.Context); method public boolean draw(android.graphics.Canvas); method public void finish(); method public int getMaxHeight(); method public boolean isFinished(); method public void onAbsorb(int); method public void onPull(float); method public void onPull(float, float); method public void onRelease(); method public void setSize(int, int); }
core/java/android/widget/AbsListView.java +41 −30 Original line number Diff line number Diff line Loading @@ -3267,7 +3267,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } private boolean startScrollIfNeeded(int y, MotionEvent vtev) { private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) { // Check if we have moved far enough that it looks more like a // scroll than a tap final int deltaY = y - mMotionY; Loading Loading @@ -3296,14 +3296,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (parent != null) { parent.requestDisallowInterceptTouchEvent(true); } scrollIfNeeded(y, vtev); scrollIfNeeded(x, y, vtev); return true; } return false; } private void scrollIfNeeded(int y, MotionEvent vtev) { private void scrollIfNeeded(int x, int y, MotionEvent vtev) { int rawDeltaY = y - mMotionY; if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) { rawDeltaY -= mScrollConsumed[1]; Loading Loading @@ -3384,33 +3384,39 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te vtev.offsetLocation(0, mScrollOffset[1]); } } else { overScrollBy(0, overscroll, 0, mScrollY, 0, 0, 0, mOverscrollDistance, true); if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) { // Don't allow overfling if we're at the edge. if (mVelocityTracker != null) { final boolean atOverscrollEdge = overScrollBy(0, overscroll, 0, mScrollY, 0, 0, 0, mOverscrollDistance, true); if (atOverscrollEdge && mVelocityTracker != null) { // Don't allow overfling if we're at the edge mVelocityTracker.clear(); } } final int overscrollMode = getOverScrollMode(); if (overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { if (!atOverscrollEdge) { mDirection = 0; // Reset when entering overscroll. mTouchMode = TOUCH_MODE_OVERSCROLL; if (deltaY > 0) { mEdgeGlowTop.onPull((float) overscroll / getHeight()); } if (incrementalDeltaY > 0) { mEdgeGlowTop.onPull((float) overscroll / getHeight(), (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } invalidate(mEdgeGlowTop.getBounds(false)); } else if (deltaY < 0) { mEdgeGlowBottom.onPull((float) overscroll / getHeight()); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } else if (incrementalDeltaY < 0) { mEdgeGlowBottom.onPull((float) overscroll / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } } } Loading Loading @@ -3445,17 +3451,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) { if (rawDeltaY > 0) { mEdgeGlowTop.onPull((float) overScrollDistance / getHeight()); mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(), (float) x / getWidth()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } invalidate(mEdgeGlowTop.getBounds(false)); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } else if (rawDeltaY < 0) { mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight()); mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } } } Loading Loading @@ -3703,7 +3714,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te case TOUCH_MODE_DONE_WAITING: // Check if we have moved far enough that it looks more like a // scroll than a tap. If so, we'll enter scrolling mode. if (startScrollIfNeeded(y, vtev)) { if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) { break; } // Otherwise, check containment within list bounds. If we're Loading @@ -3723,7 +3734,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; case TOUCH_MODE_SCROLL: case TOUCH_MODE_OVERSCROLL: scrollIfNeeded(y, vtev); scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev); break; } } Loading Loading @@ -4022,8 +4033,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.translate(leftPadding, edgeY); mEdgeGlowTop.setSize(width, getHeight()); if (mEdgeGlowTop.draw(canvas)) { mEdgeGlowTop.setPosition(leftPadding, edgeY); invalidate(mEdgeGlowTop.getBounds(false)); invalidate(0, 0, getWidth(), mEdgeGlowTop.getMaxHeight() + getPaddingTop()); } canvas.restoreToCount(restoreCount); } Loading @@ -4040,9 +4051,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { // Account for the rotation mEdgeGlowBottom.setPosition(edgeX + width, edgeY); invalidate(mEdgeGlowBottom.getBounds(true)); invalidate(0, getHeight() - getPaddingBottom() - mEdgeGlowBottom.getMaxHeight(), getWidth(), getHeight()); } canvas.restoreToCount(restoreCount); } Loading Loading @@ -4161,7 +4172,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int y = (int) ev.getY(pointerIndex); initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); if (startScrollIfNeeded(y, null)) { if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) { return true; } break; Loading
core/java/android/widget/EdgeEffect.java +85 −136 Original line number Diff line number Diff line Loading @@ -16,7 +16,14 @@ package android.widget; import android.content.res.TypedArray; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Xfermode; import android.util.Log; import com.android.internal.R; import android.content.Context; Loading Loading @@ -59,12 +66,10 @@ public class EdgeEffect { private static final int PULL_DECAY_TIME = 1000; private static final float MAX_ALPHA = 1.f; private static final float HELD_EDGE_SCALE_Y = 0.5f; private static final float MAX_GLOW_HEIGHT = 4.f; private static final float MAX_GLOW_HEIGHT = 1.5f; private static final float PULL_GLOW_BEGIN = 1.f; private static final float PULL_EDGE_BEGIN = 0.6f; private static final float PULL_GLOW_BEGIN = 0.f; // Minimum velocity that will be absorbed private static final int MIN_VELOCITY = 100; Loading @@ -73,24 +78,11 @@ public class EdgeEffect { private static final float EPSILON = 0.001f; private final Drawable mEdge; private final Drawable mGlow; private int mWidth; private int mHeight; private int mX; private int mY; private static final int MIN_WIDTH = 300; private final int mMinWidth; private float mEdgeAlpha; private float mEdgeScaleY; private static final float SIN_45 = (float) Math.sin(Math.PI / 4); private float mGlowAlpha; private float mGlowScaleY; private float mEdgeAlphaStart; private float mEdgeAlphaFinish; private float mEdgeScaleYStart; private float mEdgeScaleYFinish; private float mGlowAlphaStart; private float mGlowAlphaFinish; private float mGlowScaleYStart; Loading @@ -107,16 +99,11 @@ public class EdgeEffect { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; // How much dragging should effect the height of the edge image. // Number determined by user testing. private static final int PULL_DISTANCE_EDGE_FACTOR = 7; // How much dragging should effect the height of the glow image. // Number determined by user testing. private static final int PULL_DISTANCE_GLOW_FACTOR = 7; private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; private static final int VELOCITY_EDGE_FACTOR = 8; private static final int VELOCITY_GLOW_FACTOR = 12; private int mState = STATE_IDLE; Loading @@ -124,30 +111,26 @@ public class EdgeEffect { private float mPullDistance; private final Rect mBounds = new Rect(); private final int mEdgeHeight; private final int mGlowHeight; private final int mGlowWidth; private final int mMaxEffectHeight; private final RectF mArcRect = new RectF(); private final Paint mPaint = new Paint(); private float mRadius; private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; /** * Construct a new EdgeEffect with a theme appropriate for the provided context. * @param context Context used to provide theming and resource information for the EdgeEffect */ public EdgeEffect(Context context) { final Resources res = context.getResources(); mEdge = context.getDrawable(R.drawable.overscroll_edge); mGlow = context.getDrawable(R.drawable.overscroll_glow); mEdgeHeight = mEdge.getIntrinsicHeight(); mGlowHeight = mGlow.getIntrinsicHeight(); mGlowWidth = mGlow.getIntrinsicWidth(); mMaxEffectHeight = (int) (Math.min( mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f, mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f); mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f); mPaint.setAntiAlias(true); final TypedArray a = context.obtainStyledAttributes( com.android.internal.R.styleable.EdgeEffect); final int themeColor = a.getColor( com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666); a.recycle(); mPaint.setColor((themeColor & 0xffffff) | 0x66000000); mPaint.setStyle(Paint.Style.FILL); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); mInterpolator = new DecelerateInterpolator(); } Loading @@ -158,20 +141,12 @@ public class EdgeEffect { * @param height Effect height in pixels */ public void setSize(int width, int height) { mWidth = width; mHeight = height; } final float r = width * 0.5f / SIN_45; final float y = SIN_45 * r; final float h = r - y; mRadius = r; /** * Set the position of this edge effect in pixels. This position is * only used by {@link #getBounds(boolean)}. * * @param x The position of the edge effect on the X axis * @param y The position of the edge effect on the Y axis */ void setPosition(int x, int y) { mX = x; mY = y; mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); } /** Loading Loading @@ -199,17 +174,38 @@ public class EdgeEffect { * The host view should always {@link android.view.View#invalidate()} after this * and draw the results accordingly. * * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement * of the pull point is known.</p> * * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to * 1.f (full length of the view) or negative values to express change * back toward the edge reached to initiate the effect. */ public void onPull(float deltaDistance) { onPull(deltaDistance, 0.5f); } /** * A view should call this when content is pulled away from an edge by the user. * This will update the state of the current visual effect and its associated animation. * The host view should always {@link android.view.View#invalidate()} after this * and draw the results accordingly. * * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to * 1.f (full length of the view) or negative values to express change * back toward the edge reached to initiate the effect. * @param displacement The displacement from the starting side of the effect of the point * initiating the pull. In the case of touch this is the finger position. * Values may be from 0-1. */ public void onPull(float deltaDistance, float displacement) { final long now = AnimationUtils.currentAnimationTimeMillis(); mTargetDisplacement = displacement; if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { return; } if (mState != STATE_PULL) { mGlowScaleY = PULL_GLOW_BEGIN; mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY); } mState = STATE_PULL; Loading @@ -217,11 +213,6 @@ public class EdgeEffect { mDuration = PULL_TIME; mPullDistance += deltaDistance; float distance = Math.abs(mPullDistance); mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); mEdgeScaleY = mEdgeScaleYStart = Math.max( HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, mGlowAlpha + Loading @@ -239,8 +230,6 @@ public class EdgeEffect { mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); mEdgeAlphaFinish = mEdgeAlpha; mEdgeScaleYFinish = mEdgeScaleY; mGlowAlphaFinish = mGlowAlpha; mGlowScaleYFinish = mGlowScaleY; } Loading @@ -259,13 +248,9 @@ public class EdgeEffect { } mState = STATE_RECEDE; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; Loading @@ -290,30 +275,21 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = 0.15f + (velocity * 0.02f); // The edge should always be at least partially visible, regardless // of velocity. mEdgeAlphaStart = 0.f; mEdgeScaleY = mEdgeScaleYStart = 0.f; // The glow depends more on the velocity, and therefore starts out // nearly invisible. mGlowAlphaStart = 0.3f; mGlowScaleYStart = 0.f; mGlowScaleYStart = Math.max(mGlowScaleY, 0.f); // Factor the velocity by 8. Testing on device shows this works best to // reflect the strength of the user's scrolling. mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); // Edge should never get larger than the size of its asset. mEdgeScaleYFinish = Math.max( HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); // Growth for the size of the glow should be quadratic to properly // respond // to a user's scrolling speed. The faster the scrolling speed, the more // intense the effect should be for both the size and the saturation. mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f); // Alpha should change for the glow as well as size. mGlowAlphaFinish = Math.max( mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); mTargetDisplacement = 0.5f; } Loading @@ -330,52 +306,42 @@ public class EdgeEffect { public boolean draw(Canvas canvas) { update(); mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); int glowBottom = (int) Math.min( mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f, mGlowHeight * MAX_GLOW_HEIGHT); if (mWidth < mMinWidth) { // Center the glow and clip it. int glowLeft = (mWidth - mMinWidth)/2; mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); } else { // Stretch the glow to fit. mGlow.setBounds(0, 0, mWidth, glowBottom); } mGlow.draw(canvas); final int count = canvas.save(); mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); final float y = mBounds.height(); final float centerY = y - mRadius; final float centerX = mBounds.centerX(); mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius); canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0); int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY); if (mWidth < mMinWidth) { // Center the edge and clip it. int edgeLeft = (mWidth - mMinWidth)/2; mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); } else { // Stretch the edge to fit. mEdge.setBounds(0, 0, mWidth, edgeBottom); final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; float translateX = mBounds.width() * displacement; float translateY = 0; if (mGlowScaleY > 1.f) { translateY = (mGlowScaleY - 1.f) * mBounds.height(); } mEdge.draw(canvas); if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) { canvas.clipRect(Float.MIN_VALUE, mBounds.top, Float.MAX_VALUE, Float.MAX_VALUE); canvas.translate(translateX, translateY); canvas.drawArc(mArcRect, 0, 180, true, mPaint); canvas.restoreToCount(count); boolean oneLastFrame = false; if (mState == STATE_RECEDE && mGlowScaleY == 0) { mState = STATE_IDLE; oneLastFrame = true; } return mState != STATE_IDLE; return mState != STATE_IDLE || oneLastFrame; } /** * Returns the bounds of the edge effect. * * @hide * Return the maximum height that the edge effect will be drawn at given the original * {@link #setSize(int, int) input size}. * @return The maximum height of the edge effect */ public Rect getBounds(boolean reverse) { mBounds.set(0, 0, mWidth, mMaxEffectHeight); mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0)); return mBounds; public int getMaxHeight() { return (int) (mBounds.height() * MAX_GLOW_HEIGHT + 0.5f); } private void update() { Loading @@ -384,10 +350,9 @@ public class EdgeEffect { final float interp = mInterpolator.getInterpolation(t); mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; mDisplacement = (mDisplacement + mTargetDisplacement) / 2; if (t >= 1.f - EPSILON) { switch (mState) { Loading @@ -396,14 +361,10 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = RECEDE_TIME; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; // After absorb, the glow and edge should fade to nothing. mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; // After absorb, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; Loading @@ -412,26 +373,14 @@ public class EdgeEffect { mStartTime = AnimationUtils.currentAnimationTimeMillis(); mDuration = PULL_DECAY_TIME; mEdgeAlphaStart = mEdgeAlpha; mEdgeScaleYStart = mEdgeScaleY; mGlowAlphaStart = mGlowAlpha; mGlowScaleYStart = mGlowScaleY; // After pull, the glow and edge should fade to nothing. mEdgeAlphaFinish = 0.f; mEdgeScaleYFinish = 0.f; // After pull, the glow should fade to nothing. mGlowAlphaFinish = 0.f; mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: // When receding, we want edge to decrease more slowly // than the glow. float factor = mGlowScaleYFinish != 0 ? 1 / (mGlowScaleYFinish * mGlowScaleYFinish) : Float.MAX_VALUE; mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp * factor; mState = STATE_RECEDE; break; case STATE_RECEDE: Loading
core/java/android/widget/HorizontalScrollView.java +4 −2 Original line number Diff line number Diff line Loading @@ -616,12 +616,14 @@ public class HorizontalScrollView extends FrameLayout { if (canOverscroll) { final int pulledToX = oldX + deltaX; if (pulledToX < 0) { mEdgeGlowLeft.onPull((float) deltaX / getWidth()); mEdgeGlowLeft.onPull((float) deltaX / getWidth(), 1.f - ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowRight.isFinished()) { mEdgeGlowRight.onRelease(); } } else if (pulledToX > range) { mEdgeGlowRight.onPull((float) deltaX / getWidth()); mEdgeGlowRight.onPull((float) deltaX / getWidth(), ev.getY(activePointerIndex) / getHeight()); if (!mEdgeGlowLeft.isFinished()) { mEdgeGlowLeft.onRelease(); } Loading
core/java/android/widget/ScrollView.java +4 −2 File changed.Preview size limit exceeded, changes collapsed. Show changes