Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1d4c812 authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Make internal recycler view use stretch edge effect" into sc-dev

parents 6f4e27d3 3006c811
Loading
Loading
Loading
Loading
+143 −1
Original line number Diff line number Diff line
@@ -16,10 +16,16 @@
package com.android.internal.widget;
import static android.widget.EdgeEffect.TYPE_GLOW;
import static android.widget.EdgeEffect.TYPE_STRETCH;
import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_BY_DEFAULT;
import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED;
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.Compatibility;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
@@ -460,6 +466,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
    private final int[] mScrollConsumed = new int[2];
    private final int[] mNestedOffsets = new int[2];
    private int mEdgeEffectType;
    /**
     * These are views that had their a11y importance changed during a layout. We defer these events
     * until the end of the layout because a11y service may make sync calls back to the RV while
@@ -587,6 +595,14 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
            setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        }
        boolean defaultToStretch = Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT)
                || Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED);
        TypedArray a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.EdgeEffect);
        mEdgeEffectType = a.getInt(com.android.internal.R.styleable.EdgeEffect_edgeEffectType,
                defaultToStretch ? TYPE_STRETCH : TYPE_GLOW);
        a.recycle();
        // Re-set whether nested scrolling is enabled so that it is set on all API levels
        setNestedScrollingEnabled(nestedScrollingEnabled);
    }
@@ -609,6 +625,28 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
        setAccessibilityDelegate(mAccessibilityDelegate);
    }
    /**
     * Returns the {@link EdgeEffect#getType()} used for all EdgeEffects.
     *
     * @return @link EdgeEffect#getType()} used for all EdgeEffects.
     */
    @EdgeEffect.EdgeEffectType
    public int getEdgeEffectType() {
        return mEdgeEffectType;
    }
    /**
     * Sets the {@link EdgeEffect#getType()} used in all EdgeEffects.
     * Any existing over-scroll effects are cleared and new effects are created as needed.
     *
     * @param type the {@link EdgeEffect#getType()} used in all EdgeEffects.
     */
    public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
        mEdgeEffectType = type;
        invalidateGlows();
        invalidate();
    }
    /**
     * Instantiate and set a LayoutManager, if specified in the attributes.
     */
@@ -2183,6 +2221,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
            return;
        }
        mLeftGlow = new EdgeEffect(getContext());
        mLeftGlow.setType(mEdgeEffectType);
        if (mClipToPadding) {
            mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
                    getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2196,6 +2235,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
            return;
        }
        mRightGlow = new EdgeEffect(getContext());
        mRightGlow.setType(mEdgeEffectType);
        if (mClipToPadding) {
            mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
                    getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2209,6 +2249,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
            return;
        }
        mTopGlow = new EdgeEffect(getContext());
        mTopGlow.setType(mEdgeEffectType);
        if (mClipToPadding) {
            mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                    getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2223,6 +2264,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
            return;
        }
        mBottomGlow = new EdgeEffect(getContext());
        mBottomGlow.setType(mEdgeEffectType);
        if (mClipToPadding) {
            mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                    getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2663,7 +2705,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
                mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
                mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
                if (mScrollState == SCROLL_STATE_SETTLING) {
                if (stopGlowAnimations(e) || mScrollState == SCROLL_STATE_SETTLING) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    setScrollState(SCROLL_STATE_DRAGGING);
                }
@@ -2731,6 +2773,38 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
        return mScrollState == SCROLL_STATE_DRAGGING;
    }
    /**
     * This stops any edge glow animation that is currently running by applying a
     * 0 length pull at the displacement given by the provided MotionEvent. On pre-S devices,
     * this method does nothing, allowing any animating edge effect to continue animating and
     * returning <code>false</code> always.
     *
     * @param e The motion event to use to indicate the finger position for the displacement of
     *          the current pull.
     * @return <code>true</code> if any edge effect had an existing effect to be drawn ond the
     * animation was stopped or <code>false</code> if no edge effect had a value to display.
     */
    private boolean stopGlowAnimations(MotionEvent e) {
        boolean stopped = false;
        if (mLeftGlow != null && mLeftGlow.getDistance() != 0) {
            mLeftGlow.onPullDistance(0, 1 - (e.getY() / getHeight()));
            stopped = true;
        }
        if (mRightGlow != null && mRightGlow.getDistance() != 0) {
            mRightGlow.onPullDistance(0, e.getY() / getHeight());
            stopped = true;
        }
        if (mTopGlow != null && mTopGlow.getDistance() != 0) {
            mTopGlow.onPullDistance(0, e.getX() / getWidth());
            stopped = true;
        }
        if (mBottomGlow != null && mBottomGlow.getDistance() != 0) {
            mBottomGlow.onPullDistance(0, 1 - e.getX() / getWidth());
            stopped = true;
        }
        return stopped;
    }
    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        final int listenerCount = mOnItemTouchListeners.size();
