18347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang/*
28347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Copyright (C) 2012 The Android Open Source Project
38347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
48347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Licensed under the Apache License, Version 2.0 (the "License");
58347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * you may not use this file except in compliance with the License.
68347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * You may obtain a copy of the License at
78347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
88347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *      http://www.apache.org/licenses/LICENSE-2.0
98347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * Unless required by applicable law or agreed to in writing, software
118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * distributed under the License is distributed on an "AS IS" BASIS,
128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * See the License for the specific language governing permissions and
148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * limitations under the License.
158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */
168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangpackage com.android.ex.widget;
188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.content.Context;
208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.content.res.TypedArray;
218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.database.DataSetObserver;
228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.graphics.Canvas;
238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.os.Parcel;
248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.os.Parcelable;
258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.util.SparseArrayCompat;
268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.MotionEventCompat;
278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.VelocityTrackerCompat;
288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.support.v4.view.ViewCompat;
298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.AttributeSet;
308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.Log;
318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.util.SparseArray;
328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.MotionEvent;
338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.VelocityTracker;
348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.View;
358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.ViewConfiguration;
368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.view.ViewGroup;
378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport android.widget.ListAdapter;
388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport java.util.ArrayList;
408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangimport java.util.Arrays;
418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang/**
438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * ListView and GridView just not complex enough? Try StaggeredGridView!
448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>StaggeredGridView presents a multi-column grid with consistent column sizes
468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * but varying row sizes between the columns. Each successive item from a
478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * {@link android.widget.ListAdapter ListAdapter} will be arranged from top to bottom,
488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * left to right. The largest vertical gap is always filled first.</p>
498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>Item views may span multiple columns as specified by their {@link LayoutParams}.
518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * The attribute <code>android:layout_span</code> may be used when inflating
528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * item views from xml.</p>
538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang *
548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang * <p>This class is still under development and is not fully functional yet.</p>
558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang */
568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yangpublic class StaggeredGridView extends ViewGroup {
578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final String TAG = "StaggeredGridView";
588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final boolean DEBUG = false;
598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /*
618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * There are a few things you should know if you're going to make modifications
628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * to StaggeredGridView.
638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Like ListView, SGV populates from an adapter and recycles views that fall out
658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * of the visible boundaries of the grid. A few invariants always hold:
668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * - mFirstPosition is the adapter position of the View returned by getChildAt(0).
688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * - Any child index can be translated to an adapter position by adding mFirstPosition.
698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * - Any adapter position can be translated to a child index by subtracting mFirstPosition.
708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * - Views for items in the range [mFirstPosition, mFirstPosition + getChildCount()) are
718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *   currently attached to the grid as children. All other adapter positions do not have
728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *   active views.
738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * This means a few things thanks to the staggered grid's nature. Some views may stay attached
758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * long after they have scrolled offscreen if removing and recycling them would result in
768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * breaking one of the invariants above.
778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * LayoutRecords are used to track data about a particular item's layout after the associated
798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * view has been removed. These let positioning and the choice of column for an item
808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * remain consistent even though the rules for filling content up vs. filling down vary.
818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Whenever layout parameters for a known LayoutRecord change, other LayoutRecords before
838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * or after it may need to be invalidated. e.g. if the item's height or the number
848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * of columns it spans changes, all bets for other items in the same direction are off
858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * since the cached information no longer applies.
868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private ListAdapter mAdapter;
898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public static final int COLUMN_COUNT_AUTO = -1;
918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mColCountSetting = 2;
938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mColCount = 2;
948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mMinColWidth = 0;
958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mItemMargin;
968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int[] mItemTops;
988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int[] mItemBottoms;
998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mFastChildLayout;
1018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mPopulating;
1028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mForcePopulateOnLayout;
1038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mInLayout;
1048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mRestoreOffset;
1058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final RecycleBin mRecycler = new RecycleBin();
1078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final AdapterDataSetObserver mObserver = new AdapterDataSetObserver();
1098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mDataChanged;
1118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mOldItemCount;
1128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mItemCount;
1138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean mHasStableIds;
1148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mFirstPosition;
1168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mTouchSlop;
1188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mMaximumVelocity;
1198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mFlingVelocity;
1208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private float mLastTouchY;
1218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private float mTouchRemainderY;
1228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mActivePointerId;
1238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final int TOUCH_MODE_IDLE = 0;
1258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final int TOUCH_MODE_DRAGGING = 1;
1268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final int TOUCH_MODE_FLINGING = 2;
1278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private int mTouchMode;
1298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
1308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final ScrollerCompat mScroller;
1318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final EdgeEffectCompat mTopEdge;
1338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final EdgeEffectCompat mBottomEdge;
1348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private static final class LayoutRecord {
1368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public int column;
1378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public long id = -1;
1388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public int height;
1398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public int span;
1408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private int[] mMargins;
1418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private final void ensureMargins() {
1438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins == null) {
1448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // Don't need to confirm length;
1458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // all layoutrecords are purged when column count changes.
1468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mMargins = new int[span * 2];
1478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public final int getMarginAbove(int col) {
1518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins == null) {
1528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return 0;
1538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return mMargins[col * 2];
1558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public final int getMarginBelow(int col) {
1588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins == null) {
1598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return 0;
1608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return mMargins[col * 2 + 1];
1628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public final void setMarginAbove(int col, int margin) {
1658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins == null && margin == 0) {
1668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return;
1678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ensureMargins();
1698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mMargins[col * 2] = margin;
1708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public final void setMarginBelow(int col, int margin) {
1738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins == null && margin == 0) {
1748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return;
1758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ensureMargins();
1778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mMargins[col * 2 + 1] = margin;
1788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        @Override
1818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public String toString() {
1828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            String result = "LayoutRecord{c=" + column + ", id=" + id + " h=" + height +
1838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    " s=" + span;
1848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mMargins != null) {
1858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                result += " margins[above, below](";
1868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int i = 0; i < mMargins.length; i += 2) {
1878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    result += "[" + mMargins[i] + ", " + mMargins[i+1] + "]";
1888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
1898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                result += ")";
1908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
1918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return result + "}";
1928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
1938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
1948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final SparseArrayCompat<LayoutRecord> mLayoutRecords =
1958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            new SparseArrayCompat<LayoutRecord>();
1968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
1978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public StaggeredGridView(Context context) {
1988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        this(context, null);
1998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public StaggeredGridView(Context context, AttributeSet attrs) {
2028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        this(context, attrs, 0);
2038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public StaggeredGridView(Context context, AttributeSet attrs, int defStyle) {
2068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        super(context, attrs, defStyle);
2078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final ViewConfiguration vc = ViewConfiguration.get(context);
2098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mTouchSlop = vc.getScaledTouchSlop();
2108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mMaximumVelocity = vc.getScaledMaximumFlingVelocity();
2118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mFlingVelocity = vc.getScaledMinimumFlingVelocity();
2128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mScroller = ScrollerCompat.from(context);
2138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mTopEdge = new EdgeEffectCompat(context);
2158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mBottomEdge = new EdgeEffectCompat(context);
2168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        setWillNotDraw(false);
2178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        setClipToPadding(false);
2188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
2218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Set a fixed number of columns for this grid. Space will be divided evenly
2228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * among all columns, respecting the item margin between columns.
2238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * The default is 2. (If it were 1, perhaps you should be using a
2248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * {@link android.widget.ListView ListView}.)
2258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
2268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param colCount Number of columns to display.
2278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @see #setMinColumnWidth(int)
2288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
2298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void setColumnCount(int colCount) {
2308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (colCount < 1 && colCount != COLUMN_COUNT_AUTO) {
2318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            throw new IllegalArgumentException("Column count must be at least 1 - received " +
2328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    colCount);
2338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
2348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final boolean needsPopulate = colCount != mColCount;
2358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mColCount = mColCountSetting = colCount;
2368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (needsPopulate) {
2378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            populate();
2388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
2398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public int getColumnCount() {
2428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return mColCount;
2438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
2468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Set a minimum column width for
2478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param minColWidth
2488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
2498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void setMinColumnWidth(int minColWidth) {
2508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mMinColWidth = minColWidth;
2518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        setColumnCount(COLUMN_COUNT_AUTO);
2528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
2558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Set the margin between items in pixels. This margin is applied
2568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * both vertically and horizontally.
2578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
2588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param marginPixels Spacing between items in pixels
2598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
2608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void setItemMargin(int marginPixels) {
2618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final boolean needsPopulate = marginPixels != mItemMargin;
2628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mItemMargin = marginPixels;
2638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (needsPopulate) {
2648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            populate();
2658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
2668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
2698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Return the first adapter position with a view currently attached as
2708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * a child view of this grid.
2718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
2728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return the adapter position represented by the view at getChildAt(0).
2738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
2748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public int getFirstPosition() {
2758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return mFirstPosition;
2768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
2778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
2798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public boolean onInterceptTouchEvent(MotionEvent ev) {
2808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mVelocityTracker.addMovement(ev);
2818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
2828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        switch (action) {
2838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_DOWN:
2848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mVelocityTracker.clear();
2858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mScroller.abortAnimation();
2868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mLastTouchY = ev.getY();
2878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
2888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchRemainderY = 0;
2898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mTouchMode == TOUCH_MODE_FLINGING) {
2908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    // Catch!
2918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTouchMode = TOUCH_MODE_DRAGGING;
2928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    return true;
2938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
2948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                break;
2958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
2968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_MOVE: {
2978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
2988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (index < 0) {
2998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
3008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
3018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            "event stream?");
3028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    return false;
3038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final float y = MotionEventCompat.getY(ev, index);
3058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final float dy = y - mLastTouchY + mTouchRemainderY;
3068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int deltaY = (int) dy;
3078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchRemainderY = dy - deltaY;
3088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (Math.abs(dy) > mTouchSlop) {
3108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTouchMode = TOUCH_MODE_DRAGGING;
3118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    return true;
3128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
3148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
3158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return false;
3178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
3188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
3208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public boolean onTouchEvent(MotionEvent ev) {
3218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mVelocityTracker.addMovement(ev);
3228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
3238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        switch (action) {
3248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_DOWN:
3258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mVelocityTracker.clear();
3268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mScroller.abortAnimation();
3278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mLastTouchY = ev.getY();
3288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
3298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchRemainderY = 0;
3308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                break;
3318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_MOVE: {
3338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
3348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (index < 0) {
3358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
3368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
3378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            "event stream?");
3388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    return false;
3398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final float y = MotionEventCompat.getY(ev, index);
3418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final float dy = y - mLastTouchY + mTouchRemainderY;
3428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int deltaY = (int) dy;
3438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchRemainderY = dy - deltaY;
3448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (Math.abs(dy) > mTouchSlop) {
3468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTouchMode = TOUCH_MODE_DRAGGING;
3478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mTouchMode == TOUCH_MODE_DRAGGING) {
3508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mLastTouchY = y;
3518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (!trackMotionScroll(deltaY, true)) {
3538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        // Break fling velocity if we impacted an edge.
3548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        mVelocityTracker.clear();
3558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
3568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } break;
3588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_CANCEL:
3608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchMode = TOUCH_MODE_IDLE;
3618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                break;
3628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            case MotionEvent.ACTION_UP: {
3648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
3658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final float velocity = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
3668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        mActivePointerId);
3678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (Math.abs(velocity) > mFlingVelocity) { // TODO
3688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTouchMode = TOUCH_MODE_FLINGING;
3698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mScroller.fling(0, 0, 0, (int) velocity, 0, 0,
3708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            Integer.MIN_VALUE, Integer.MAX_VALUE);
3718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mLastTouchY = 0;
3728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    ViewCompat.postInvalidateOnAnimation(this);
3738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                } else {
3748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTouchMode = TOUCH_MODE_IDLE;
3758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
3768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } break;
3788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
3798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return true;
3808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
3818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
3838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
3848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param deltaY Pixels that content should move by
3858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return true if the movement completed, false if it was stopped prematurely.
3868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
3878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private boolean trackMotionScroll(int deltaY, boolean allowOverScroll) {
3888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final boolean contentFits = contentFits();
3898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int allowOverhang = Math.abs(deltaY);
3908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
3918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int overScrolledBy;
3928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int movedBy;
3938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (!contentFits) {
3948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int overhang;
3958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final boolean up;
3968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mPopulating = true;
3978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (deltaY > 0) {
3988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                overhang = fillUp(mFirstPosition - 1, allowOverhang);
3998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                up = true;
4008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
4018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                overhang = fillDown(mFirstPosition + getChildCount(), allowOverhang) + mItemMargin;
4028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                up = false;
4038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            movedBy = Math.min(overhang, allowOverhang);
4058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            offsetChildren(up ? movedBy : -movedBy);
4068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            recycleOffscreenViews();
4078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mPopulating = false;
4088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            overScrolledBy = allowOverhang - overhang;
4098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        } else {
4108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            overScrolledBy = allowOverhang;
4118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            movedBy = 0;
4128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (allowOverScroll) {
4158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int overScrollMode = ViewCompat.getOverScrollMode(this);
4168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
4188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits)) {
4198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (overScrolledBy > 0) {
4218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    EdgeEffectCompat edge = deltaY > 0 ? mTopEdge : mBottomEdge;
4228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    edge.onPull((float) Math.abs(deltaY) / getHeight());
4238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    ViewCompat.postInvalidateOnAnimation(this);
4248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
4258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return deltaY == 0 || movedBy != 0;
4298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
4308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private final boolean contentFits() {
4328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mFirstPosition != 0 || getChildCount() != mItemCount) {
4338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return false;
4348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int topmost = Integer.MAX_VALUE;
4378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int bottommost = Integer.MIN_VALUE;
4388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
4398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mItemTops[i] < topmost) {
4408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                topmost = mItemTops[i];
4418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mItemBottoms[i] > bottommost) {
4438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                bottommost = mItemBottoms[i];
4448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return topmost >= getPaddingTop() && bottommost <= getHeight() - getPaddingBottom();
4488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
4498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void recycleAllViews() {
4518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < getChildCount(); i++) {
4528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.addScrap(getChildAt(i));
4538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mInLayout) {
4568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            removeAllViewsInLayout();
4578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        } else {
4588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            removeAllViews();
4598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
4618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
4638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Important: this method will leave offscreen views attached if they
4648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * are required to maintain the invariant that child view with index i
4658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * is always the view corresponding to position mFirstPosition + i.
4668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
4678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void recycleOffscreenViews() {
4688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int height = getHeight();
4698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int clearAbove = -mItemMargin;
4708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int clearBelow = height + mItemMargin;
4718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = getChildCount() - 1; i >= 0; i--) {
4728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View child = getChildAt(i);
4738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (child.getTop() <= clearBelow)  {
4748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // There may be other offscreen views, but we need to maintain
4758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // the invariant documented above.
4768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                break;
4778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mInLayout) {
4808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeViewsInLayout(i, 1);
4818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
4828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeViewAt(i);
4838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.addScrap(child);
4868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
4878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        while (getChildCount() > 0) {
4898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View child = getChildAt(0);
4908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (child.getBottom() >= clearAbove) {
4918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // There may be other offscreen views, but we need to maintain
4928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // the invariant documented above.
4938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                break;
4948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
4958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
4968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mInLayout) {
4978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeViewsInLayout(0, 1);
4988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
4998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeViewAt(0);
5008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.addScrap(child);
5038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mFirstPosition++;
5048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
5058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int childCount = getChildCount();
5078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (childCount > 0) {
5088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            // Repair the top and bottom column boundaries from the views we still have
5098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Arrays.fill(mItemTops, Integer.MAX_VALUE);
5108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Arrays.fill(mItemBottoms, Integer.MIN_VALUE);
5118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = 0; i < childCount; i++){
5138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final View child = getChildAt(i);
5148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
5158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int top = child.getTop() - mItemMargin;
5168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int bottom = child.getBottom();
5178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final LayoutRecord rec = mLayoutRecords.get(mFirstPosition + i);
5188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int colEnd = lp.column + Math.min(mColCount, lp.span);
5208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int col = lp.column; col < colEnd; col++) {
5218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int colTop = top - rec.getMarginAbove(col - lp.column);
5228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int colBottom = bottom + rec.getMarginBelow(col - lp.column);
5238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (colTop < mItemTops[col]) {
5248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        mItemTops[col] = colTop;
5258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
5268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (colBottom > mItemBottoms[col]) {
5278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        mItemBottoms[col] = colBottom;
5288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
5298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
5308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int col = 0; col < mColCount; col++) {
5338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mItemTops[col] == Integer.MAX_VALUE) {
5348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    // If one was untouched, both were.
5358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mItemTops[col] = 0;
5368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mItemBottoms[col] = 0;
5378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
5388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
5408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
5418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void computeScroll() {
5438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mScroller.computeScrollOffset()) {
5448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int y = mScroller.getCurrY();
5458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int dy = (int) (y - mLastTouchY);
5468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mLastTouchY = y;
5478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final boolean stopped = !trackMotionScroll(dy, false);
5488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!stopped && !mScroller.isFinished()) {
5508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                ViewCompat.postInvalidateOnAnimation(this);
5518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
5528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (stopped) {
5538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int overScrollMode = ViewCompat.getOverScrollMode(this);
5548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (overScrollMode != ViewCompat.OVER_SCROLL_NEVER) {
5558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        final EdgeEffectCompat edge;
5568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        if (dy > 0) {
5578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            edge = mTopEdge;
5588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        } else {
5598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                            edge = mBottomEdge;
5608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        }
5618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity()));
5628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        ViewCompat.postInvalidateOnAnimation(this);
5638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
5648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mScroller.abortAnimation();
5658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
5668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTouchMode = TOUCH_MODE_IDLE;
5678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
5698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
5708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
5728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void draw(Canvas canvas) {
5738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        super.draw(canvas);
5748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mTopEdge != null) {
5768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            boolean needsInvalidate = false;
5778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!mTopEdge.isFinished()) {
5788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTopEdge.draw(canvas);
5798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                needsInvalidate = true;
5808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!mBottomEdge.isFinished()) {
5828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int restoreCount = canvas.save();
5838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int width = getWidth();
5848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                canvas.translate(-width, getHeight());
5858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                canvas.rotate(180, width, 0);
5868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mBottomEdge.draw(canvas);
5878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                canvas.restoreToCount(restoreCount);
5888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                needsInvalidate = true;
5898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (needsInvalidate) {
5928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                ViewCompat.postInvalidateOnAnimation(this);
5938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
5948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
5958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
5968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
5978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void beginFastChildLayout() {
5988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mFastChildLayout = true;
5998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void endFastChildLayout() {
6028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mFastChildLayout = false;
6038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        populate();
6048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
6078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void requestLayout() {
6088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (!mPopulating && !mFastChildLayout) {
6098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super.requestLayout();
6108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
6148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
6158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
6168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
6178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
6188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
6198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (widthMode != MeasureSpec.EXACTLY) {
6218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Log.e(TAG, "onMeasure: must have an exact width or match_parent! " +
6228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    "Using fallback spec of EXACTLY " + widthSize);
6238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            widthMode = MeasureSpec.EXACTLY;
6248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (heightMode != MeasureSpec.EXACTLY) {
6268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Log.e(TAG, "onMeasure: must have an exact height or match_parent! " +
6278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    "Using fallback spec of EXACTLY " + heightSize);
6288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            heightMode = MeasureSpec.EXACTLY;
6298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        setMeasuredDimension(widthSize, heightSize);
6328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mColCountSetting == COLUMN_COUNT_AUTO) {
6348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int colCount = widthSize / mMinColWidth;
6358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (colCount != mColCount) {
6368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mColCount = colCount;
6378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mForcePopulateOnLayout = true;
6388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
6398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
6438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    protected void onLayout(boolean changed, int l, int t, int r, int b) {
6448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mInLayout = true;
6458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        populate();
6468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mInLayout = false;
6478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mForcePopulateOnLayout = false;
6488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int width = r - l;
6508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int height = b - t;
6518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mTopEdge.setSize(width, height);
6528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mBottomEdge.setSize(width, height);
6538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void populate() {
6568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (getWidth() == 0 || getHeight() == 0) {
6578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return;
6588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mColCount == COLUMN_COUNT_AUTO) {
6618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int colCount = getWidth() / mMinColWidth;
6628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (colCount != mColCount) {
6638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mColCount = colCount;
6648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
6658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
6688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mItemTops == null || mItemTops.length != colCount) {
6698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemTops = new int[colCount];
6708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemBottoms = new int[colCount];
6718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int top = getPaddingTop();
6728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int offset = top + Math.min(mRestoreOffset, 0);
6738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Arrays.fill(mItemTops, offset);
6748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Arrays.fill(mItemBottoms, offset);
6758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mLayoutRecords.clear();
6768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mInLayout) {
6778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeAllViewsInLayout();
6788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
6798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                removeAllViews();
6808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
6818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRestoreOffset = 0;
6828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
6838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mPopulating = true;
6858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        layoutChildren(mDataChanged);
6868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        fillDown(mFirstPosition + getChildCount(), 0);
6878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        fillUp(mFirstPosition - 1, 0);
6888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mPopulating = false;
6898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mDataChanged = false;
6908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
6918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
6928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void dumpItemPositions() {
6938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int childCount = getChildCount();
6948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Log.d(TAG, "dumpItemPositions:");
6958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Log.d(TAG, " => Tops:");
6968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
6978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Log.d(TAG, "  => " + mItemTops[i]);
6988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            boolean found = false;
6998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int j = 0; j < childCount; j++) {
7008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final View child = getChildAt(j);
7018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mItemTops[i] == child.getTop() - mItemMargin) {
7028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    found = true;
7038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
7048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!found) {
7068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.d(TAG, "!!! No top item found for column " + i + " value " + mItemTops[i]);
7078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
7098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Log.d(TAG, " => Bottoms:");
7108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
7118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            Log.d(TAG, "  => " + mItemBottoms[i]);
7128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            boolean found = false;
7138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int j = 0; j < childCount; j++) {
7148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final View child = getChildAt(j);
7158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mItemBottoms[i] == child.getBottom()) {
7168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    found = true;
7178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
7188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!found) {
7208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.d(TAG, "!!! No bottom item found for column " + i + " value " + mItemBottoms[i]);
7218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
7238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
7248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final void offsetChildren(int offset) {
7268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int childCount = getChildCount();
7278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < childCount; i++) {
7288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View child = getChildAt(i);
7298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.layout(child.getLeft(), child.getTop() + offset,
7308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    child.getRight(), child.getBottom() + offset);
7318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
7328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
7348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < colCount; i++) {
7358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemTops[i] += offset;
7368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemBottoms[i] += offset;
7378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
7388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
7398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
7418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Measure and layout all currently visible children.
7428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
7438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param queryAdapter true to requery the adapter for view data
7448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
7458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final void layoutChildren(boolean queryAdapter) {
7468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingLeft = getPaddingLeft();
7478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingRight = getPaddingRight();
7488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int itemMargin = mItemMargin;
7498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colWidth =
7508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
7518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int rebuildLayoutRecordsBefore = -1;
7528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int rebuildLayoutRecordsAfter = -1;
7538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Arrays.fill(mItemBottoms, Integer.MIN_VALUE);
7558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int childCount = getChildCount();
7578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < childCount; i++) {
7588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            View child = getChildAt(i);
7598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            LayoutParams lp = (LayoutParams) child.getLayoutParams();
7608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int col = lp.column;
7618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int position = mFirstPosition + i;
7628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final boolean needsLayout = queryAdapter || child.isLayoutRequested();
7638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (queryAdapter) {
7658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                View newView = obtainView(position, child);
7668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (newView != child) {
7678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    removeViewAt(i);
7688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    addView(newView, i);
7698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    child = newView;
7708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
7718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lp = (LayoutParams) child.getLayoutParams(); // Might have changed
7728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int span = Math.min(mColCount, lp.span);
7758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int widthSize = colWidth * span + itemMargin * (span - 1);
7768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (needsLayout) {
7788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
7798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int heightSpec;
7818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (lp.height == LayoutParams.WRAP_CONTENT) {
7828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
7838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                } else {
7848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
7858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
7868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                child.measure(widthSpec, heightSpec);
7888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
7898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
7908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            int childTop = mItemBottoms[col] > Integer.MIN_VALUE ?
7918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mItemBottoms[col] + mItemMargin : child.getTop();
7928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (span > 1) {
7938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                int lowest = childTop;
7948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int j = col + 1; j < col + span; j++) {
7958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int bottom = mItemBottoms[j] + mItemMargin;
7968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (bottom > lowest) {
7978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        lowest = bottom;
7988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
7998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
8008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                childTop = lowest;
8018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childHeight = child.getMeasuredHeight();
8038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childBottom = childTop + childHeight;
8048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childLeft = paddingLeft + col * (colWidth + itemMargin);
8058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childRight = childLeft + child.getMeasuredWidth();
8068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.layout(childLeft, childTop, childRight, childBottom);
8078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int j = col; j < col + span; j++) {
8098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mItemBottoms[j] = childBottom;
8108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final LayoutRecord rec = mLayoutRecords.get(position);
8138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rec != null && rec.height != childHeight) {
8148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // Invalidate our layout records for everything before this.
8158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.height = childHeight;
8168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rebuildLayoutRecordsBefore = position;
8178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rec != null && rec.span != span) {
8208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // Invalidate our layout records for everything after this.
8218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = span;
8228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rebuildLayoutRecordsAfter = position;
8238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
8258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Update mItemBottoms for any empty columns
8278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
8288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mItemBottoms[i] == Integer.MIN_VALUE) {
8298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mItemBottoms[i] = mItemTops[i];
8308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
8328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (rebuildLayoutRecordsBefore >= 0 || rebuildLayoutRecordsAfter >= 0) {
8348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rebuildLayoutRecordsBefore >= 0) {
8358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateLayoutRecordsBeforePosition(rebuildLayoutRecordsBefore);
8368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rebuildLayoutRecordsAfter >= 0) {
8388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateLayoutRecordsAfterPosition(rebuildLayoutRecordsAfter);
8398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = 0; i < childCount; i++) {
8418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int position = mFirstPosition + i;
8428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final View child = getChildAt(i);
8438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
8448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                LayoutRecord rec = mLayoutRecords.get(position);
8458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (rec == null) {
8468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    rec = new LayoutRecord();
8478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mLayoutRecords.put(position, rec);
8488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
8498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.column = lp.column;
8508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.height = child.getHeight();
8518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.id = lp.id;
8528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = Math.min(mColCount, lp.span);
8538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
8548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
8558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
8568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final void invalidateLayoutRecordsBeforePosition(int position) {
8588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int endAt = 0;
8598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        while (endAt < mLayoutRecords.size() && mLayoutRecords.keyAt(endAt) < position) {
8608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            endAt++;
8618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
8628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mLayoutRecords.removeAtRange(0, endAt);
8638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
8648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final void invalidateLayoutRecordsAfterPosition(int position) {
8668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int beginAt = mLayoutRecords.size() - 1;
8678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        while (beginAt >= 0 && mLayoutRecords.keyAt(beginAt) > position) {
8688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            beginAt--;
8698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
8708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        beginAt++;
8718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mLayoutRecords.removeAtRange(beginAt + 1, mLayoutRecords.size() - beginAt);
8728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
8738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
8758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Should be called with mPopulating set to true
8768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
8778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param fromPosition Position to start filling from
8788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param overhang the number of extra pixels to fill beyond the current top edge
8798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return the max overhang beyond the beginning of the view of any added items at the top
8808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
8818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final int fillUp(int fromPosition, int overhang) {
8828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingLeft = getPaddingLeft();
8838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingRight = getPaddingRight();
8848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int itemMargin = mItemMargin;
8858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colWidth =
8868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
8878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int gridTop = getPaddingTop();
8888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int fillTo = gridTop - overhang;
8898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int nextCol = getNextColumnUp();
8908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int position = fromPosition;
8918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        while (nextCol >= 0 && mItemTops[nextCol] > fillTo && position >= 0) {
8938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View child = obtainView(position, null);
8948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            LayoutParams lp = (LayoutParams) child.getLayoutParams();
8958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
8968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (child.getParent() != this) {
8978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mInLayout) {
8988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    addViewInLayout(child, 0, lp);
8998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                } else {
9008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    addView(child, 0);
9018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
9028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int span = Math.min(mColCount, lp.span);
9058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int widthSize = colWidth * span + itemMargin * (span - 1);
9068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
9078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            LayoutRecord rec;
9098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (span > 1) {
9108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = getNextRecordUp(position, span);
9118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                nextCol = rec.column;
9128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
9138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = mLayoutRecords.get(position);
9148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            boolean invalidateBefore = false;
9178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rec == null) {
9188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = new LayoutRecord();
9198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mLayoutRecords.put(position, rec);
9208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.column = nextCol;
9218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = span;
9228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else if (span != rec.span) {
9238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = span;
9248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.column = nextCol;
9258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateBefore = true;
9268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
9278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                nextCol = rec.column;
9288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mHasStableIds) {
9318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final long id = mAdapter.getItemId(position);
9328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.id = id;
9338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lp.id = id;
9348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            lp.column = nextCol;
9378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int heightSpec;
9398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (lp.height == LayoutParams.WRAP_CONTENT) {
9408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
9418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
9428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
9438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.measure(widthSpec, heightSpec);
9458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childHeight = child.getMeasuredHeight();
9478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (invalidateBefore || (childHeight != rec.height && rec.height > 0)) {
9488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateLayoutRecordsBeforePosition(position);
9498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.height = childHeight;
9518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int startFrom;
9538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (span > 1) {
9548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                int highest = mItemTops[nextCol];
9558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int i = nextCol + 1; i < nextCol + span; i++) {
9568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int top = mItemTops[i];
9578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (top < highest) {
9588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        highest = top;
9598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
9608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
9618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                startFrom = highest;
9628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
9638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                startFrom = mItemTops[nextCol];
9648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childBottom = startFrom;
9668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childTop = childBottom - childHeight;
9678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin);
9688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childRight = childLeft + child.getMeasuredWidth();
9698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.layout(childLeft, childTop, childRight, childBottom);
9708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = nextCol; i < nextCol + span; i++) {
9728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mItemTops[i] = childTop - rec.getMarginAbove(i - nextCol) - itemMargin;
9738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            nextCol = getNextColumnUp();
9768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mFirstPosition = position--;
9778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
9788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int highestView = getHeight();
9808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
9818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mItemTops[i] < highestView) {
9828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                highestView = mItemTops[i];
9838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
9848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
9858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return gridTop - highestView;
9868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
9878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
9888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
9898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Should be called with mPopulating set to true
9908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
9918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param fromPosition Position to start filling from
9928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param overhang the number of extra pixels to fill beyond the current bottom edge
9938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return the max overhang beyond the end of the view of any added items at the bottom
9948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
9958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final int fillDown(int fromPosition, int overhang) {
9968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingLeft = getPaddingLeft();
9978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int paddingRight = getPaddingRight();
9988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int itemMargin = mItemMargin;
9998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colWidth =
10008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
10018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int gridBottom = getHeight() - getPaddingBottom();
10028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int fillTo = gridBottom + overhang;
10038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int nextCol = getNextColumnDown();
10048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int position = fromPosition;
10058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        while (nextCol >= 0 && mItemBottoms[nextCol] < fillTo && position < mItemCount) {
10078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View child = obtainView(position, null);
10088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            LayoutParams lp = (LayoutParams) child.getLayoutParams();
10098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (child.getParent() != this) {
10118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mInLayout) {
10128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    addViewInLayout(child, -1, lp);
10138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                } else {
10148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    addView(child);
10158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
10168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int span = Math.min(mColCount, lp.span);
10198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int widthSize = colWidth * span + itemMargin * (span - 1);
10208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
10218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            LayoutRecord rec;
10238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (span > 1) {
10248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = getNextRecordDown(position, span);
10258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                nextCol = rec.column;
10268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
10278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = mLayoutRecords.get(position);
10288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            boolean invalidateAfter = false;
10318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (rec == null) {
10328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec = new LayoutRecord();
10338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mLayoutRecords.put(position, rec);
10348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.column = nextCol;
10358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = span;
10368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else if (span != rec.span) {
10378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.span = span;
10388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.column = nextCol;
10398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateAfter = true;
10408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
10418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                nextCol = rec.column;
10428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mHasStableIds) {
10458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final long id = mAdapter.getItemId(position);
10468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                rec.id = id;
10478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lp.id = id;
10488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            lp.column = nextCol;
10518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int heightSpec;
10538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (lp.height == LayoutParams.WRAP_CONTENT) {
10548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
10558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
10568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
10578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.measure(widthSpec, heightSpec);
10598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childHeight = child.getMeasuredHeight();
10618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (invalidateAfter || (childHeight != rec.height && rec.height > 0)) {
10628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                invalidateLayoutRecordsAfterPosition(position);
10638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.height = childHeight;
10658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int startFrom;
10678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (span > 1) {
10688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                int lowest = mItemBottoms[nextCol];
10698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int i = nextCol + 1; i < nextCol + span; i++) {
10708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    final int bottom = mItemBottoms[i];
10718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    if (bottom > lowest) {
10728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        lowest = bottom;
10738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    }
10748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
10758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                startFrom = lowest;
10768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else {
10778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                startFrom = mItemBottoms[nextCol];
10788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childTop = startFrom + itemMargin;
10808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childBottom = childTop + childHeight;
10818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin);
10828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childRight = childLeft + child.getMeasuredWidth();
10838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            child.layout(childLeft, childTop, childRight, childBottom);
10848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = nextCol; i < nextCol + span; i++) {
10868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mItemBottoms[i] = childBottom + rec.getMarginBelow(i - nextCol);
10878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            nextCol = getNextColumnDown();
10908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            position++;
10918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
10928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
10938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int lowestView = 0;
10948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < mColCount; i++) {
10958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mItemBottoms[i] > lowestView) {
10968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lowestView = mItemBottoms[i];
10978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
10988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
10998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return lowestView - gridBottom;
11008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
11018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
11038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return column that the next view filling upwards should occupy. This is the bottom-most
11048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *         position available for a single-column item.
11058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
11068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final int getNextColumnUp() {
11078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int result = -1;
11088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int bottomMost = Integer.MIN_VALUE;
11098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
11118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = colCount - 1; i >= 0; i--) {
11128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int top = mItemTops[i];
11138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (top > bottomMost) {
11148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                bottomMost = top;
11158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                result = i;
11168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
11178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return result;
11198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
11208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
11228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Return a LayoutRecord for the given position
11238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param position
11248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param span
11258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return
11268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
11278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final LayoutRecord getNextRecordUp(int position, int span) {
11288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        LayoutRecord rec = mLayoutRecords.get(position);
11298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (rec == null) {
11308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec = new LayoutRecord();
11318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.span = span;
11328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mLayoutRecords.put(position, rec);
11338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        } else if (rec.span != span) {
11348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span +
11358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    " but caller requested span=" + span + " for position=" + position);
11368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int targetCol = -1;
11388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int bottomMost = Integer.MIN_VALUE;
11398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
11418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = colCount - span; i >= 0; i--) {
11428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            int top = Integer.MAX_VALUE;
11438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int j = i; j < i + span; j++) {
11448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int singleTop = mItemTops[j];
11458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (singleTop < top) {
11468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    top = singleTop;
11478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
11488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
11498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (top > bottomMost) {
11508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                bottomMost = top;
11518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                targetCol = i;
11528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
11538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        rec.column = targetCol;
11568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < span; i++) {
11588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.setMarginBelow(i, mItemTops[i + targetCol] - bottomMost);
11598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return rec;
11628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
11638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
11658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return column that the next view filling downwards should occupy. This is the top-most
11668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *         position available.
11678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
11688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final int getNextColumnDown() {
11698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int result = -1;
11708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int topMost = Integer.MAX_VALUE;
11718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
11738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < colCount; i++) {
11748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int bottom = mItemBottoms[i];
11758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (bottom < topMost) {
11768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                topMost = bottom;
11778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                result = i;
11788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
11798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return result;
11818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
11828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final LayoutRecord getNextRecordDown(int position, int span) {
11848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        LayoutRecord rec = mLayoutRecords.get(position);
11858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (rec == null) {
11868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec = new LayoutRecord();
11878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.span = span;
11888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mLayoutRecords.put(position, rec);
11898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        } else if (rec.span != span) {
11908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span +
11918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    " but caller requested span=" + span + " for position=" + position);
11928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
11938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int targetCol = -1;
11948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int topMost = Integer.MAX_VALUE;
11958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
11968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
11978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i <= colCount - span; i++) {
11988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            int bottom = Integer.MIN_VALUE;
11998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int j = i; j < i + span; j++) {
12008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int singleBottom = mItemBottoms[j];
12018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (singleBottom > bottom) {
12028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    bottom = singleBottom;
12038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
12048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
12058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (bottom < topMost) {
12068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                topMost = bottom;
12078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                targetCol = i;
12088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
12098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        rec.column = targetCol;
12128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        for (int i = 0; i < span; i++) {
12148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            rec.setMarginAbove(i, topMost - mItemBottoms[i + targetCol]);
12158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return rec;
12188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
12198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
12218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Obtain a populated view from the adapter. If optScrap is non-null and is not
12228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * reused it will be placed in the recycle bin.
12238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     *
12248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param position position to get view for
12258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @param optScrap Optional scrap view; will be reused if possible
12268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * @return A new view, a recycled view from mRecycler, or optScrap
12278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
12288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    final View obtainView(int position, View optScrap) {
12298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        View view = mRecycler.getTransientStateView(position);
12308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (view != null) {
12318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return view;
12328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Reuse optScrap if it's of the right type (and not null)
12358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int optType = optScrap != null ?
12368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                ((LayoutParams) optScrap.getLayoutParams()).viewType : -1;
12378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int positionViewType = mAdapter.getItemViewType(position);
12388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final View scrap = optType == positionViewType ?
12398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                optScrap : mRecycler.getScrapView(positionViewType);
12408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        view = mAdapter.getView(position, scrap, this);
12428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (view != scrap && scrap != null) {
12448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            // The adapter didn't use it; put it back.
12458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.addScrap(scrap);
12468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        ViewGroup.LayoutParams lp = view.getLayoutParams();
12498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (view.getParent() != this) {
12518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (lp == null) {
12528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lp = generateDefaultLayoutParams();
12538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            } else if (!checkLayoutParams(lp)) {
12548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                lp = generateLayoutParams(lp);
12558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
12568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final LayoutParams sglp = (LayoutParams) lp;
12598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        sglp.position = position;
12608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        sglp.viewType = positionViewType;
12618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return view;
12638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
12648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public ListAdapter getAdapter() {
12668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return mAdapter;
12678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
12688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void setAdapter(ListAdapter adapter) {
12708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mAdapter != null) {
12718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mAdapter.unregisterDataSetObserver(mObserver);
12728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // TODO: If the new adapter says that there are stable IDs, remove certain layout records
12748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // and onscreen views if they have changed instead of removing all of the state here.
12758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        clearAllState();
12768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mAdapter = adapter;
12778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mDataChanged = true;
12788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mOldItemCount = mItemCount = adapter != null ? adapter.getCount() : 0;
12798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (adapter != null) {
12808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            adapter.registerDataSetObserver(mObserver);
12818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.setViewTypeCount(adapter.getViewTypeCount());
12828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mHasStableIds = adapter.hasStableIds();
12838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        } else {
12848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mHasStableIds = false;
12858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
12868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        populate();
12878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
12888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
12908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Clear all state because the grid will be used for a completely different set of data.
12918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
12928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void clearAllState() {
12938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Clear all layout records and views
12948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mLayoutRecords.clear();
12958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        removeAllViews();
12968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
12978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Reset to the top of the grid
12988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        resetStateForGridTop();
12998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Clear recycler because there could be different view types now
13018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mRecycler.clear();
13028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
13058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Reset all internal state to be at the top of the grid.
13068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
13078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private void resetStateForGridTop() {
13088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Reset mItemTops and mItemBottoms
13098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int colCount = mColCount;
13108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (mItemTops == null || mItemTops.length != colCount) {
13118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemTops = new int[colCount];
13128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemBottoms = new int[colCount];
13138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
13148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int top = getPaddingTop();
13158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Arrays.fill(mItemTops, top);
13168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        Arrays.fill(mItemBottoms, top);
13178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Reset the first visible position in the grid to be item 0
13198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mFirstPosition = 0;
13208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mRestoreOffset = 0;
13218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    /**
13248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     * Scroll the list so the first visible position in the grid is the first item in the adapter.
13258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang     */
13268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void setSelectionToTop() {
13278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Clear out the views (but don't clear out the layout records or recycler because the data
13288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // has not changed)
13298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        removeAllViews();
13308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Reset to top of grid
13328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        resetStateForGridTop();
13338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        // Start populating again
13358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        populate();
13368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    protected LayoutParams generateDefaultLayoutParams() {
13408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return new LayoutParams(LayoutParams.WRAP_CONTENT);
13418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
13458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return new LayoutParams(lp);
13468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) {
13508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return lp instanceof LayoutParams;
13518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
13558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return new LayoutParams(getContext(), attrs);
13568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public Parcelable onSaveInstanceState() {
13608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final Parcelable superState = super.onSaveInstanceState();
13618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final SavedState ss = new SavedState(superState);
13628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        final int position = mFirstPosition;
13638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        ss.position = position;
13648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (position >= 0 && mAdapter != null && position < mAdapter.getCount()) {
13658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ss.firstId = mAdapter.getItemId(position);
13668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
13678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        if (getChildCount() > 0) {
13688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ss.topOffset = getChildAt(0).getTop() - mItemMargin - getPaddingTop();
13698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
13708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        return ss;
13718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    @Override
13748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public void onRestoreInstanceState(Parcelable state) {
13758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        SavedState ss = (SavedState) state;
13768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        super.onRestoreInstanceState(ss.getSuperState());
13778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mDataChanged = true;
13788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mFirstPosition = ss.position;
13798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        mRestoreOffset = ss.topOffset;
13808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        requestLayout();
13818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
13828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    public static class LayoutParams extends ViewGroup.LayoutParams {
13848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private static final int[] LAYOUT_ATTRS = new int[] {
13858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            android.R.attr.layout_span
13868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        };
13878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private static final int SPAN_INDEX = 0;
13898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        /**
13918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         * The number of columns this item should span
13928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         */
13938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public int span = 1;
13948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
13958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        /**
13968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         * Item position this view represents
13978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         */
13988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int position;
13998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        /**
14018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         * Type of this view as reported by the adapter
14028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         */
14038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int viewType;
14048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        /**
14068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         * The column this view is occupying
14078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         */
14088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int column;
14098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        /**
14118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         * The stable ID of the item this view displays
14128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang         */
14138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        long id = -1;
14148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public LayoutParams(int height) {
14168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super(FILL_PARENT, height);
14178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (this.height == FILL_PARENT) {
14198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.w(TAG, "Constructing LayoutParams with height FILL_PARENT - " +
14208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        "impossible! Falling back to WRAP_CONTENT");
14218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                this.height = WRAP_CONTENT;
14228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public LayoutParams(Context c, AttributeSet attrs) {
14268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super(c, attrs);
14278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (this.width != FILL_PARENT) {
14298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.w(TAG, "Inflation setting LayoutParams width to " + this.width +
14308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        " - must be MATCH_PARENT");
14318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                this.width = FILL_PARENT;
14328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (this.height == FILL_PARENT) {
14348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.w(TAG, "Inflation setting LayoutParams height to MATCH_PARENT - " +
14358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        "impossible! Falling back to WRAP_CONTENT");
14368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                this.height = WRAP_CONTENT;
14378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
14408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            span = a.getInteger(SPAN_INDEX, 1);
14418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            a.recycle();
14428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public LayoutParams(ViewGroup.LayoutParams other) {
14458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super(other);
14468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (this.width != FILL_PARENT) {
14488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.w(TAG, "Constructing LayoutParams with width " + this.width +
14498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        " - must be MATCH_PARENT");
14508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                this.width = FILL_PARENT;
14518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (this.height == FILL_PARENT) {
14538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " +
14548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        "impossible! Falling back to WRAP_CONTENT");
14558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                this.height = WRAP_CONTENT;
14568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
14598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private class RecycleBin {
14618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private ArrayList<View>[] mScrapViews;
14628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private int mViewTypeCount;
14638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private int mMaxScrap;
14648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private SparseArray<View> mTransientStateViews;
14668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void setViewTypeCount(int viewTypeCount) {
14688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (viewTypeCount < 1) {
14698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                throw new IllegalArgumentException("Must have at least one view type (" +
14708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                        viewTypeCount + " types reported)");
14718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (viewTypeCount == mViewTypeCount) {
14738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return;
14748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
14778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = 0; i < viewTypeCount; i++) {
14788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                scrapViews[i] = new ArrayList<View>();
14798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mViewTypeCount = viewTypeCount;
14818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mScrapViews = scrapViews;
14828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void clear() {
14858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int typeCount = mViewTypeCount;
14868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            for (int i = 0; i < typeCount; i++) {
14878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mScrapViews[i].clear();
14888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mTransientStateViews != null) {
14908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTransientStateViews.clear();
14918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
14948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void clearTransientViews() {
14958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mTransientStateViews != null) {
14968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTransientStateViews.clear();
14978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
14988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
14998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void addScrap(View v) {
15018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final LayoutParams lp = (LayoutParams) v.getLayoutParams();
15028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (ViewCompat.hasTransientState(v)) {
15038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                if (mTransientStateViews == null) {
15048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mTransientStateViews = new SparseArray<View>();
15058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
15068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTransientStateViews.put(lp.position, v);
15078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return;
15088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int childCount = getChildCount();
15118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (childCount > mMaxScrap) {
15128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mMaxScrap = childCount;
15138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ArrayList<View> scrap = mScrapViews[lp.viewType];
15168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (scrap.size() < mMaxScrap) {
15178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                scrap.add(v);
15188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public View getTransientStateView(int position) {
15228347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (mTransientStateViews == null) {
15238347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return null;
15248347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15258347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15268347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View result = mTransientStateViews.get(position);
15278347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (result != null) {
15288347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mTransientStateViews.remove(position);
15298347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15308347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return result;
15318347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15328347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15338347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public View getScrapView(int type) {
15348347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            ArrayList<View> scrap = mScrapViews[type];
15358347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (scrap.isEmpty()) {
15368347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return null;
15378347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15388347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15398347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final int index = scrap.size() - 1;
15408347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            final View result = scrap.get(index);
15418347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            scrap.remove(index);
15428347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return result;
15438347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15448347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
15458347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15468347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    private class AdapterDataSetObserver extends DataSetObserver {
15478347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        @Override
15488347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void onChanged() {
15498347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mDataChanged = true;
15508347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mOldItemCount = mItemCount;
15518347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mItemCount = mAdapter.getCount();
15528347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15538347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            // TODO: Consider matching these back up if we have stable IDs.
15548347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            mRecycler.clearTransientViews();
15558347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15568347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            if (!mHasStableIds) {
15578347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // Clear all layout records and recycle the views
15588347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                mLayoutRecords.clear();
15598347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                recycleAllViews();
15608347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15618347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                // Reset item bottoms to be equal to item tops
15628347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                final int colCount = mColCount;
15638347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                for (int i = 0; i < colCount; i++) {
15648347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                    mItemBottoms[i] = mItemTops[i];
15658347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                }
15668347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
15678347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15688347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            // TODO: consider repopulating in a deferred runnable instead
15698347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            // (so that successive changes may still be batched)
15708347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            requestLayout();
15718347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15728347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15738347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        @Override
15748347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void onInvalidated() {
15758347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15768347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
15778347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15788347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    static class SavedState extends BaseSavedState {
15798347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        long firstId = -1;
15808347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int position;
15818347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        int topOffset;
15828347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15838347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        SavedState(Parcelable superState) {
15848347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super(superState);
15858347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15868347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15878347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        private SavedState(Parcel in) {
15888347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super(in);
15898347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            firstId = in.readLong();
15908347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            position = in.readInt();
15918347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            topOffset = in.readInt();
15928347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
15938347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
15948347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        @Override
15958347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public void writeToParcel(Parcel out, int flags) {
15968347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            super.writeToParcel(out, flags);
15978347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            out.writeLong(firstId);
15988347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            out.writeInt(position);
15998347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            out.writeInt(topOffset);
16008347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
16018347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
16028347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        @Override
16038347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public String toString() {
16048347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            return "StaggereGridView.SavedState{"
16058347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang			+ Integer.toHexString(System.identityHashCode(this))
16068347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang			+ " firstId=" + firstId
16078347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang			+ " position=" + position + "}";
16088347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        }
16098347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
16108347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        public static final Parcelable.Creator<SavedState> CREATOR
16118347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                = new Parcelable.Creator<SavedState>() {
16128347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            public SavedState createFromParcel(Parcel in) {
16138347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return new SavedState(in);
16148347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
16158347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang
16168347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            public SavedState[] newArray(int size) {
16178347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang                return new SavedState[size];
16188347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang            }
16198347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang        };
16208347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang    }
16218347d6ca5f1b3f4f1594d3bc16a0be2de4cc214aAlice Yang}
1622