1b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn/*
2b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * Copyright (C) 2014 The Android Open Source Project
3b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *
4b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * in compliance with the License. You may obtain a copy of the License at
6b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *
7b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * http://www.apache.org/licenses/LICENSE-2.0
8b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *
9b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * Unless required by applicable law or agreed to in writing, software distributed under the License
10b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * or implied. See the License for the specific language governing permissions and limitations under
12b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * the License.
13b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn */
14b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbournpackage android.support.v17.leanback.widget;
15b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
16b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbournimport android.support.v4.util.CircularArray;
17b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
18b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbournimport java.io.PrintWriter;
19adc2a01f5701cbcc044754119b572abcf31c7c5fDake Guimport java.util.ArrayList;
20adc2a01f5701cbcc044754119b572abcf31c7c5fDake Guimport java.util.List;
21b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
22b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn/**
23b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * A dynamic data structure that maintains staggered grid position information
24b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * for each individual child. The algorithm ensures that each row will be kept
25b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * as balanced as possible when prepending and appending a child.
26b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *
27b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * <p>
28b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * You may keep view {@link StaggeredGrid.Location} inside StaggeredGrid as much
29b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * as possible since prepending and appending views is not symmetric: layout
30b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * going from 0 to N will likely produce a different result than layout going
31b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * from N to 0 for the staggered cases. If a user scrolls from 0 to N then
32b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * scrolls back to 0 and we don't keep history location information, edges of
33b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * the very beginning of rows will not be aligned. It is recommended to keep a
34b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * list of tens of thousands of {@link StaggeredGrid.Location}s which will be
35b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * big enough to remember a typical user's scroll history. There are situations
36b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * where StaggeredGrid falls back to the simple case where we do not need save a
37b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * huge list of locations inside StaggeredGrid:
38b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * <ul>
39b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *   <li>Only one row (e.g., a single row listview)</li>
40b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *   <li> Each item has the same length (not staggered at all)</li>
41b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * </ul>
42b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn *
43b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * <p>
44b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn * This class is abstract and can be replaced with different implementations.
45b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn */
46b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbournabstract class StaggeredGrid {
47b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
48b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
49b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * TODO: document this
50b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
51b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public static interface Provider {
52b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
53b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * Return how many items are in the adapter.
54b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
55b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public abstract int getCount();
56b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
57b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
58b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * Create the object at a given row.
59b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
60b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public abstract void createItem(int index, int row, boolean append);
61b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
62b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
63b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
64b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Location of an item in the grid. For now it only saves row index but
65b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * more information may be added in the future.
66b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
67b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final static class Location {
68b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
69b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * The index of the row for this Location.
70b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
71b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public final int row;
72b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
73b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
74b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * Create a Location with the given row index.
75b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
76b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public Location(int row) {
77b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            this.row = row;
78b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
79b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
80b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
81b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
82b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * TODO: document this
83b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
84b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final static class Row {
85b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
86b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * first view start location
87b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
88b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public int low;
89b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        /**
90b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         * last view end location
91b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn         */
92b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        public int high;
93b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
94b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
95b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected Provider mProvider;
96b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected int mNumRows = 1; // mRows.length
97b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected Row[] mRows;
98b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected CircularArray<Location> mLocations = new CircularArray<Location>(64);
99adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu    private ArrayList<Integer>[] mTmpItemPositionsInRows;
100e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing    protected boolean mReversedFlow;
101b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
102b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
103b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * A constant representing a default starting index, indicating that the
104b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * developer did not provide a start index.
105b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
106b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public static final int START_DEFAULT = -1;
107b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
108b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    // the first index that grid will layout
109b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected int mStartIndex = START_DEFAULT;
110b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    // the row to layout the first index
111b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected int mStartRow = START_DEFAULT;
112b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
113b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected int mFirstIndex = -1;
114b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
115e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing    public void setReversedFlow(boolean reversedFlow) {
116e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing        mReversedFlow = reversedFlow;
117e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing    }
118e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing
119b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
120b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Sets the {@link Provider} for this staggered grid.
121b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     *
122b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * @param provider The provider for this staggered grid.
123b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
124b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public void setProvider(Provider provider) {
125b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mProvider = provider;
126b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
127b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
128b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
129b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Sets the array of {@link Row}s to fill into. For views that represent a
130b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * horizontal list, this will be the rows of the view. For views that
131b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * represent a vertical list, this will be the columns.
132b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     *
133b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * @param row The array of {@link Row}s to be filled.
134b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
135b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final void setRows(Row[] row) {
136b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        if (row == null || row.length == 0) {
137b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            throw new IllegalArgumentException();
138b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
139b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mNumRows = row.length;
140b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mRows = row;
141adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        mTmpItemPositionsInRows = new ArrayList[mNumRows];
142adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        for (int i = 0; i < mNumRows; i++) {
143adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu            mTmpItemPositionsInRows[i] = new ArrayList(32);
144adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        }
145b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
146b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
147b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
148b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Returns the number of rows in the staggered grid.
149b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
150b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final int getNumRows() {
151b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return mNumRows;
152b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
153b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
154b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
155b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Set the first item index and the row index to load when there are no
156b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * items.
157b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     *
158b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * @param startIndex the index of the first item
159b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * @param startRow the index of the row
160b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
161b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final void setStart(int startIndex, int startRow) {
162b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mStartIndex = startIndex;
163b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mStartRow = startRow;
164b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
165b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
166b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
167b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Returns the first index in the staggered grid.
168b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
169b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final int getFirstIndex() {
170b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return mFirstIndex;
171b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
172b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
173b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
174b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Returns the last index in the staggered grid.
175b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
176b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final int getLastIndex() {
177b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return mFirstIndex + mLocations.size() - 1;
178b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
179b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
180b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
181b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Returns the size of the saved {@link Location}s.
182b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
183b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final int getSize() {
184b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return mLocations.size();
185b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
186b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
187b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
188b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Returns the {@link Location} at the given index.
189b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
190b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final Location getLocation(int index) {
191b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        if (mLocations.size() == 0) {
192b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            return null;
193b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
194b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return mLocations.get(index - mFirstIndex);
195b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
196b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
197b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
198b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Removes the first element.
199b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
200b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final void removeFirst() {
201b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mFirstIndex++;
202b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mLocations.popFirst();
203b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
204b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
205b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
206b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Removes the last element.
207b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
208b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final void removeLast() {
209b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mLocations.popLast();
210b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
211b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
212b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public final void debugPrint(PrintWriter pw) {
213b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        for (int i = 0, size = mLocations.size(); i < size; i++) {
214b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            Location loc = mLocations.get(i);
215b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            pw.print("<" + (mFirstIndex + i) + "," + loc.row + ">");
216b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            pw.print(" ");
217b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            pw.println();
218b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
219b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
220b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
221b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final int getMaxHighRowIndex() {
222b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        int maxHighRowIndex = 0;
223b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        for (int i = 1; i < mNumRows; i++) {
224b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            if (mRows[i].high > mRows[maxHighRowIndex].high) {
225b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn                maxHighRowIndex = i;
226b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            }
227b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
228b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return maxHighRowIndex;
229b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
230b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
231b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final int getMinHighRowIndex() {
232b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        int minHighRowIndex = 0;
233b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        for (int i = 1; i < mNumRows; i++) {
234b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            if (mRows[i].high < mRows[minHighRowIndex].high) {
235b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn                minHighRowIndex = i;
236b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            }
237b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
238b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return minHighRowIndex;
239b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
240b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
241b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final Location appendItemToRow(int itemIndex, int rowIndex) {
242b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        Location loc = new Location(rowIndex);
243b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        if (mLocations.size() == 0) {
244b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            mFirstIndex = itemIndex;
245b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
246b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mLocations.addLast(loc);
24779b86b227e6794937ec311522b50e727f8eec263Dake Gu        mProvider.createItem(itemIndex, rowIndex, true);
248b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return loc;
249b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
250b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
251b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
252b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Append items until the high edge reaches upTo.
253b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
254e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing    public abstract void appendItems(int toLimit);
255b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
256b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final int getMaxLowRowIndex() {
257b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        int maxLowRowIndex = 0;
258b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        for (int i = 1; i < mNumRows; i++) {
259b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            if (mRows[i].low > mRows[maxLowRowIndex].low) {
260b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn                maxLowRowIndex = i;
261b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            }
262b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
263b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return maxLowRowIndex;
264b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
265b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
266b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final int getMinLowRowIndex() {
267b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        int minLowRowIndex = 0;
268b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        for (int i = 1; i < mNumRows; i++) {
269b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            if (mRows[i].low < mRows[minLowRowIndex].low) {
270b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn                minLowRowIndex = i;
271b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn            }
272b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        }
273b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return minLowRowIndex;
274b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
275b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
276b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    protected final Location prependItemToRow(int itemIndex, int rowIndex) {
277b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        Location loc = new Location(rowIndex);
278b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mFirstIndex = itemIndex;
279b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        mLocations.addFirst(loc);
28079b86b227e6794937ec311522b50e727f8eec263Dake Gu        mProvider.createItem(itemIndex, rowIndex, false);
281b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn        return loc;
282b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    }
283b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
284b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
285adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu     * Return array of Lists for all rows, each List contains item positions
286adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu     * on that row between startPos(included) and endPositions(included).
287adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu     * Returned value is read only, do not change it.
288adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu     */
289adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu    public final List<Integer>[] getItemPositionsInRows(int startPos, int endPos) {
290adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        for (int i = 0; i < mNumRows; i++) {
291adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu            mTmpItemPositionsInRows[i].clear();
292adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        }
293adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        if (startPos >= 0) {
294adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu            for (int i = startPos; i <= endPos; i++) {
295adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu                mTmpItemPositionsInRows[getLocation(i).row].add(i);
296adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu            }
297adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        }
298adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu        return mTmpItemPositionsInRows;
299adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu    }
300adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu
301adc2a01f5701cbcc044754119b572abcf31c7c5fDake Gu    /**
302b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Prepend items until the low edge reaches downTo.
303b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
304e0e66a21916f94ebbced0d1ffe3dc652c9c7a15eKris Giesing    public abstract void prependItems(int toLimit);
305b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn
306b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    /**
307b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * Strip items, keep a contiguous subset of items; the subset should include
308b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * at least one item on every row that currently has at least one item.
309b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     *
310b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * <p>
311b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     * TODO: document this better
312b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn     */
313b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn    public abstract void stripDownTo(int itemIndex);
314b9537aff4a6ff5231030799cdaf931c27fb9579bTim Kilbourn}
315