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

Commit 1dada3da authored by Alan Viverette's avatar Alan Viverette
Browse files

DO NOT MERGE Remove sub-position scroller

BUG: 14477472
Change-Id: I019c58dedb383e9e906831c8e44bab8b88e92604
(cherry picked from commit 66072fe0e1494a851e54bc7756734141dfbf4fe0)
parent 8fbd0dc3
Loading
Loading
Loading
Loading
+0 −289
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.MathUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.StateSet;
@@ -61,8 +60,6 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.BaseInputConnection;
@@ -7269,290 +7266,4 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            }
        }
    }

    /**
     * Abstract position scroller that handles sub-position scrolling but has no
     * understanding of layout.
     */
    abstract class AbsSubPositionScroller extends AbsPositionScroller {
        private static final int DURATION_AUTO = -1;

        private static final int DURATION_AUTO_MIN = 100;
        private static final int DURATION_AUTO_MAX = 500;

        private final SubScroller mSubScroller = new SubScroller();

        /**
         * The target offset in pixels between the top of the list and the top
         * of the target position.
         */
        private int mOffset;

        /**
         * Scroll the minimum amount to get the target view entirely on-screen.
         */
        private void scrollToPosition(final int targetPosition, final boolean useOffset,
                final int offset, final int boundPosition, final int duration) {
            stop();

            if (mDataChanged) {
                // Wait until we're back in a stable state to try this.
                mPositionScrollAfterLayout = new Runnable() {
                    @Override
                    public void run() {
                        scrollToPosition(
                                targetPosition, useOffset, offset, boundPosition, duration);
                    }
                };
                return;
            }

            if (mAdapter == null) {
                // Can't scroll anywhere without an adapter.
                return;
            }

            final int itemCount = getCount();
            final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1);
            final int clampedBoundPosition = MathUtils.constrain(boundPosition, -1, itemCount - 1);
            final int firstPosition = getFirstVisiblePosition();
            final int lastPosition = firstPosition + getChildCount();
            final int targetRow = getRowForPosition(clampedPosition);
            final int firstRow = getRowForPosition(firstPosition);
            final int lastRow = getRowForPosition(lastPosition);
            if (useOffset || targetRow <= firstRow) {
                // Offset so the target row is top-aligned.
                mOffset = offset;
            } else if (targetRow >= lastRow - 1) {
                // Offset so the target row is bottom-aligned.
                final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
                mOffset = getHeightForPosition(clampedPosition) - listHeight;
            } else {
                // Don't scroll, target is entirely on-screen.
                return;
            }

            float endSubRow = targetRow;
            if (clampedBoundPosition != INVALID_POSITION) {
                final int boundRow = getRowForPosition(clampedBoundPosition);
                if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) {
                    endSubRow = computeBoundSubRow(targetRow, boundRow);
                }
            }

            final View firstChild = getChildAt(0);
            if (firstChild == null) {
                return;
            }

            final int firstChildHeight = firstChild.getHeight();
            final float startOffsetRatio;
            if (firstChildHeight == 0) {
                startOffsetRatio = 0;
            } else {
                startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight;
            }

            final float startSubRow = MathUtils.constrain(
                    firstRow + startOffsetRatio, 0, getCount());
            if (startSubRow == endSubRow && mOffset == 0) {
                // Don't scroll, target is already in position.
                return;
            }

            final int durationMillis;
            if (duration == DURATION_AUTO) {
                final float subRowDelta = Math.abs(startSubRow - endSubRow);
                durationMillis = (int) MathUtils.lerp(
                        DURATION_AUTO_MIN, DURATION_AUTO_MAX, subRowDelta / getCount());
            } else {
                durationMillis = duration;
            }

            mSubScroller.startScroll(startSubRow, endSubRow, durationMillis);

            postOnAnimation(mAnimationFrame);
        }

        /**
         * Given a target row and offset, computes the sub-row position that
         * aligns with the top of the list. If the offset is negative, the
         * resulting sub-row will be smaller than the target row.
         */
        private float resolveOffset(int targetRow, int offset) {
            // Compute the target sub-row position by finding the actual row
            // indicated by the target and offset.
            int remainingOffset = offset;
            int targetHeight = getHeightForRow(targetRow);
            if (offset < 0) {
                // Subtract row heights until we find the right row.
                while (targetRow > 0 && remainingOffset < 0) {
                    remainingOffset += targetHeight;
                    targetRow--;
                    targetHeight = getHeightForRow(targetRow);
                }
            } else if (offset > 0) {
                // Add row heights until we find the right row.
                while (targetRow < getCount() - 1 && remainingOffset > targetHeight) {
                    remainingOffset -= targetHeight;
                    targetRow++;
                    targetHeight = getHeightForRow(targetRow);
                }
            }

            final float targetOffsetRatio;
            if (remainingOffset < 0 || targetHeight == 0) {
                targetOffsetRatio = 0;
            } else {
                targetOffsetRatio = remainingOffset / (float) targetHeight;
            }

            return targetRow + targetOffsetRatio;
        }

        private float computeBoundSubRow(int targetRow, int boundRow) {
            final float targetSubRow = resolveOffset(targetRow, mOffset);
            mOffset = 0;

            // The target row is below the bound row, so the end position would
            // push the bound position above the list. Abort!
            if (targetSubRow >= boundRow) {
                return boundRow;
            }

            // Compute the closest possible sub-position that wouldn't push the
            // bound position's view further below the list.
            final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
            final int boundHeight = getHeightForRow(boundRow);
            final float boundSubRow = resolveOffset(boundRow, -listHeight + boundHeight);

            return Math.max(boundSubRow, targetSubRow);
        }

        @Override
        public void start(int position) {
            scrollToPosition(position, false, 0, INVALID_POSITION, DURATION_AUTO);
        }

        @Override
        public void start(int position, int boundPosition) {
            scrollToPosition(position, false, 0, boundPosition, DURATION_AUTO);
        }

        @Override
        public void startWithOffset(int position, int offset) {
            scrollToPosition(position, true, offset, INVALID_POSITION, DURATION_AUTO);
        }

        @Override
        public void startWithOffset(int position, int offset, int duration) {
            scrollToPosition(position, true, offset, INVALID_POSITION, duration);
        }

        @Override
        public void stop() {
            removeCallbacks(mAnimationFrame);
        }

        /**
         * Returns the height of a row, which is computed as the maximum height of
         * the items in the row.
         *
         * @param row the row index
         * @return row height in pixels
         */
        public abstract int getHeightForRow(int row);

        /**
         * Returns the row for the specified item position.
         *
         * @param position the item position
         * @return the row index
         */
        public abstract int getRowForPosition(int position);

        /**
         * Returns the first item position within the specified row.
         *
         * @param row the row
         * @return the position of the first item in the row
         */
        public abstract int getFirstPositionForRow(int row);

        private void onAnimationFrame() {
            final boolean shouldPost = mSubScroller.computePosition();
            final float subRow = mSubScroller.getPosition();

            final int row = (int) subRow;
            final int position = getFirstPositionForRow(row);
            if (position >= getCount()) {
                // Invalid position, abort scrolling.
                return;
            }

            final int rowHeight = getHeightForRow(row);
            final int offset = (int) (rowHeight * (subRow - row));
            final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue());
            setSelectionFromTop(position, -offset - addOffset);

            if (shouldPost) {
                postOnAnimation(mAnimationFrame);
            }
        }

        private Runnable mAnimationFrame = new Runnable() {
            @Override
            public void run() {
                onAnimationFrame();
            }
        };
    }

    /**
     * Scroller capable of returning floating point positions.
     */
    static class SubScroller {
        private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();

        private float mStartPosition;
        private float mEndPosition;
        private long mStartTime;
        private long mDuration;

        private float mPosition;
        private float mInterpolatedValue;

        public void startScroll(float startPosition, float endPosition, int duration) {
            mStartPosition = startPosition;
            mEndPosition = endPosition;
            mDuration = duration;

            mStartTime = AnimationUtils.currentAnimationTimeMillis();
            mPosition = startPosition;
            mInterpolatedValue = 0;
        }

        public boolean computePosition() {
            final long elapsed = AnimationUtils.currentAnimationTimeMillis() - mStartTime;
            final float value;
            if (mDuration <= 0) {
                value = 1;
            } else {
                value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1);
            }

            mInterpolatedValue = INTERPOLATOR.getInterpolation(value);
            mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition;

            return elapsed < mDuration;
        }

        public float getPosition() {
            return mPosition;
        }

        public float getInterpolatedValue() {
            return mInterpolatedValue;
        }
    }
}
+0 −34
Original line number Diff line number Diff line
@@ -1028,11 +1028,6 @@ public class GridView extends AbsListView {
        return didNotInitiallyFit;
    }

    @Override
    AbsPositionScroller createPositionScroller() {
        return new GridViewPositionScroller();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Sets up mListPadding
@@ -2392,33 +2387,4 @@ public class GridView extends AbsListView {
                column, 1, row, 1, isHeading, isSelected);
        info.setCollectionItemInfo(itemInfo);
    }

    /**
     * Sub-position scroller that understands the layout of a GridView.
     */
    class GridViewPositionScroller extends AbsSubPositionScroller {
        @Override
        public int getRowForPosition(int position) {
            return position / mNumColumns;
        }

        @Override
        public int getFirstPositionForRow(int row) {
            return row * mNumColumns;
        }

        @Override
        public int getHeightForRow(int row) {
            final int firstRowPosition = row * mNumColumns;
            final int lastRowPosition = Math.min(getCount(), firstRowPosition + mNumColumns);
            int maxHeight = 0;
            for (int i = firstRowPosition; i < lastRowPosition; i++) {
                final int height = getHeightForPosition(i);
                if (height > maxHeight) {
                    maxHeight = height;
                }
            }
            return maxHeight;
        }
    }
}
+0 −25
Original line number Diff line number Diff line
@@ -3871,11 +3871,6 @@ public class ListView extends AbsListView {
        return false;
    }

    @Override
    AbsPositionScroller createPositionScroller() {
        return new ListViewPositionScroller();
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
@@ -3905,24 +3900,4 @@ public class ListView extends AbsListView {
                0, 1, position, 1, isHeading, isSelected);
        info.setCollectionItemInfo(itemInfo);
    }

    /**
     * Sub-position scroller that understands the layout of a ListView.
     */
    class ListViewPositionScroller extends AbsSubPositionScroller {
        @Override
        public int getRowForPosition(int position) {
            return position;
        }

        @Override
        public int getFirstPositionForRow(int row) {
            return row;
        }

        @Override
        public int getHeightForRow(int row) {
            return getHeightForPosition(row);
        }
    }
}