171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck/*
271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Copyright (C) 2013 The Android Open Source Project
371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * you may not use this file except in compliance with the License.
671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * You may obtain a copy of the License at
771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck *
1071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * Unless required by applicable law or agreed to in writing, software
1171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
1271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * See the License for the specific language governing permissions and
1471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck * limitations under the License.
1571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck */
1671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
1771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckpackage com.android.photos.views;
1871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
1971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.content.Context;
2071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.content.res.TypedArray;
2171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.database.DataSetObserver;
2271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.graphics.Canvas;
2371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.support.v4.view.MotionEventCompat;
2471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.support.v4.view.VelocityTrackerCompat;
2571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.support.v4.view.ViewCompat;
2671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.support.v4.widget.EdgeEffectCompat;
2771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.util.AttributeSet;
2871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.util.Log;
2971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.util.SparseArray;
3071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.view.MotionEvent;
3171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.view.VelocityTracker;
3271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.view.View;
3371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.view.ViewConfiguration;
3471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.view.ViewGroup;
3571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.widget.ListAdapter;
3671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport android.widget.OverScroller;
3771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
3871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckimport java.util.ArrayList;
3971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
4071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reckpublic class GalleryThumbnailView extends ViewGroup {
4171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
4271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public interface GalleryThumbnailAdapter extends ListAdapter {
4371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
4471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * @param position Position to get the intrinsic aspect ratio for
4571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * @return width / height
4671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
4771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float getIntrinsicAspectRatio(int position);
4871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
4971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
5071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final String TAG = "GalleryThumbnailView";
5171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final float ASPECT_RATIO = (float) Math.sqrt(1.5f);
5271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final int LAND_UNITS = 2;
5371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final int PORT_UNITS = 3;
5471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
5571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private GalleryThumbnailAdapter mAdapter;
5671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
5771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final RecycleBin mRecycler = new RecycleBin();
5871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
5971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final AdapterDataSetObserver mObserver = new AdapterDataSetObserver();
6071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
6171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean mDataChanged;
6271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mOldItemCount;
6371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mItemCount;
6471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean mHasStableIds;
6571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
6671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mFirstPosition;
6771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
6871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean mPopulating;
6971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean mInLayout;
7071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
7171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mTouchSlop;
7271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mMaximumVelocity;
7371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mFlingVelocity;
7471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private float mLastTouchX;
7571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private float mTouchRemainderX;
7671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mActivePointerId;
7771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
7871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final int TOUCH_MODE_IDLE = 0;
7971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final int TOUCH_MODE_DRAGGING = 1;
8071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private static final int TOUCH_MODE_FLINGING = 2;
8171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
8271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mTouchMode;
8371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
8471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final OverScroller mScroller;
8571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
8671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final EdgeEffectCompat mLeftEdge;
8771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final EdgeEffectCompat mRightEdge;
8871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
8971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mLargeColumnWidth;
9071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mSmallColumnWidth;
9171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mLargeColumnUnitCount = 8;
9271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int mSmallColumnUnitCount = 10;
9371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
9471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public GalleryThumbnailView(Context context) {
9571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        this(context, null);
9671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
9771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
9871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public GalleryThumbnailView(Context context, AttributeSet attrs) {
9971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        this(context, attrs, 0);
10071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
10171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
10271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public GalleryThumbnailView(Context context, AttributeSet attrs, int defStyle) {
10371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        super(context, attrs, defStyle);
10471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
10571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final ViewConfiguration vc = ViewConfiguration.get(context);
10671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mTouchSlop = vc.getScaledTouchSlop();
10771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mMaximumVelocity = vc.getScaledMaximumFlingVelocity();
10871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mFlingVelocity = vc.getScaledMinimumFlingVelocity();
10971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mScroller = new OverScroller(context);
11071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
11171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mLeftEdge = new EdgeEffectCompat(context);
11271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mRightEdge = new EdgeEffectCompat(context);
11371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        setWillNotDraw(false);
11471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        setClipToPadding(false);
11571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
11671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
11771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
11871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void requestLayout() {
11971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (!mPopulating) {
12071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            super.requestLayout();
12171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
12271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
12371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
12471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
12571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
12671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
12771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
12871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
12971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
13071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
13171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (widthMode != MeasureSpec.EXACTLY) {
13271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            Log.e(TAG, "onMeasure: must have an exact width or match_parent! " +
13371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    "Using fallback spec of EXACTLY " + widthSize);
13471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
13571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (heightMode != MeasureSpec.EXACTLY) {
13671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            Log.e(TAG, "onMeasure: must have an exact height or match_parent! " +
13771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    "Using fallback spec of EXACTLY " + heightSize);
13871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
13971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
14071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        setMeasuredDimension(widthSize, heightSize);
14171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
14271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float portSpaces = mLargeColumnUnitCount / PORT_UNITS;
14371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        float height = getMeasuredHeight() / portSpaces;
14471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mLargeColumnWidth = (int) (height / ASPECT_RATIO);
14571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        portSpaces++;
14671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        height = getMeasuredHeight() / portSpaces;
14771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mSmallColumnWidth = (int) (height / ASPECT_RATIO);
14871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
14971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
15071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
15171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected void onLayout(boolean changed, int l, int t, int r, int b) {
15271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mInLayout = true;
15371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        populate();
15471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mInLayout = false;
15571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
15671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int width = r - l;
15771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int height = b - t;
15871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mLeftEdge.setSize(width, height);
15971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mRightEdge.setSize(width, height);
16071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
16171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
16271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void populate() {
16371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (getWidth() == 0 || getHeight() == 0) {
16471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            return;
16571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
16671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
16771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // TODO: Handle size changing
16871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        final int colCount = mColCount;
16971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        if (mItemTops == null || mItemTops.length != colCount) {
17071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            mItemTops = new int[colCount];
17171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            mItemBottoms = new int[colCount];
17271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int top = getPaddingTop();
17371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int offset = top + Math.min(mRestoreOffset, 0);
17471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            Arrays.fill(mItemTops, offset);
17571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            Arrays.fill(mItemBottoms, offset);
17671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            mLayoutRecords.clear();
17771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            if (mInLayout) {
17871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                removeAllViewsInLayout();
17971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            } else {
18071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                removeAllViews();
18171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            }
18271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            mRestoreOffset = 0;
18371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        }
18471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
18571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mPopulating = true;
18671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        layoutChildren(mDataChanged);
18771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        fillRight(mFirstPosition + getChildCount(), 0);
18871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        fillLeft(mFirstPosition - 1, 0);
18971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mPopulating = false;
19071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mDataChanged = false;
19171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
19271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
19371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    final void layoutChildren(boolean queryAdapter) {
19471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck// TODO
19571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        final int childCount = getChildCount();
19671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        for (int i = 0; i < childCount; i++) {
19771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            View child = getChildAt(i);
19871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//
19971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            if (child.isLayoutRequested()) {
20071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                final int widthSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY);
20171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                final int heightSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY);
20271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                child.measure(widthSpec, heightSpec);
20371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                child.layout(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
20471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            }
20571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//
20671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            int childTop = mItemBottoms[col] > Integer.MIN_VALUE ?
20771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                    mItemBottoms[col] + mItemMargin : child.getTop();
20871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            if (span > 1) {
20971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                int lowest = childTop;
21071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                for (int j = col + 1; j < col + span; j++) {
21171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                    final int bottom = mItemBottoms[j] + mItemMargin;
21271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                    if (bottom > lowest) {
21371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                        lowest = bottom;
21471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                    }
21571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                }
21671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//                childTop = lowest;
21771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            }
21871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int childHeight = child.getMeasuredHeight();
21971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int childBottom = childTop + childHeight;
22071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int childLeft = paddingLeft + col * (colWidth + itemMargin);
22171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            final int childRight = childLeft + child.getMeasuredWidth();
22271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//            child.layout(childLeft, childTop, childRight, childBottom);
22371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck//        }
22471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
22571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
22671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    /**
22771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * Obtain the view and add it to our list of children. The view can be made
22871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * fresh, converted from an unused view, or used as is if it was in the
22971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * recycle bin.
23071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     *
23171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param startPosition Logical position in the list to start from
23271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param x Left or right edge of the view to add
23371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param forward If true, align left edge to x and increase position.
23471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     *                If false, align right edge to x and decrease position.
23571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @return Number of views added
23671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     */
23771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int makeAndAddColumn(int startPosition, int x, boolean forward) {
23871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int columnWidth = mLargeColumnWidth;
23971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int addViews = 0;
24071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        for (int remaining = mLargeColumnUnitCount, i = 0;
24171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                remaining > 0 && startPosition + i >= 0 && startPosition + i < mItemCount;
24271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                i += forward ? 1 : -1, addViews++) {
24371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mAdapter.getIntrinsicAspectRatio(startPosition + i) >= 1f) {
24471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // landscape
24571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                remaining -= LAND_UNITS;
24671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
24771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // portrait
24871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                remaining -= PORT_UNITS;
24971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (remaining < 0) {
25071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    remaining += (mSmallColumnUnitCount - mLargeColumnUnitCount);
25171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    columnWidth = mSmallColumnWidth;
25271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
25371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
25471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
25571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int nextTop = 0;
25671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        for (int i = 0; i < addViews; i++) {
25771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            int position = startPosition + (forward ? i : -i);
25871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            View child = obtainView(position, null);
25971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (child.getParent() != this) {
26071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (mInLayout) {
26171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    addViewInLayout(child, forward ? -1 : 0, child.getLayoutParams());
26271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                } else {
26371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    addView(child, forward ? -1 : 0);
26471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
26571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
26671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            int heightSize = (int) (.5f + (mAdapter.getIntrinsicAspectRatio(position) >= 1f
26771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    ? columnWidth / ASPECT_RATIO
26871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    : columnWidth * ASPECT_RATIO));
26971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
27071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            int widthSpec = MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY);
27171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            child.measure(widthSpec, heightSpec);
27271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            int childLeft = forward ? x : x - columnWidth;
27371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            child.layout(childLeft, nextTop, childLeft + columnWidth, nextTop + heightSize);
27471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            nextTop += heightSize;
27571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
27671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return addViews;
27771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
27871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
27971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
28071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public boolean onInterceptTouchEvent(MotionEvent ev) {
28171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mVelocityTracker.addMovement(ev);
28271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
28371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        switch (action) {
28471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_DOWN:
28571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mVelocityTracker.clear();
28671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mScroller.abortAnimation();
28771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mLastTouchX = ev.getX();
28871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
28971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchRemainderX = 0;
29071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (mTouchMode == TOUCH_MODE_FLINGING) {
29171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    // Catch!
29271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTouchMode = TOUCH_MODE_DRAGGING;
29371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    return true;
29471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
29571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                break;
29671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
29771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_MOVE: {
29871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
29971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (index < 0) {
30071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
30171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
30271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            "event stream?");
30371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    return false;
30471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
30571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final float x = MotionEventCompat.getX(ev, index);
30671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final float dx = x - mLastTouchX + mTouchRemainderX;
30771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final int deltaY = (int) dx;
30871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchRemainderX = dx - deltaY;
30971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
31071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (Math.abs(dx) > mTouchSlop) {
31171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTouchMode = TOUCH_MODE_DRAGGING;
31271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    return true;
31371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
31471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
31571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
31671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
31771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return false;
31871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
31971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
32071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
32171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public boolean onTouchEvent(MotionEvent ev) {
32271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mVelocityTracker.addMovement(ev);
32371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
32471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        switch (action) {
32571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_DOWN:
32671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mVelocityTracker.clear();
32771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mScroller.abortAnimation();
32871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mLastTouchX = ev.getX();
32971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
33071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchRemainderX = 0;
33171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                break;
33271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
33371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_MOVE: {
33471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
33571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (index < 0) {
33671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
33771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
33871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            "event stream?");
33971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    return false;
34071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
34171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final float x = MotionEventCompat.getX(ev, index);
34271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final float dx = x - mLastTouchX + mTouchRemainderX;
34371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final int deltaX = (int) dx;
34471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchRemainderX = dx - deltaX;
34571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
34671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (Math.abs(dx) > mTouchSlop) {
34771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTouchMode = TOUCH_MODE_DRAGGING;
34871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
34971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
35071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (mTouchMode == TOUCH_MODE_DRAGGING) {
35171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mLastTouchX = x;
35271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
35371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    if (!trackMotionScroll(deltaX, true)) {
35471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        // Break fling velocity if we impacted an edge.
35571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        mVelocityTracker.clear();
35671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    }
35771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
35871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } break;
35971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
36071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_CANCEL:
36171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchMode = TOUCH_MODE_IDLE;
36271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                break;
36371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
36471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            case MotionEvent.ACTION_UP: {
36571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
36671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                final float velocity = VelocityTrackerCompat.getXVelocity(mVelocityTracker,
36771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        mActivePointerId);
36871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (Math.abs(velocity) > mFlingVelocity) { // TODO
36971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTouchMode = TOUCH_MODE_FLINGING;
37071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mScroller.fling(0, 0, (int) velocity, 0,
37171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
37271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mLastTouchX = 0;
37371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    ViewCompat.postInvalidateOnAnimation(this);
37471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                } else {
37571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTouchMode = TOUCH_MODE_IDLE;
37671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
37771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
37871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } break;
37971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
38071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return true;
38171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
38271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
38371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    /**
38471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     *
38571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param deltaX Pixels that content should move by
38671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @return true if the movement completed, false if it was stopped prematurely.
38771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     */
38871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean trackMotionScroll(int deltaX, boolean allowOverScroll) {
38971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final boolean contentFits = contentFits();
39071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int allowOverhang = Math.abs(deltaX);
39171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
39271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int overScrolledBy;
39371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int movedBy;
39471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (!contentFits) {
39571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int overhang;
39671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final boolean up;
39771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mPopulating = true;
39871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (deltaX > 0) {
39971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                overhang = fillLeft(mFirstPosition - 1, allowOverhang);
40071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                up = true;
40171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
40271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                overhang = fillRight(mFirstPosition + getChildCount(), allowOverhang);
40371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                up = false;
40471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
40571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            movedBy = Math.min(overhang, allowOverhang);
40671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            offsetChildren(up ? movedBy : -movedBy);
40771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            recycleOffscreenViews();
40871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mPopulating = false;
40971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            overScrolledBy = allowOverhang - overhang;
41071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
41171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            overScrolledBy = allowOverhang;
41271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            movedBy = 0;
41371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
41471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
41571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (allowOverScroll) {
41671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int overScrollMode = ViewCompat.getOverScrollMode(this);
41771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
41871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
41971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits)) {
42071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
42171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (overScrolledBy > 0) {
42271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    EdgeEffectCompat edge = deltaX > 0 ? mLeftEdge : mRightEdge;
42371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    edge.onPull((float) Math.abs(deltaX) / getWidth());
42471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    ViewCompat.postInvalidateOnAnimation(this);
42571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
42671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
42771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
42871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
42971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return deltaX == 0 || movedBy != 0;
43071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
43171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
43271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    /**
43371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * Important: this method will leave offscreen views attached if they
43471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * are required to maintain the invariant that child view with index i
43571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * is always the view corresponding to position mFirstPosition + i.
43671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     */
43771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void recycleOffscreenViews() {
43871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int height = getHeight();
43971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int clearAbove = 0;
44071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int clearBelow = height;
44171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        for (int i = getChildCount() - 1; i >= 0; i--) {
44271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final View child = getChildAt(i);
44371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (child.getTop() <= clearBelow)  {
44471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // There may be other offscreen views, but we need to maintain
44571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // the invariant documented above.
44671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                break;
44771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
44871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
44971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mInLayout) {
45071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                removeViewsInLayout(i, 1);
45171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
45271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                removeViewAt(i);
45371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
45471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
45571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.addScrap(child);
45671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
45771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
45871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        while (getChildCount() > 0) {
45971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final View child = getChildAt(0);
46071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (child.getBottom() >= clearAbove) {
46171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // There may be other offscreen views, but we need to maintain
46271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                // the invariant documented above.
46371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                break;
46471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
46571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
46671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mInLayout) {
46771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                removeViewsInLayout(0, 1);
46871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
46971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                removeViewAt(0);
47071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
47171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
47271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.addScrap(child);
47371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mFirstPosition++;
47471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
47571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
47671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
47771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    final void offsetChildren(int offset) {
47871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int childCount = getChildCount();
47971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        for (int i = 0; i < childCount; i++) {
48071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final View child = getChildAt(i);
48171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            child.layout(child.getLeft() + offset, child.getTop(),
48271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    child.getRight() + offset, child.getBottom());
48371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
48471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
48571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
48671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private boolean contentFits() {
48771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int childCount = getChildCount();
48871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (childCount == 0) return true;
48971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (childCount != mItemCount) return false;
49071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
49171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return getChildAt(0).getLeft() >= getPaddingLeft() &&
49271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                getChildAt(childCount - 1).getRight() <= getWidth() - getPaddingRight();
49371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
49471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
49571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void recycleAllViews() {
49671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        for (int i = 0; i < getChildCount(); i++) {
49771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.addScrap(getChildAt(i));
49871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
49971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
50071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (mInLayout) {
50171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            removeAllViewsInLayout();
50271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
50371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            removeAllViews();
50471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
50571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
50671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
50771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int fillRight(int pos, int overhang) {
50871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int end = (getRight() - getLeft()) + overhang;
50971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
51071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int nextLeft = getChildCount() == 0 ? 0 : getChildAt(getChildCount() - 1).getRight();
51171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        while (nextLeft < end && pos < mItemCount) {
51271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            pos += makeAndAddColumn(pos, nextLeft, true);
51371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            nextLeft = getChildAt(getChildCount() - 1).getRight();
51471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
51571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int gridRight = getWidth() - getPaddingRight();
51671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return getChildAt(getChildCount() - 1).getRight() - gridRight;
51771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
51871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
51971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private int fillLeft(int pos, int overhang) {
52071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int end = getPaddingLeft() - overhang;
52171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
52271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int nextRight = getChildAt(0).getLeft();
52371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        while (nextRight > end && pos >= 0) {
52471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            pos -= makeAndAddColumn(pos, nextRight, false);
52571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            nextRight = getChildAt(0).getLeft();
52671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
52771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
52871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mFirstPosition = pos + 1;
52971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return getPaddingLeft() - getChildAt(0).getLeft();
53071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
53171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
53271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
53371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void computeScroll() {
53471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (mScroller.computeScrollOffset()) {
53571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int x = mScroller.getCurrX();
53671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int dx = (int) (x - mLastTouchX);
53771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mLastTouchX = x;
53871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final boolean stopped = !trackMotionScroll(dx, false);
53971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
54071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (!stopped && !mScroller.isFinished()) {
54171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                ViewCompat.postInvalidateOnAnimation(this);
54271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else {
54371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (stopped) {
54471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    final int overScrollMode = ViewCompat.getOverScrollMode(this);
54571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    if (overScrollMode != ViewCompat.OVER_SCROLL_NEVER) {
54671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        final EdgeEffectCompat edge;
54771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        if (dx > 0) {
54871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            edge = mLeftEdge;
54971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        } else {
55071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                            edge = mRightEdge;
55171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        }
55271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity()));
55371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        ViewCompat.postInvalidateOnAnimation(this);
55471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    }
55571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mScroller.abortAnimation();
55671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
55771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTouchMode = TOUCH_MODE_IDLE;
55871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
55971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
56071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
56171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
56271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
56371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void draw(Canvas canvas) {
56471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        super.draw(canvas);
56571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
56671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (!mLeftEdge.isFinished()) {
56771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int restoreCount = canvas.save();
56871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int height = getHeight() - getPaddingTop() - getPaddingBottom();
56971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
57071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.rotate(270);
57171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.translate(-height + getPaddingTop(), 0);
57271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mLeftEdge.setSize(height, getWidth());
57371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mLeftEdge.draw(canvas)) {
57471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                postInvalidateOnAnimation();
57571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
57671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.restoreToCount(restoreCount);
57771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
57871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (!mRightEdge.isFinished()) {
57971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int restoreCount = canvas.save();
58071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int width = getWidth();
58171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int height = getHeight() - getPaddingTop() - getPaddingBottom();
58271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
58371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.rotate(90);
58471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.translate(-getPaddingTop(), width);
58571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRightEdge.setSize(height, width);
58671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mRightEdge.draw(canvas)) {
58771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                postInvalidateOnAnimation();
58871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
58971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            canvas.restoreToCount(restoreCount);
59071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
59171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
59271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
59371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    /**
59471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * Obtain a populated view from the adapter. If optScrap is non-null and is not
59571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * reused it will be placed in the recycle bin.
59671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     *
59771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param position position to get view for
59871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @param optScrap Optional scrap view; will be reused if possible
59971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * @return A new view, a recycled view from mRecycler, or optScrap
60071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     */
60171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private final View obtainView(int position, View optScrap) {
60271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        View view = mRecycler.getTransientStateView(position);
60371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (view != null) {
60471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            return view;
60571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
60671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
60771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Reuse optScrap if it's of the right type (and not null)
60871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int optType = optScrap != null ?
60971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                ((LayoutParams) optScrap.getLayoutParams()).viewType : -1;
61071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final int positionViewType = mAdapter.getItemViewType(position);
61171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final View scrap = optType == positionViewType ?
61271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                optScrap : mRecycler.getScrapView(positionViewType);
61371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
61471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        view = mAdapter.getView(position, scrap, this);
61571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
61671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (view != scrap && scrap != null) {
61771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            // The adapter didn't use it; put it back.
61871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.addScrap(scrap);
61971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
62071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
62171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        ViewGroup.LayoutParams lp = view.getLayoutParams();
62271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
62371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (view.getParent() != this) {
62471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (lp == null) {
62571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                lp = generateDefaultLayoutParams();
62671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            } else if (!checkLayoutParams(lp)) {
62771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                lp = generateLayoutParams(lp);
62871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
62971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            view.setLayoutParams(lp);
63071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
63171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
63271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        final LayoutParams sglp = (LayoutParams) lp;
63371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        sglp.position = position;
63471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        sglp.viewType = positionViewType;
63571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
63671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return view;
63771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
63871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
63971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public GalleryThumbnailAdapter getAdapter() {
64071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return mAdapter;
64171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
64271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
64371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public void setAdapter(GalleryThumbnailAdapter adapter) {
64471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (mAdapter != null) {
64571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mAdapter.unregisterDataSetObserver(mObserver);
64671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
64771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // TODO: If the new adapter says that there are stable IDs, remove certain layout records
64871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // and onscreen views if they have changed instead of removing all of the state here.
64971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        clearAllState();
65071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mAdapter = adapter;
65171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mDataChanged = true;
65271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mOldItemCount = mItemCount = adapter != null ? adapter.getCount() : 0;
65371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        if (adapter != null) {
65471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            adapter.registerDataSetObserver(mObserver);
65571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.setViewTypeCount(adapter.getViewTypeCount());
65671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mHasStableIds = adapter.hasStableIds();
65771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        } else {
65871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mHasStableIds = false;
65971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
66071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        populate();
66171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
66271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
66371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    /**
66471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     * Clear all state because the grid will be used for a completely different set of data.
66571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck     */
66671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private void clearAllState() {
66771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Clear all layout records and views
66871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        removeAllViews();
66971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
67071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Reset to the top of the grid
67171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mFirstPosition = 0;
67271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
67371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        // Clear recycler because there could be different view types now
67471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        mRecycler.clear();
67571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
67671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
67771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
67871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected LayoutParams generateDefaultLayoutParams() {
67971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return new LayoutParams(LayoutParams.WRAP_CONTENT);
68071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
68171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
68271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
68371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
68471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return new LayoutParams(lp);
68571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
68671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
68771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
68871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) {
68971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return lp instanceof LayoutParams;
69071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
69171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
69271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    @Override
69371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
69471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        return new LayoutParams(getContext(), attrs);
69571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
69671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
69771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    public static class LayoutParams extends ViewGroup.LayoutParams {
69871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private static final int[] LAYOUT_ATTRS = new int[] {
69971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                android.R.attr.layout_span
70071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        };
70171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
70271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private static final int SPAN_INDEX = 0;
70371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
70471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
70571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * The number of columns this item should span
70671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
70771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public int span = 1;
70871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
70971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
71071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * Item position this view represents
71171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
71271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int position;
71371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
71471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
71571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * Type of this view as reported by the adapter
71671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
71771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int viewType;
71871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
71971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
72071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * The column this view is occupying
72171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
72271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        int column;
72371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
72471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        /**
72571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         * The stable ID of the item this view displays
72671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck         */
72771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        long id = -1;
72871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
72971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public LayoutParams(int height) {
73071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            super(MATCH_PARENT, height);
73171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
73271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (this.height == MATCH_PARENT) {
73371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " +
73471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        "impossible! Falling back to WRAP_CONTENT");
73571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                this.height = WRAP_CONTENT;
73671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
73771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
73871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
73971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public LayoutParams(Context c, AttributeSet attrs) {
74071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            super(c, attrs);
74171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
74271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (this.width != MATCH_PARENT) {
74371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                Log.w(TAG, "Inflation setting LayoutParams width to " + this.width +
74471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        " - must be MATCH_PARENT");
74571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                this.width = MATCH_PARENT;
74671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
74771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (this.height == MATCH_PARENT) {
74871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                Log.w(TAG, "Inflation setting LayoutParams height to MATCH_PARENT - " +
74971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        "impossible! Falling back to WRAP_CONTENT");
75071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                this.height = WRAP_CONTENT;
75171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
75271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
75371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
75471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            span = a.getInteger(SPAN_INDEX, 1);
75571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            a.recycle();
75671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
75771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
75871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public LayoutParams(ViewGroup.LayoutParams other) {
75971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            super(other);
76071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
76171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (this.width != MATCH_PARENT) {
76271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                Log.w(TAG, "Constructing LayoutParams with width " + this.width +
76371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        " - must be MATCH_PARENT");
76471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                this.width = MATCH_PARENT;
76571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
76671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (this.height == MATCH_PARENT) {
76771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " +
76871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        "impossible! Falling back to WRAP_CONTENT");
76971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                this.height = WRAP_CONTENT;
77071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
77171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
77271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
77371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
77471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private class RecycleBin {
77571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private ArrayList<View>[] mScrapViews;
77671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private int mViewTypeCount;
77771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private int mMaxScrap;
77871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
77971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        private SparseArray<View> mTransientStateViews;
78071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
78171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void setViewTypeCount(int viewTypeCount) {
78271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (viewTypeCount < 1) {
78371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                throw new IllegalArgumentException("Must have at least one view type (" +
78471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                        viewTypeCount + " types reported)");
78571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
78671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (viewTypeCount == mViewTypeCount) {
78771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                return;
78871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
78971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
79071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
79171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            for (int i = 0; i < viewTypeCount; i++) {
79271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                scrapViews[i] = new ArrayList<View>();
79371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
79471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mViewTypeCount = viewTypeCount;
79571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mScrapViews = scrapViews;
79671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
79771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
79871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void clear() {
79971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int typeCount = mViewTypeCount;
80071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            for (int i = 0; i < typeCount; i++) {
80171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mScrapViews[i].clear();
80271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
80371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mTransientStateViews != null) {
80471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTransientStateViews.clear();
80571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
80671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
80771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
80871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void clearTransientViews() {
80971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mTransientStateViews != null) {
81071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTransientStateViews.clear();
81171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
81271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
81371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
81471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void addScrap(View v) {
81571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final LayoutParams lp = (LayoutParams) v.getLayoutParams();
81671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (ViewCompat.hasTransientState(v)) {
81771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                if (mTransientStateViews == null) {
81871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                    mTransientStateViews = new SparseArray<View>();
81971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                }
82071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTransientStateViews.put(lp.position, v);
82171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                return;
82271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
82371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
82471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int childCount = getChildCount();
82571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (childCount > mMaxScrap) {
82671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mMaxScrap = childCount;
82771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
82871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
82971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            ArrayList<View> scrap = mScrapViews[lp.viewType];
83071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (scrap.size() < mMaxScrap) {
83171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                scrap.add(v);
83271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
83371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
83471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
83571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public View getTransientStateView(int position) {
83671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (mTransientStateViews == null) {
83771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                return null;
83871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
83971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
84071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final View result = mTransientStateViews.get(position);
84171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (result != null) {
84271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                mTransientStateViews.remove(position);
84371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
84471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            return result;
84571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
84671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
84771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public View getScrapView(int type) {
84871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            ArrayList<View> scrap = mScrapViews[type];
84971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (scrap.isEmpty()) {
85071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                return null;
85171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
85271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
85371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final int index = scrap.size() - 1;
85471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            final View result = scrap.get(index);
85571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            scrap.remove(index);
85671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            return result;
85771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
85871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
85971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
86071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    private class AdapterDataSetObserver extends DataSetObserver {
86171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        @Override
86271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void onChanged() {
86371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mDataChanged = true;
86471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mOldItemCount = mItemCount;
86571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mItemCount = mAdapter.getCount();
86671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
86771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            // TODO: Consider matching these back up if we have stable IDs.
86871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            mRecycler.clearTransientViews();
86971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
87071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            if (!mHasStableIds) {
87171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck                recycleAllViews();
87271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            }
87371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
87471bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            // TODO: consider repopulating in a deferred runnable instead
87571bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            // (so that successive changes may still be batched)
87671bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck            requestLayout();
87771bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
87871bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck
87971bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        @Override
88071bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        public void onInvalidated() {
88171bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck        }
88271bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck    }
88371bfefaf9029df26ba4c6e4077c4e3e2f259634fJohn Reck}
884