@@ -2807,6 +2881,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
                final int y = (int) (e.getY(index) + 0.5f);
                int dx = mLastTouchX - x;
                int dy = mLastTouchY - y;
                dx -= releaseHorizontalGlow(dx, e.getY());
                dy -= releaseVerticalGlow(dy, e.getX());
                if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
                    dx -= mScrollConsumed[0];
@@ -2887,6 +2963,72 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
        return true;
    }
    /**
     * If either of the horizontal edge glows are currently active, this consumes part or all of
     * deltaX on the edge glow.
     *
     * @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
     *                         for moving down and negative for moving up.
     * @param y The vertical position of the pointer.
     * @return The amount of <code>deltaX</code> that has been consumed by the
     * edge glow.
     */
    private int releaseHorizontalGlow(int deltaX, float y) {
        // First allow releasing existing overscroll effect:
        float consumed = 0;
        float displacement = y / getHeight();
        float pullDistance = (float) deltaX / getWidth();
        if (mLeftGlow != null && mLeftGlow.getDistance() != 0) {
            consumed = -mLeftGlow.onPullDistance(-pullDistance, 1 - displacement);
            if (mLeftGlow.getDistance() == 0) {
                mLeftGlow.onRelease();
            }
        } else if (mRightGlow != null && mRightGlow.getDistance() != 0) {
            consumed = mRightGlow.onPullDistance(pullDistance, displacement);
            if (mRightGlow.getDistance() == 0) {
                mRightGlow.onRelease();
            }
        }
        int pixelsConsumed = Math.round(consumed * getWidth());
        if (pixelsConsumed != 0) {
            invalidate();
        }
        return pixelsConsumed;
    }
    /**
     * If either of the vertical edge glows are currently active, this consumes part or all of
     * deltaY on the edge glow.
     *
     * @param deltaY The pointer motion, in pixels, in the vertical direction, positive
     *                         for moving down and negative for moving up.
     * @param x The vertical position of the pointer.
     * @return The amount of <code>deltaY</code> that has been consumed by the
     * edge glow.
     */
    private int releaseVerticalGlow(int deltaY, float x) {
        // First allow releasing existing overscroll effect:
        float consumed = 0;
        float displacement = x / getWidth();
        float pullDistance = (float) deltaY / getHeight();
        if (mTopGlow != null && mTopGlow.getDistance() != 0) {
            consumed = -mTopGlow.onPullDistance(-pullDistance, displacement);
            if (mTopGlow.getDistance() == 0) {
                mTopGlow.onRelease();
            }
        } else if (mBottomGlow != null && mBottomGlow.getDistance() != 0) {
            consumed = mBottomGlow.onPullDistance(pullDistance, 1 - displacement);
            if (mBottomGlow.getDistance() == 0) {
                mBottomGlow.onRelease();
            }
        }
        int pixelsConsumed = Math.round(consumed * getHeight());
        if (pixelsConsumed != 0) {
            invalidate();
        }
        return pixelsConsumed;
    }
    private void resetTouch() {
        if (mVelocityTracker != null) {
            mVelocityTracker.clear();