Grid.java revision f923d595ace34894c49d1609d3c629336b175b89
16e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu/*
26e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * Copyright (C) 2014 The Android Open Source Project
36e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu *
46e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
56e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * in compliance with the License. You may obtain a copy of the License at
66e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu *
76e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
86e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu *
96e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * the License.
136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu */
146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gupackage android.support.v17.leanback.widget;
156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guimport android.support.v4.util.CircularIntArray;
176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guimport android.util.Log;
186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guimport java.io.PrintWriter;
206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu/**
22f923d595ace34894c49d1609d3c629336b175b89Dake Gu * A grid is representation of single or multiple rows layout data structure and algorithm.
23f923d595ace34894c49d1609d3c629336b175b89Dake Gu * Grid is the base class for single row, non-staggered grid and staggered grid.
246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * <p>
256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * To use the Grid, user must implement a Provider to create or remove visible item.
266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * Grid maintains a list of visible items.  Visible items are created when
276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * user calls appendVisibleItems() or prependVisibleItems() with certain limitation
286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * (e.g. a max edge that append up to).  Visible items are deleted when user calls
296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * removeInvisibleItemsAtEnd() or removeInvisibleItemsAtFront().  Grid's algorithm
306e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * uses size of visible item returned from Provider.createItem() to decide which row
316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * to add a new visible item and may cache the algorithm results.   User must call
326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * invalidateItemsAfter() when it detects item size changed to ask Grid to remove cached
336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * results.
346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu */
356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guabstract class Grid {
366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * A constant representing a default starting index, indicating that the
396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * developer did not provide a start index.
406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static final int START_DEFAULT = -1;
426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * When user uses Grid,  he should provide count of items and
456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the method to create item and remove item.
466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static interface Provider {
486e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Return how many items (are in the adapter).
516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract int getCount();
536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Create visible item and where the provider should measure it.
566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * The call is always followed by addItem().
576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
586e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param append  True if new item is after last visible item, false if new item is
596e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         *                before first visible item.
606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param item    item[0] returns created item that will be passed in addItem() call.
616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @return length of the item.
626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract int createItem(int index, boolean append, Object[] item);
646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * add item to given row and given edge.  The call is always after createItem().
676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param item      The object returned by createItem()
686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param length    The size of the object
706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param rowIndex  Row index to put the item
716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param edge      min_edge if not reversed or max_edge if reversed.
726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract void addItem(Object item, int index, int length, int rowIndex, int edge);
746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Remove visible item at index.
776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract void removeItem(int index);
806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Get edge of an existing visible item. edge will be the min_edge
836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * if not reversed or the max_edge if reversed.
846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract int getEdge(int index);
876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Get size of an existing visible item.
906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public abstract int getSize(int index);
936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Cached representation of an item in Grid.  May be subclassed.
976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static class Location {
996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
1006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * The index of the row for this Location.
1016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
1026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public int row;
1036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public Location(int row) {
1056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            this.row = row;
1066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
1076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected Provider mProvider;
1106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected boolean mReversedFlow;
1116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mMargin;
1126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mNumRows;
1136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mFirstVisibleIndex = -1;
1146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mLastVisibleIndex = -1;
1156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected CircularIntArray[] mTmpItemPositionsInRows;
1176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    // the first index that grid will layout
1196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mStartIndex = START_DEFAULT;
1206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
122f923d595ace34894c49d1609d3c629336b175b89Dake Gu     * Creates a single or multiple rows (can be staggered or not staggered) grid
1236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
124f923d595ace34894c49d1609d3c629336b175b89Dake Gu    public static Grid createGrid(int rows) {
125f923d595ace34894c49d1609d3c629336b175b89Dake Gu        Grid grid;
126f923d595ace34894c49d1609d3c629336b175b89Dake Gu        if (rows == 1) {
127f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid = new SingleRow();
128f923d595ace34894c49d1609d3c629336b175b89Dake Gu        } else {
129f923d595ace34894c49d1609d3c629336b175b89Dake Gu            // TODO support non staggered multiple rows grid
130f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid = new StaggeredGridDefault();
131f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid.setNumRows(rows);
132f923d595ace34894c49d1609d3c629336b175b89Dake Gu        }
1336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return grid;
1346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets the margin between items in a row
1386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void setMargin(int margin) {
1406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mMargin = margin;
1416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets if reversed flow (rtl)
1456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void setReversedFlow(boolean reversedFlow) {
1476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mReversedFlow = reversedFlow;
1486e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if reversed flow (rtl)
1526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public boolean isReversedFlow() {
1546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mReversedFlow;
1556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1586e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets the {@link Provider} for this grid.
1596e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
1606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param provider The provider for this grid.
1616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void setProvider(Provider provider) {
1636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mProvider = provider;
1646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets the first item index to create when there are no items.
1686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
1696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param startIndex the index of the first item
1706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void setStart(int startIndex) {
1726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mStartIndex = startIndex;
1736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns the number of rows in the grid.
1776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public int getNumRows() {
1796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mNumRows;
1806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets number of rows to fill into. For views that represent a
1846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * horizontal list, this will be the rows of the view. For views that
1856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * represent a vertical list, this will be the columns.
1866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
1876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param numRows numberOfRows
1886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    void setNumRows(int numRows) {
1906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (numRows <= 0) {
1916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            throw new IllegalArgumentException();
1926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
1936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mNumRows == numRows) {
1946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
1956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
1966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mNumRows = numRows;
1976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mTmpItemPositionsInRows = new CircularIntArray[mNumRows];
1986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        for (int i = 0; i < mNumRows; i++) {
1996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            mTmpItemPositionsInRows[i] = new CircularIntArray();
2006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns index of first visible item in the staggered grid.  Returns negative value
2056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * if no visible item.
2066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getFirstVisibleIndex() {
2086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mFirstVisibleIndex;
2096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns index of last visible item in the staggered grid.  Returns negative value
2136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * if no visible item.
2146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getLastVisibleIndex() {
2166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mLastVisibleIndex;
2176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Reset visible indices and keep cache (if exists)
2216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void resetVisibleIndex() {
2236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mFirstVisibleIndex = mLastVisibleIndex = -1;
2246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Invalidate items after or equal to index. This will remove visible items
2286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * after that and invalidate cache of layout results after that.
2296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2306e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void invalidateItemsAfter(int index) {
2316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (index < 0) {
2326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
2336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mLastVisibleIndex < 0) {
2356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
2366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        while (mLastVisibleIndex >= index) {
2386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            mProvider.removeItem(mLastVisibleIndex);
2396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            mLastVisibleIndex--;
2406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        resetVisbileIndexIfEmpty();
2426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (getFirstVisibleIndex() < 0) {
2436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            setStart(index);
2446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2486e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Gets the row index of item at given index.
2496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getRowIndex(int index) {
2516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return getLocation(index).row;
2526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Gets {@link Location} of item.  The return object is read only and temporarily.
2566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract Location getLocation(int index);
2586e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2596e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row min edge of visible items,
2616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the row index is returned in indices[0], the item index is returned in indices[1].
2626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int findRowMin(boolean findLarge, int[] indices) {
2646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return findRowMin(findLarge, mReversedFlow ? mLastVisibleIndex : mFirstVisibleIndex,
2656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                indices);
2666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row min edge of visible items, starts searching from
2706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * indexLimit, the row index is returned in indices[0], the item index is returned in indices[1].
2716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract int findRowMin(boolean findLarge, int indexLimit, int[] rowIndex);
2736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row max edge of visible items, the row index is returned in
2766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * indices[0], the item index is returned in indices[1].
2776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int findRowMax(boolean findLarge, int[] indices) {
2796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return findRowMax(findLarge, mReversedFlow ? mFirstVisibleIndex : mLastVisibleIndex,
2806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                indices);
2816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Find largest or smallest row max edge of visible items, starts searching from indexLimit,
2856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the row index is returned in indices[0], the item index is returned in indices[1].
2866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract int findRowMax(boolean findLarge, int indexLimit, int[] indices);
2886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if appending item has reached "toLimit"
2916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected final boolean checkAppendOverLimit(int toLimit) {
29385df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        if (mLastVisibleIndex < 0) {
29485df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu            return false;
29585df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        }
29685df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        return mReversedFlow ? findRowMin(true, null) <= toLimit + mMargin :
29785df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu                    findRowMax(false, null) >= toLimit - mMargin;
2986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if prepending item has reached "toLimit"
3026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected final boolean checkPrependOverLimit(int toLimit) {
30485df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        if (mLastVisibleIndex < 0) {
30585df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu            return false;
30685df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        }
30785df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        return mReversedFlow ? findRowMax(false, null) >= toLimit + mMargin :
30885df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu                    findRowMin(true, null) <= toLimit - mMargin;
3096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Return array of int array for all rows, each int array contains visible item positions
3136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * in pair on that row between startPos(included) and endPositions(included).
3146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returned value is read only, do not change it.
3156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * <p>
3166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * E.g. First row has 3,7,8, second row has 4,5,6.
3176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * getItemPositionsInRows(3, 8) returns { {3,3,7,8}, {4,6} }
3186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract CircularIntArray[] getItemPositionsInRows(int startPos, int endPos);
3206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Return array of int array for all rows, each int array contains visible item positions
3236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * in pair on that row.
3246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returned value is read only, do not change it.
3256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * <p>
3266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * E.g. First row has 3,7,8, second row has 4,5,6  { {3,3,7,8}, {4,6} }
3276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final CircularIntArray[] getItemPositionsInRows() {
3296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return getItemPositionsInRows(getFirstVisibleIndex(), getLastVisibleIndex());
3306e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items and stops after one column is filled.
3346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * (i.e. filled items from row 0 to row mNumRows - 1)
3356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final boolean prependOneColumnVisibleItems() {
3386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return prependVisibleItems(mReversedFlow ? Integer.MIN_VALUE : Integer.MAX_VALUE, true);
3396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items until first item or reaches toLimit (min edge when not reversed or
3436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * max edge when reversed)
3446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void prependVisibleItems(int toLimit) {
3466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        prependVisibleItems(toLimit, false);
3476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3486e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items until first item or reaches toLimit (min edge when not reversed or
3516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * max edge when reversed).
3526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param oneColumnMode  true when fills one column and stops,  false
3536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * when checks if condition matches before filling first column.
3546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract boolean prependVisibleItems(int toLimit, boolean oneColumnMode);
3576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3586e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3596e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Appends items and stops after one column is filled.
3606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * (i.e. filled items from row 0 to row mNumRows - 1)
3616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public boolean appendOneColumnVisibleItems() {
3646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return appendVisibleItems(mReversedFlow ? Integer.MAX_VALUE : Integer.MIN_VALUE, true);
3656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Append items until last item or reaches toLimit (max edge when not
3696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * reversed or min edge when reversed)
3706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void appendVisibleItems(int toLimit) {
3726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        appendVisibleItems(toLimit, false);
3736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Appends items until last or reaches toLimit (high edge when not
3776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * reversed or low edge when reversed).
3786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param oneColumnMode True when fills one column and stops,  false
3796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * when checks if condition matches before filling first column.
3806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if filled at least one item
3816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract boolean appendVisibleItems(int toLimit, boolean oneColumnMode);
3836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Removes invisible items from end until reaches item at aboveIndex or toLimit.
3866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void removeInvisibleItemsAtEnd(int aboveIndex, int toLimit) {
3886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        while(mLastVisibleIndex >= mFirstVisibleIndex && mLastVisibleIndex > aboveIndex) {
3896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            boolean offEnd = !mReversedFlow ? mProvider.getEdge(mLastVisibleIndex) >= toLimit
3906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                    : mProvider.getEdge(mLastVisibleIndex) <= toLimit;
3916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            if (offEnd) {
3926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mProvider.removeItem(mLastVisibleIndex);
3936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mLastVisibleIndex--;
3946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            } else {
3956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                break;
3966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            }
3976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
3986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        resetVisbileIndexIfEmpty();
3996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
4016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
4026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Removes invisible items from front until reaches item at belowIndex or toLimit.
4036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
4046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void removeInvisibleItemsAtFront(int belowIndex, int toLimit) {
4056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        while(mLastVisibleIndex >= mFirstVisibleIndex && mFirstVisibleIndex < belowIndex) {
4066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            boolean offFront = !mReversedFlow ? mProvider.getEdge(mFirstVisibleIndex)
4076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                    + mProvider.getSize(mFirstVisibleIndex) <= toLimit
4086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                    : mProvider.getEdge(mFirstVisibleIndex)
4096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                            - mProvider.getSize(mFirstVisibleIndex) >= toLimit;
4106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            if (offFront) {
4116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mProvider.removeItem(mFirstVisibleIndex);
4126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mFirstVisibleIndex++;
4136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            } else {
4146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                break;
4156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            }
4166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
4176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        resetVisbileIndexIfEmpty();
4186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
4206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    private void resetVisbileIndexIfEmpty() {
4216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mLastVisibleIndex < mFirstVisibleIndex) {
4226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            resetVisibleIndex();
4236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
4246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
4266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract void debugPrint(PrintWriter pw);
4276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu}
428