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

Commit c9c93e75 authored by Adam Powell's avatar Adam Powell Committed by Android (Google) Code Review
Browse files

Merge "Revert "Update smoothScrollToPosition to move faster for large offsets""

parents 2ba4efff 56032a37
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -31482,12 +31482,10 @@ package android.widget {
    method public int getCheckedItemPosition();
    method public android.util.SparseBooleanArray getCheckedItemPositions();
    method public int getChoiceMode();
    method public int getFirstPositionForRow(int);
    method public int getListPaddingBottom();
    method public int getListPaddingLeft();
    method public int getListPaddingRight();
    method public int getListPaddingTop();
    method public int getRowForPosition(int);
    method public android.view.View getSelectedView();
    method public android.graphics.drawable.Drawable getSelector();
    method public java.lang.CharSequence getTextFilter();
@@ -31533,7 +31531,6 @@ package android.widget {
    method public void setRemoteViewsAdapter(android.content.Intent);
    method public void setScrollIndicators(android.view.View, android.view.View);
    method public void setScrollingCacheEnabled(boolean);
    method public void setSelectionFromTop(int, int);
    method public void setSelector(int);
    method public void setSelector(android.graphics.drawable.Drawable);
    method public void setSmoothScrollbarEnabled(boolean);
@@ -32649,6 +32646,7 @@ package android.widget {
    method public void setOverscrollHeader(android.graphics.drawable.Drawable);
    method public void setSelection(int);
    method public void setSelectionAfterHeaderView();
    method public void setSelectionFromTop(int, int);
    method public void smoothScrollByOffset(int);
  }
+8 −318
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.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
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;
@@ -421,7 +418,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
    /**
     * Handles scrolling between positions within the list.
     */
    SubPositionScroller mPositionScroller;
    PositionScroller mPositionScroller;

    /**
     * The offset in pixels form the top of the AdapterView to the top
@@ -4843,14 +4840,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    public void smoothScrollToPosition(int position) {
        if (mPositionScroller == null) {
            mPositionScroller = new SubPositionScroller();
            mPositionScroller = new PositionScroller();
        }
        mPositionScroller.start(position);
    }

    /**
     * Smoothly scroll to the specified adapter position. The view will scroll
     * such that the indicated position is displayed <code>offset</code> pixels below
     * such that the indicated position is displayed <code>offset</code> pixels from
     * the top edge of the view. If this is impossible, (e.g. the offset would scroll
     * the first or last item beyond the boundaries of the list) it will get as close
     * as possible. The scroll will take <code>duration</code> milliseconds to complete.
@@ -4862,14 +4859,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    public void smoothScrollToPositionFromTop(int position, int offset, int duration) {
        if (mPositionScroller == null) {
            mPositionScroller = new SubPositionScroller();
            mPositionScroller = new PositionScroller();
        }
        mPositionScroller.startWithOffset(position, offset, duration);
    }

    /**
     * Smoothly scroll to the specified adapter position. The view will scroll
     * such that the indicated position is displayed <code>offset</code> pixels below
     * such that the indicated position is displayed <code>offset</code> pixels from
     * the top edge of the view. If this is impossible, (e.g. the offset would scroll
     * the first or last item beyond the boundaries of the list) it will get as close
     * as possible.
@@ -4880,9 +4877,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    public void smoothScrollToPositionFromTop(int position, int offset) {
        if (mPositionScroller == null) {
            mPositionScroller = new SubPositionScroller();
            mPositionScroller = new PositionScroller();
        }
        mPositionScroller.startWithOffset(position, offset, offset);
        mPositionScroller.startWithOffset(position, offset);
    }

    /**
@@ -4896,7 +4893,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     */
    public void smoothScrollToPosition(int position, int boundPosition) {
        if (mPositionScroller == null) {
            mPositionScroller = new SubPositionScroller();
            mPositionScroller = new PositionScroller();
        }
        mPositionScroller.start(position, boundPosition);
    }
@@ -6995,311 +6992,4 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            return null;
        }
    }

    /**
     * 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
     */
    private int getHeightForRow(int row) {
        final int firstRowPosition = getFirstPositionForRow(row);
        final int lastRowPosition = getFirstPositionForRow(row + 1);
        int maxHeight = 0;
        for (int i = firstRowPosition; i < lastRowPosition; i++) {
            final int height = getHeightForPosition(i);
            if (height > maxHeight) {
                maxHeight = height;
            }
        }
        return maxHeight;
    }

    /**
     * Returns the height of the view for the specified position.
     *
     * @param position the item position
     * @return view height in pixels
     */
    int getHeightForPosition(int position) {
        final int firstVisiblePosition = getFirstVisiblePosition();
        final int childCount = getChildCount();
        final int index = position - firstVisiblePosition;
        if (position >= 0 && position < childCount) {
            final View view = getChildAt(index);
            return view.getHeight();
        } else {
            final View view = obtainView(position, mIsScrap);
            view.measure(mWidthMeasureSpec, MeasureSpec.UNSPECIFIED);
            final int height = view.getMeasuredHeight();
            mRecycler.addScrapView(view, position);
            return height;
        }
    }

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

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

    /**
     * Sets the selected item and positions the selection y pixels from the top edge
     * of the ListView. (If in touch mode, the item will not be selected but it will
     * still be positioned appropriately.)
     *
     * @param position Index (starting at 0) of the data item to be selected.
     * @param y The distance from the top edge of the ListView (plus padding) that the
     *        item will be positioned.
     */
    public void setSelectionFromTop(int position, int y) {
        if (mAdapter == null) {
            return;
        }

        if (!isInTouchMode()) {
            position = lookForSelectablePosition(position, true);
            if (position >= 0) {
                setNextSelectedPositionInt(position);
            }
        } else {
            mResurrectToPosition = position;
        }

        if (position >= 0) {
            mLayoutMode = LAYOUT_SPECIFIC;
            mSpecificTop = mListPadding.top + y;

            if (mNeedSync) {
                mSyncPosition = position;
                mSyncRowId = mAdapter.getItemId(position);
            }

            if (mPositionScroller != null) {
                mPositionScroller.stop();
            }
            requestLayout();
        }
    }

    class SubPositionScroller {
        private static final int DEFAULT_SCROLL_DURATION = 200;

        private SubScroller mSubScroller;
        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;
            }

            final int firstPosition = getFirstVisiblePosition();
            final int lastPosition = firstPosition + getChildCount();
            final int targetRow = getRowForPosition(targetPosition);
            final int firstRow = getRowForPosition(firstPosition);
            final int lastRow = getRowForPosition(lastPosition);
            if (useOffset || targetRow <= firstRow) {
                mOffset = offset;
            } else if (targetRow >= lastRow - 1) {
                final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
                mOffset = listHeight - getHeightForPosition(targetPosition);
            } else {
                // Don't scroll, target is entirely on-screen.
                return;
            }

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

            final View firstChild = getChildAt(0);
            final float startOffsetRatio = -firstChild.getTop() / (float) firstChild.getHeight();
            final float startSubRow = firstRow + startOffsetRatio;
            if (startSubRow == endSubRow && mOffset == 0) {
                // Don't scroll, target is already in position.
                return;
            }

            if (mSubScroller == null) {
                mSubScroller = new SubScroller();
            }
            mSubScroller.startScroll(startSubRow, endSubRow, duration);

            postOnAnimation(mAnimationFrame);
        }

        private float computeBoundSubRow(int targetRow, int boundRow) {
            // Compute the target and offset as a sub-position.
            int remainingOffset = mOffset;
            int targetHeight = getHeightForRow(targetRow - 1);
            while (remainingOffset > 0) {
                remainingOffset -= targetHeight;
                targetRow--;
                targetHeight = getHeightForRow(targetRow - 1);
            }
            final float targetSubRow = targetRow - remainingOffset / targetHeight;
            mOffset = 0;

            if (targetSubRow >= boundRow) {
                // End position would push the bound position above the list.
                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);
            int endRow = boundRow;
            int totalHeight = boundHeight;
            int endHeight;
            do {
                endRow--;
                endHeight = getHeightForRow(endRow);
                totalHeight += endHeight;
            } while (totalHeight < listHeight && endRow > 0);

            final float endOffsetRatio = (totalHeight - listHeight) / (float) endHeight;
            final float boundSubRow = endRow + endOffsetRatio;
            return Math.max(boundSubRow, targetSubRow);
        }

        /**
         * @param position
         * @param boundPosition
         */
        public void start(int position, int boundPosition) {
            scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION);
        }

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

        /**
         * @param position
         */
        public void start(int position) {
            scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION);
        }

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

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

            final int row = (int) subRow;
            final int position = getFirstPositionForRow(row);
            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.
     */
    private static class SubScroller {
        private final Interpolator mInterpolator;

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

        private float mPosition;
        private float mInterpolatedValue;

        public SubScroller() {
            this(null);
        }

        public SubScroller(Interpolator interpolator) {
            if (interpolator == null) {
                mInterpolator = new AccelerateDecelerateInterpolator();
            } else {
                mInterpolator = interpolator;
            }
        }

        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 = MathUtils.constrain(elapsed / (float) mDuration, 0, 1);

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

            return elapsed < mDuration;
        }

        public float getPosition() {
            return mPosition;
        }

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

    @Override
    public int getRowForPosition(int position) {
        return position / mNumColumns;
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Sets up mListPadding
+39 −78
Original line number Diff line number Diff line
@@ -1891,6 +1891,45 @@ public class ListView extends AbsListView {
        setSelectionFromTop(position, 0);
    }

    /**
     * Sets the selected item and positions the selection y pixels from the top edge
     * of the ListView. (If in touch mode, the item will not be selected but it will
     * still be positioned appropriately.)
     *
     * @param position Index (starting at 0) of the data item to be selected.
     * @param y The distance from the top edge of the ListView (plus padding) that the
     *        item will be positioned.
     */
    public void setSelectionFromTop(int position, int y) {
        if (mAdapter == null) {
            return;
        }

        if (!isInTouchMode()) {
            position = lookForSelectablePosition(position, true);
            if (position >= 0) {
                setNextSelectedPositionInt(position);
            }
        } else {
            mResurrectToPosition = position;
        }

        if (position >= 0) {
            mLayoutMode = LAYOUT_SPECIFIC;
            mSpecificTop = mListPadding.top + y;

            if (mNeedSync) {
                mSyncPosition = position;
                mSyncRowId = mAdapter.getItemId(position);
            }

            if (mPositionScroller != null) {
                mPositionScroller.stop();
            }
            requestLayout();
        }
    }

    /**
     * Makes the item at the supplied position selected.
     * 
@@ -3706,84 +3745,6 @@ public class ListView extends AbsListView {
        return new long[0];
    }

    @Override
    int getHeightForPosition(int position) {
        final int height = super.getHeightForPosition(position);
        if (shouldAdjustHeightForDivider(position)) {
            return height + mDividerHeight;
        }
        return height;
    }

    private boolean shouldAdjustHeightForDivider(int itemIndex) {
        final int dividerHeight = mDividerHeight;
        final Drawable overscrollHeader = mOverScrollHeader;
        final Drawable overscrollFooter = mOverScrollFooter;
        final boolean drawOverscrollHeader = overscrollHeader != null;
        final boolean drawOverscrollFooter = overscrollFooter != null;
        final boolean drawDividers = dividerHeight > 0 && mDivider != null;

        if (drawDividers) {
            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
            final int itemCount = mItemCount;
            final int headerCount = mHeaderViewInfos.size();
            final int footerLimit = (itemCount - mFooterViewInfos.size());
            final boolean isHeader = (itemIndex < headerCount);
            final boolean isFooter = (itemIndex >= footerLimit);
            final boolean headerDividers = mHeaderDividersEnabled;
            final boolean footerDividers = mFooterDividersEnabled;
            if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
                final ListAdapter adapter = mAdapter;
                if (!mStackFromBottom) {
                    final boolean isLastItem = (itemIndex == (itemCount - 1));
                    if (!drawOverscrollFooter || !isLastItem) {
                        final int nextIndex = itemIndex + 1;
                        // Draw dividers between enabled items, headers
                        // and/or footers when enabled and requested, and
                        // after the last enabled item.
                        if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
                                && (nextIndex >= headerCount)) && (isLastItem
                                || adapter.isEnabled(nextIndex) && (footerDividers || !isFooter
                                                && (nextIndex < footerLimit)))) {
                            return true;
                        } else if (fillForMissingDividers) {
                            return true;
                        }
                    }
                } else {
                    final int start = drawOverscrollHeader ? 1 : 0;
                    final boolean isFirstItem = (itemIndex == start);
                    if (!isFirstItem) {
                        final int previousIndex = (itemIndex - 1);
                        // Draw dividers between enabled items, headers
                        // and/or footers when enabled and requested, and
                        // before the first enabled item.
                        if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
                                && (previousIndex >= headerCount)) && (isFirstItem ||
                                adapter.isEnabled(previousIndex) && (footerDividers || !isFooter
                                        && (previousIndex < footerLimit)))) {
                            return true;
                        } else if (fillForMissingDividers) {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    @Override
    public int getRowForPosition(int position) {
        return position;
    }

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

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);