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
16cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craikimport android.support.annotation.NonNull;
17cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craikimport android.support.annotation.Nullable;
186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guimport android.support.v4.util.CircularIntArray;
19cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craikimport android.support.v7.widget.RecyclerView;
20c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Guimport android.util.SparseIntArray;
216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guimport java.io.PrintWriter;
23c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Guimport java.util.Arrays;
246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu/**
26f923d595ace34894c49d1609d3c629336b175b89Dake Gu * A grid is representation of single or multiple rows layout data structure and algorithm.
27f923d595ace34894c49d1609d3c629336b175b89Dake Gu * Grid is the base class for single row, non-staggered grid and staggered grid.
286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * <p>
296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * To use the Grid, user must implement a Provider to create or remove visible item.
306e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * Grid maintains a list of visible items.  Visible items are created when
316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * user calls appendVisibleItems() or prependVisibleItems() with certain limitation
326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * (e.g. a max edge that append up to).  Visible items are deleted when user calls
336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * removeInvisibleItemsAtEnd() or removeInvisibleItemsAtFront().  Grid's algorithm
346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * uses size of visible item returned from Provider.createItem() to decide which row
356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * to add a new visible item and may cache the algorithm results.   User must call
366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * invalidateItemsAfter() when it detects item size changed to ask Grid to remove cached
376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu * results.
386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu */
396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Guabstract class Grid {
406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * A constant representing a default starting index, indicating that the
436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * developer did not provide a start index.
446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static final int START_DEFAULT = -1;
466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
47c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu    Object[] mTmpItem = new Object[1];
48c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu
496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * When user uses Grid,  he should provide count of items and
516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the method to create item and remove item.
526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static interface Provider {
546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Return how many items (are in the adapter).
576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
58134b0891c25facf14c53ef939846010284025ca9Dake Gu        int getCount();
59134b0891c25facf14c53ef939846010284025ca9Dake Gu
60134b0891c25facf14c53ef939846010284025ca9Dake Gu        /**
61134b0891c25facf14c53ef939846010284025ca9Dake Gu         * @return Min index to prepend, usually it's 0; but in the preLayout case,
62134b0891c25facf14c53ef939846010284025ca9Dake Gu         * when grid was showing 5,6,7.  Removing 3,4,5 will make the layoutPosition to
63134b0891c25facf14c53ef939846010284025ca9Dake Gu         * be 3(deleted),4,5 in prelayout pass; Grid's index is still 5,6,7 in prelayout.
64134b0891c25facf14c53ef939846010284025ca9Dake Gu         * When we prepend in prelayout, we can call createItem(4), createItem(3), createItem(2),
65134b0891c25facf14c53ef939846010284025ca9Dake Gu         * the minimal index is 2, which is also the delta to mapping to layoutPosition in
66134b0891c25facf14c53ef939846010284025ca9Dake Gu         * prelayout pass.
67134b0891c25facf14c53ef939846010284025ca9Dake Gu         */
68134b0891c25facf14c53ef939846010284025ca9Dake Gu        int getMinIndex();
696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Create visible item and where the provider should measure it.
726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * The call is always followed by addItem().
736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param append  True if new item is after last visible item, false if new item is
756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         *                before first visible item.
766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param item    item[0] returns created item that will be passed in addItem() call.
77c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu         * @param disappearingItem The item is a disappearing item added by
78c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu         *                         {@link Grid#fillDisappearingItems(int[], int, SparseIntArray)}.
79c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu         *
806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @return length of the item.
816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
82c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        int createItem(int index, boolean append, Object[] item, boolean disappearingItem);
836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * add item to given row and given edge.  The call is always after createItem().
866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param item      The object returned by createItem()
876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param length    The size of the object
896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param rowIndex  Row index to put the item
906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param edge      min_edge if not reversed or max_edge if reversed.
916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
92134b0891c25facf14c53ef939846010284025ca9Dake Gu        void addItem(Object item, int index, int length, int rowIndex, int edge);
936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Remove visible item at index.
966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
98134b0891c25facf14c53ef939846010284025ca9Dake Gu        void removeItem(int index);
996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
1016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Get edge of an existing visible item. edge will be the min_edge
1026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * if not reversed or the max_edge if reversed.
1036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
1046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
105134b0891c25facf14c53ef939846010284025ca9Dake Gu        int getEdge(int index);
1066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
1086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * Get size of an existing visible item.
1096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * @param index     0-based index of the item in provider
1106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
111134b0891c25facf14c53ef939846010284025ca9Dake Gu        int getSize(int index);
1126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Cached representation of an item in Grid.  May be subclassed.
1166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public static class Location {
1186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        /**
1196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         * The index of the row for this Location.
1206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu         */
1216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public int row;
1226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        public Location(int row) {
1246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            this.row = row;
1256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
1266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected Provider mProvider;
1296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected boolean mReversedFlow;
130ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu    protected int mSpacing;
1316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mNumRows;
1326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mFirstVisibleIndex = -1;
1336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mLastVisibleIndex = -1;
1346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected CircularIntArray[] mTmpItemPositionsInRows;
1366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    // the first index that grid will layout
1386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected int mStartIndex = START_DEFAULT;
1396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
141f923d595ace34894c49d1609d3c629336b175b89Dake Gu     * Creates a single or multiple rows (can be staggered or not staggered) grid
1426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
143f923d595ace34894c49d1609d3c629336b175b89Dake Gu    public static Grid createGrid(int rows) {
144f923d595ace34894c49d1609d3c629336b175b89Dake Gu        Grid grid;
145f923d595ace34894c49d1609d3c629336b175b89Dake Gu        if (rows == 1) {
146f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid = new SingleRow();
147f923d595ace34894c49d1609d3c629336b175b89Dake Gu        } else {
148f923d595ace34894c49d1609d3c629336b175b89Dake Gu            // TODO support non staggered multiple rows grid
149f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid = new StaggeredGridDefault();
150f923d595ace34894c49d1609d3c629336b175b89Dake Gu            grid.setNumRows(rows);
151f923d595ace34894c49d1609d3c629336b175b89Dake Gu        }
1526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return grid;
1536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
156ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu     * Sets the space between items in a row
1576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
158ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu    public final void setSpacing(int spacing) {
159ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu        mSpacing = spacing;
1606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets if reversed flow (rtl)
1646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void setReversedFlow(boolean reversedFlow) {
1666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mReversedFlow = reversedFlow;
1676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if reversed flow (rtl)
1716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public boolean isReversedFlow() {
1736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mReversedFlow;
1746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets the {@link Provider} for this grid.
1786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
1796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param provider The provider for this grid.
1806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void setProvider(Provider provider) {
1826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mProvider = provider;
1836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets the first item index to create when there are no items.
1876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
1886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param startIndex the index of the first item
1896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void setStart(int startIndex) {
1916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mStartIndex = startIndex;
1926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
1936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
1946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
1956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns the number of rows in the grid.
1966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
1976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public int getNumRows() {
1986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mNumRows;
1996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Sets number of rows to fill into. For views that represent a
2036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * horizontal list, this will be the rows of the view. For views that
2046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * represent a vertical list, this will be the columns.
2056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     *
2066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param numRows numberOfRows
2076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    void setNumRows(int numRows) {
2096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (numRows <= 0) {
2106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            throw new IllegalArgumentException();
2116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mNumRows == numRows) {
2136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
2146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mNumRows = numRows;
2166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mTmpItemPositionsInRows = new CircularIntArray[mNumRows];
2176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        for (int i = 0; i < mNumRows; i++) {
2186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            mTmpItemPositionsInRows[i] = new CircularIntArray();
2196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns index of first visible item in the staggered grid.  Returns negative value
2246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * if no visible item.
2256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getFirstVisibleIndex() {
2276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mFirstVisibleIndex;
2286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2306e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns index of last visible item in the staggered grid.  Returns negative value
2326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * if no visible item.
2336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getLastVisibleIndex() {
2356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return mLastVisibleIndex;
2366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Reset visible indices and keep cache (if exists)
2406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void resetVisibleIndex() {
2426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        mFirstVisibleIndex = mLastVisibleIndex = -1;
2436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Invalidate items after or equal to index. This will remove visible items
2475723e456309c09c31054d29187fd26b6e2b760efDake Gu     * after that and invalidate cache of layout results after that. Note that it's client's
2485723e456309c09c31054d29187fd26b6e2b760efDake Gu     * responsibility to perform removing child action, {@link Provider#removeItem(int)} will not
2495723e456309c09c31054d29187fd26b6e2b760efDake Gu     * be called because the index might be invalidated.
2506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void invalidateItemsAfter(int index) {
2526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (index < 0) {
2536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
2546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mLastVisibleIndex < 0) {
2566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            return;
2576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2585723e456309c09c31054d29187fd26b6e2b760efDake Gu        if (mLastVisibleIndex >= index) {
2595723e456309c09c31054d29187fd26b6e2b760efDake Gu            mLastVisibleIndex = index - 1;
2606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
261c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        resetVisibleIndexIfEmpty();
2626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (getFirstVisibleIndex() < 0) {
2636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            setStart(index);
2646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
2656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Gets the row index of item at given index.
2696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final int getRowIndex(int index) {
271e36e2ce16cbd6144ccd49e0b90ae4c587a08c8f3Dake Gu        Location location = getLocation(index);
272e36e2ce16cbd6144ccd49e0b90ae4c587a08c8f3Dake Gu        if (location == null) {
273e36e2ce16cbd6144ccd49e0b90ae4c587a08c8f3Dake Gu            return -1;
274e36e2ce16cbd6144ccd49e0b90ae4c587a08c8f3Dake Gu        }
275e36e2ce16cbd6144ccd49e0b90ae4c587a08c8f3Dake Gu        return location.row;
2766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Gets {@link Location} of item.  The return object is read only and temporarily.
2806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract Location getLocation(int index);
2826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row min edge of visible items,
2856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the row index is returned in indices[0], the item index is returned in indices[1].
2866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
287cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik    public final int findRowMin(boolean findLarge, @Nullable int[] indices) {
2886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return findRowMin(findLarge, mReversedFlow ? mLastVisibleIndex : mFirstVisibleIndex,
2896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                indices);
2906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
2916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row min edge of visible items, starts searching from
2946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * indexLimit, the row index is returned in indices[0], the item index is returned in indices[1].
2956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
2966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract int findRowMin(boolean findLarge, int indexLimit, int[] rowIndex);
2976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
2986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
2996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Finds the largest or smallest row max edge of visible items, the row index is returned in
3006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * indices[0], the item index is returned in indices[1].
3016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
302cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik    public final int findRowMax(boolean findLarge, @Nullable int[] indices) {
3036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return findRowMax(findLarge, mReversedFlow ? mFirstVisibleIndex : mLastVisibleIndex,
3046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                indices);
3056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Find largest or smallest row max edge of visible items, starts searching from indexLimit,
3096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * the row index is returned in indices[0], the item index is returned in indices[1].
3106e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3116e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract int findRowMax(boolean findLarge, int indexLimit, int[] indices);
3126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if appending item has reached "toLimit"
3156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected final boolean checkAppendOverLimit(int toLimit) {
31785df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        if (mLastVisibleIndex < 0) {
31885df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu            return false;
31985df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        }
320ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu        return mReversedFlow ? findRowMin(true, null) <= toLimit + mSpacing :
321ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu                    findRowMax(false, null) >= toLimit - mSpacing;
3226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3246e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returns true if prepending item has reached "toLimit"
3266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected final boolean checkPrependOverLimit(int toLimit) {
32885df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        if (mLastVisibleIndex < 0) {
32985df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu            return false;
33085df3117f0fcd0aa10d7bd45194dab97e22112f2Dake Gu        }
331ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu        return mReversedFlow ? findRowMax(false, null) >= toLimit - mSpacing :
332ef4e1b371215f9fffa9245159250740b611dfb4dDake Gu                    findRowMin(true, null) <= toLimit + mSpacing;
3336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3346e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3356e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3366e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Return array of int array for all rows, each int array contains visible item positions
3376e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * in pair on that row between startPos(included) and endPositions(included).
3386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returned value is read only, do not change it.
3396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * <p>
3406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * E.g. First row has 3,7,8, second row has 4,5,6.
3416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * getItemPositionsInRows(3, 8) returns { {3,3,7,8}, {4,6} }
3426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract CircularIntArray[] getItemPositionsInRows(int startPos, int endPos);
3446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3456e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Return array of int array for all rows, each int array contains visible item positions
3476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * in pair on that row.
3486e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Returned value is read only, do not change it.
3496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * <p>
3506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * E.g. First row has 3,7,8, second row has 4,5,6  { {3,3,7,8}, {4,6} }
3516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final CircularIntArray[] getItemPositionsInRows() {
3536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return getItemPositionsInRows(getFirstVisibleIndex(), getLastVisibleIndex());
3546e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3556e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3566e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3576e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items and stops after one column is filled.
3586e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * (i.e. filled items from row 0 to row mNumRows - 1)
3596e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3606e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3616e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final boolean prependOneColumnVisibleItems() {
3626e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return prependVisibleItems(mReversedFlow ? Integer.MIN_VALUE : Integer.MAX_VALUE, true);
3636e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3646e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3656e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3666e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items until first item or reaches toLimit (min edge when not reversed or
3676e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * max edge when reversed)
3686e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3696e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void prependVisibleItems(int toLimit) {
3706e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        prependVisibleItems(toLimit, false);
3716e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3726e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3736e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3746e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Prepends items until first item or reaches toLimit (min edge when not reversed or
3756e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * max edge when reversed).
3766e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param oneColumnMode  true when fills one column and stops,  false
3776e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * when checks if condition matches before filling first column.
3786e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3796e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3806e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract boolean prependVisibleItems(int toLimit, boolean oneColumnMode);
3816e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3826e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3836e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Appends items and stops after one column is filled.
3846e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * (i.e. filled items from row 0 to row mNumRows - 1)
3856e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if at least one item is filled.
3866e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3876e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public boolean appendOneColumnVisibleItems() {
3886e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        return appendVisibleItems(mReversedFlow ? Integer.MAX_VALUE : Integer.MIN_VALUE, true);
3896e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3906e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3916e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
3926e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Append items until last item or reaches toLimit (max edge when not
3936e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * reversed or min edge when reversed)
3946e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
3956e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public final void appendVisibleItems(int toLimit) {
3966e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        appendVisibleItems(toLimit, false);
3976e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
3986e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
3996e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
4006e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Appends items until last or reaches toLimit (high edge when not
4016e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * reversed or low edge when reversed).
4026e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @param oneColumnMode True when fills one column and stops,  false
4036e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * when checks if condition matches before filling first column.
4046e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * @return true if filled at least one item
4056e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
4066e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    protected abstract boolean appendVisibleItems(int toLimit, boolean oneColumnMode);
4076e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
4086e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
4096e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Removes invisible items from end until reaches item at aboveIndex or toLimit.
410c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param aboveIndex Don't remove items whose index is equals or smaller than aboveIndex
411c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param toLimit Don't remove items whose left edge is less than toLimit.
4126e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
4136e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void removeInvisibleItemsAtEnd(int aboveIndex, int toLimit) {
4146e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        while(mLastVisibleIndex >= mFirstVisibleIndex && mLastVisibleIndex > aboveIndex) {
4156e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            boolean offEnd = !mReversedFlow ? mProvider.getEdge(mLastVisibleIndex) >= toLimit
4166e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                    : mProvider.getEdge(mLastVisibleIndex) <= toLimit;
4176e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            if (offEnd) {
4186e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mProvider.removeItem(mLastVisibleIndex);
4196e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mLastVisibleIndex--;
4206e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            } else {
4216e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                break;
4226e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            }
4236e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
424c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        resetVisibleIndexIfEmpty();
4256e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4266e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
4276e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    /**
4286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     * Removes invisible items from front until reaches item at belowIndex or toLimit.
429c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param belowIndex Don't remove items whose index is equals or larger than belowIndex
430c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param toLimit Don't remove items whose right edge is equals or greater than toLimit.
4316e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu     */
4326e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public void removeInvisibleItemsAtFront(int belowIndex, int toLimit) {
4336e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        while(mLastVisibleIndex >= mFirstVisibleIndex && mFirstVisibleIndex < belowIndex) {
434c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            final int size = mProvider.getSize(mFirstVisibleIndex);
435c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            boolean offFront = !mReversedFlow
436c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    ? mProvider.getEdge(mFirstVisibleIndex) + size <= toLimit
437c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    : mProvider.getEdge(mFirstVisibleIndex) - size >= toLimit;
4386e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            if (offFront) {
4396e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mProvider.removeItem(mFirstVisibleIndex);
4406e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                mFirstVisibleIndex++;
4416e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            } else {
4426e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu                break;
4436e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            }
4446e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
445c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        resetVisibleIndexIfEmpty();
4466e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4476e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
448c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas    private void resetVisibleIndexIfEmpty() {
4496e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        if (mLastVisibleIndex < mFirstVisibleIndex) {
4506e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu            resetVisibleIndex();
4516e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu        }
4526e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    }
4536e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu
454cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik    /**
455c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * Fill disappearing items, i.e. the items are moved out of window, we need give them final
456c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * location so recyclerview will run a slide out animation. The positions that was greater than
457c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * last visible index will be appended to end, the positions that was smaller than first visible
458c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * index will be prepend to beginning.
459c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param positions Sorted list of positions of disappearing items.
460c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     * @param positionToRow Which row we want to put the disappearing item.
461c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu     */
462c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu    public void fillDisappearingItems(int[] positions, int positionsLength,
463c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            SparseIntArray positionToRow) {
464c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        final int lastPos = getLastVisibleIndex();
465c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        final int resultSearchLast = lastPos >= 0
466c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                ? Arrays.binarySearch(positions, 0, positionsLength, lastPos) : 0;
467c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        if (resultSearchLast < 0) {
468c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            // we shouldn't find lastPos in disappearing position list.
469c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            int firstDisappearingIndex = -resultSearchLast - 1;
470c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            int edge;
471c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            if (mReversedFlow) {
472c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                edge = mProvider.getEdge(lastPos) - mProvider.getSize(lastPos) - mSpacing;
473c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            } else {
474c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                edge = mProvider.getEdge(lastPos) + mProvider.getSize(lastPos) + mSpacing;
475c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            }
476c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            for (int i = firstDisappearingIndex; i < positionsLength; i++) {
477c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int disappearingIndex = positions[i];
478c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int disappearingRow = positionToRow.get(disappearingIndex);
479c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                if (disappearingRow < 0) {
480c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    disappearingRow = 0; // if not found put in row 0
481c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                }
482c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int size = mProvider.createItem(disappearingIndex, true, mTmpItem, true);
483c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                mProvider.addItem(mTmpItem[0], disappearingIndex, size, disappearingRow, edge);
484c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                if (mReversedFlow) {
485c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    edge = edge - size - mSpacing;
486c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                } else {
487c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    edge = edge + size + mSpacing;
488c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                }
489c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            }
490c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        }
491c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu
492c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        final int firstPos = getFirstVisibleIndex();
493c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        final int resultSearchFirst = firstPos >= 0
494c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                ? Arrays.binarySearch(positions, 0, positionsLength, firstPos) : 0;
495c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        if (resultSearchFirst < 0) {
496c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            // we shouldn't find firstPos in disappearing position list.
497c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            int firstDisappearingIndex = -resultSearchFirst - 2;
498c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            int edge;
499c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            if (mReversedFlow) {
500c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                edge = mProvider.getEdge(firstPos);
501c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            } else {
502c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                edge = mProvider.getEdge(firstPos);
503c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            }
504c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            for (int i = firstDisappearingIndex; i >= 0; i--) {
505c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int disappearingIndex = positions[i];
506c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int disappearingRow = positionToRow.get(disappearingIndex);
507c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                if (disappearingRow < 0) {
508c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    disappearingRow = 0; // if not found put in row 0
509c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                }
510c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                int size = mProvider.createItem(disappearingIndex, false, mTmpItem, true);
511c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                if (mReversedFlow) {
512c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    edge = edge + mSpacing + size;
513c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                } else {
514c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                    edge = edge - mSpacing - size;
515c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                }
516c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu                mProvider.addItem(mTmpItem[0], disappearingIndex, size, disappearingRow, edge);
517c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu            }
518c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu        }
519c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu    }
520c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu
521c50aca4940c8ae508393278aa7a9c77a3f93f87dDake Gu    /**
522cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik     * Queries items adjacent to the viewport (in the direction of da) into the prefetch registry.
523cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik     */
524cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik    public void collectAdjacentPrefetchPositions(int fromLimit, int da,
525cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik            @NonNull RecyclerView.LayoutManager.LayoutPrefetchRegistry layoutPrefetchRegistry) {
526cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik    }
527cf2ed161d09de8af108dfa9775b2d4449d46306aChris Craik
5286e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu    public abstract void debugPrint(PrintWriter pw);
5296e96b9d46e7af6bedf6213ecc2ba0ad7b8050778Dake Gu}
530