StaggeredGridLayoutManager.java revision 6b4d950d0d1e26165a1e643a2fd1fe4e283786f1
12d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/*
22d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Copyright (C) 2014 The Android Open Source Project
32d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar *
42d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
52d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * you may not use this file except in compliance with the License.
62d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * You may obtain a copy of the License at
72d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar *
82d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
92d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar *
102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Unless required by applicable law or agreed to in writing, software
112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * See the License for the specific language governing permissions and
142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * limitations under the License.
152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */
162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpackage android.support.v7.widget;
182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.content.Context;
202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.PointF;
212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.Rect;
222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcel;
232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcelable;
242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.support.v4.view.ViewCompat;
252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.AttributeSet;
262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.Log;
272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.View;
282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.ViewGroup;
292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.ArrayList;
322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.Arrays;
332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.BitSet;
342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START;
372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END;
382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_HEAD;
392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_TAIL;
402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/**
412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * A LayoutManager that lays out children in a staggered grid formation.
422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It supports horizontal & vertical layout as well as an ability to layout children in reverse.
432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p>
442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps,
452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can
462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * control this behavior via {@link #setGapStrategy(int)}.
472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */
482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpublic class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final String TAG = "StaggeredGridLayoutManager";
512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private static final boolean DEBUG = false;
532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5403a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
5503a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
5603a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int VERTICAL = OrientationHelper.VERTICAL;
5703a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Does not do anything to hide gaps
602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_NONE = 0;
622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Scroll the shorter span slower to avoid gaps in the UI.
652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For example, if LayoutManager ends up with the following layout:
672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BXC
692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DEF
702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Where B has two spans height, if user scrolls down it will keep the positions of 2nd and 3rd
722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * columns,
732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * which will result in:
742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BXC
762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BEF
772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * instead of
792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * B
812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BEF
822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_LAZY = 1;
852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * On scroll, LayoutManager checks for a view that is assigned to wrong span.
882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When such a situation is detected, LayoutManager will wait until scroll is complete and then
892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * move children to their correct spans.
902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For example, if LayoutManager ends up with the following layout due to adapter changes:
922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * _BC
952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * It will animate to the following state:
982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BC_
1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private static final int INVALID_OFFSET = Integer.MIN_VALUE;
1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Number of spans
1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSpanCount = -1;
1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span[] mSpans;
1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Primary orientation is the layout's orientation, secondary orientation is the orientation
1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for spans. Having both makes code much cleaner for calculations.
1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mPrimaryOrientation;
1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mSecondaryOrientation;
1212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mOrientation;
1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * The width or height per span, depending on the orientation.
1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSizePerSpan;
1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private LayoutState mLayoutState;
1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mReverseLayout = false;
1322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Aggregated reverse layout value that takes RTL into account.
1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mShouldReverseLayout = false;
1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Temporary variable used during fill method to check which spans needs to be filled.
1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private BitSet mRemainingSpans;
1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout which will check this variable and re-layout accordingly.
1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1476e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPosition = RecyclerView.NO_POSITION;
1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * called.
1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1536e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPositionOffset = INVALID_OFFSET;
1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Keeps the mapping between the adapter positions and spans. This is necessary to provide
1572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * a consistent experience when user scrolls the list.
1582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    LazySpanLookup mLazySpanLookup = new LazySpanLookup();
1602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * how we handle gaps in UI.
1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Saved state needs this information to properly layout on restore.
1682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mLastLayoutFromEnd;
1702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * SavedState is not handled until a layout happens. This is where we keep it until next
1732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout.
1742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private SavedState mPendingSavedState;
1762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If LayoutManager detects an unwanted gap in the layout, it sets this flag which will trigger
1792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * a runnable after scrolling ends and will re-check. If invalid view state is still present,
1802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * it will request a layout to fix it.
1812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mHasGaps;
1832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Creates a StaggeredGridLayoutManager with given parameters.
1862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
1872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount   If orientation is vertical, spanCount is number of columns. If
1882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    orientation is horizontal, spanCount is number of rows.
1899bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar     * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL}
1902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public StaggeredGridLayoutManager(int spanCount, int orientation) {
1922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
1932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        setSpanCount(spanCount);
1942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
1952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
1972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onScrollStateChanged(int state) {
1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (state == RecyclerView.SCROLL_STATE_IDLE && mHasGaps) {
1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // re-check for gaps
2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View gapView = hasGapsToFix(0, getChildCount());
2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (gapView == null) {
2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mHasGaps = false; // yay, gap disappeared :)
2032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // We should invalidate positions after the last visible child. No reason to
2042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // re-layout.
2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int lastVisiblePosition = mShouldReverseLayout ? getFirstChildPosition()
2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        : getLastChildPosition();
2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.invalidateAfter(lastVisiblePosition + 1);
2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.invalidateAfter(getPosition(gapView));
2100ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                requestSimpleAnimationsInNextLayout();
2112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                requestLayout(); // Trigger a re-layout which will fix the layout assignments.
2122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the number of spans for the layout. This will invalidate all of the span assignments
2182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for Views.
2192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
2202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calling this method will automatically result in a new layout request unless the spanCount
2212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * parameter is equal to current span count.
2222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount Number of spans to layout
2242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setSpanCount(int spanCount) {
2260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
2272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mSpanCount != spanCount) {
2282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // invalidate span info in saved state
2292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateSpanInfo();
2302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mSpanCount = spanCount;
231333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition;
2322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (spanCount != mSpanCount) {
2342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateSpanAssignments();
2352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = spanCount;
2362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mRemainingSpans = new BitSet(mSpanCount);
2372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans = new Span[mSpanCount];
2382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
2392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpans[i] = new Span(i);
2402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
2422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep
2472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * scroll position.
2482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param orientation {@link OrientationHelper#HORIZONTAL} or {@link OrientationHelper#VERTICAL}
2502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setOrientation(int orientation) {
2522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation != HORIZONTAL && orientation != VERTICAL) {
2532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid orientation.");
2542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2550bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
2562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mOrientation != orientation) {
2572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // override pending state
2582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mOrientation = orientation;
2592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation == mOrientation) {
2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
2622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
2642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation != null && mSecondaryOrientation != null) {
2652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // swap
2662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            OrientationHelper tmp = mPrimaryOrientation;
2672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = mSecondaryOrientation;
2682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = tmp;
2692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
2712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets whether LayoutManager should start laying out items from the end of the UI. The order
2752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * items are traversed is not affected by this call.
2762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
2772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * This behaves similar to the layout change for RTL views. When set to true, first item is
2782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * laid out at the end of the ViewGroup, second item is laid out before it etc.
2792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
2802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For horizontal layouts, it depends on the layout direction.
2812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if
2822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link RecyclerView}} is RTL, it will layout from LTR.
2832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param reverseLayout Whether layout should be in reverse or not
2852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setReverseLayout(boolean reverseLayout) {
2870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
2882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) {
2892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mReverseLayout = reverseLayout;
2902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mReverseLayout = reverseLayout;
2922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
2932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the current gap handling strategy for StaggeredGridLayoutManager.
2972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
2982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Staggered grid may have gaps in the layout as items may have different sizes. To avoid gaps,
2992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * StaggeredGridLayoutManager provides 3 options. Check {@link #GAP_HANDLING_NONE},
3002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}, {@link #GAP_HANDLING_LAZY} for details.
3012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
3022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}.
3032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Current gap handling strategy.
3052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setGapStrategy(int)
3062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_NONE
3072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_LAZY
3082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
3092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getGapStrategy() {
3112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mGapStrategy;
3122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter
3162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * is different than the current strategy, calling this method will trigger a layout request.
3172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param gapStrategy The new gap handling strategy. Should be {@link #GAP_HANDLING_LAZY}
3192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    , {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or
3202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    {@link #GAP_HANDLING_NONE}
3212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #getGapStrategy()
3222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setGapStrategy(int gapStrategy) {
3240bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mGapStrategy != gapStrategy) {
3262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mGapStrategy = gapStrategy;
3272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gapStrategy == mGapStrategy) {
3292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
3302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gapStrategy != GAP_HANDLING_LAZY && gapStrategy != GAP_HANDLING_NONE &&
3322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
3332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE "
3342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    + ", GAP_HANDLING_LAZY or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
3352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mGapStrategy = gapStrategy;
3372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3400bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    @Override
3410bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void assertNotInLayoutOrScroll(String message) {
3420bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        if (mPendingSavedState == null) {
3430bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            super.assertNotInLayoutOrScroll(message);
3440bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
3450bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
3460bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
3472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the number of spans laid out by StaggeredGridLayoutManager.
3492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Number of spans in the layout
3512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getSpanCount() {
3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mSpanCount;
3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items.
3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you need to cancel current assignments, you can call this method which will clear all
3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * assignments and request a new layout.
3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void invalidateSpanAssignments() {
3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.clear();
3642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
3652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void ensureOrientationHelper() {
3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation == null) {
3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation);
3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = OrientationHelper
3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    .createOrientationHelper(this, 1 - mOrientation);
3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState = new LayoutState();
3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calculates the views' layout order. (e.g. from end to start or start to end)
3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * RTL layout support is applied automatically. So if layout is RTL and
3792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
3802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void resolveShouldLayoutReverse() {
3822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // A == B is the same result, but we rather keep it readable
3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mOrientation == VERTICAL || !isLayoutRTL()) {
3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = mReverseLayout;
3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = !mReverseLayout;
3872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean isLayoutRTL() {
3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns whether views are laid out in reverse order or not.
3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Not that this value is not affected by RecyclerView's layout direction.
3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return True if layout is reversed, false otherwise
4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean getReverseLayout() {
4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mReverseLayout;
4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
4072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Update adapter size.
4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.mAdapterSize = state.getItemCount();
4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int anchorItemPosition;
4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int anchorOffset;
4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // This value may change if we are jumping to a position.
4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean layoutFromEnd;
4152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // If set to true, spans will clear their offsets and they'll be laid out from start
4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // depending on the layout direction. Invalidating span offsets is necessary to be able
4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // to jump to a position.
4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean invalidateSpanOffsets = false;
4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (DEBUG) {
4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Log.d(TAG, "found saved state: " + mPendingSavedState);
4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            setOrientation(mPendingSavedState.mOrientation);
4262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            setSpanCount(mPendingSavedState.mSpanCount);
4272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            setGapStrategy(mPendingSavedState.mGapStrategy);
4282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            setReverseLayout(mPendingSavedState.mReverseLayout);
4292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            resolveShouldLayoutReverse();
4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPendingSavedState.mAnchorPosition != RecyclerView.NO_POSITION) {
4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutFromEnd = mShouldReverseLayout;
4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPendingSavedState.mHasSpanOffsets) {
4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].clear();
4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].setLine(mPendingSavedState.mSpanOffsets[i]);
4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPendingSavedState.mSpanLookupSize > 1) {
4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.mData = mPendingSavedState.mSpanLookup;
4452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
4482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            resolveShouldLayoutReverse();
4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            layoutFromEnd = mShouldReverseLayout; // get updated value.
4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Validate scroll position if exists.
4536e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        if (!state.isPreLayout() && mPendingScrollPosition != RecyclerView.NO_POSITION) {
4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // Validate it.
4552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
4562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mPendingScrollPosition = RecyclerView.NO_POSITION;
4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mPendingScrollPositionOffset = INVALID_OFFSET;
4582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4616e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        if (!state.isPreLayout() && mPendingScrollPosition != RecyclerView.NO_POSITION) {
4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPendingSavedState == null
4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    || mPendingSavedState.mAnchorPosition == RecyclerView.NO_POSITION
4642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    || !mPendingSavedState.mHasSpanOffsets) {
4652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // If item is visible, make it fully visible.
4662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View child = findViewByPosition(mPendingScrollPosition);
4672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (child != null) {
4682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (mPendingScrollPositionOffset != INVALID_OFFSET) {
4692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        // Use regular anchor position.
4702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        anchorItemPosition = mShouldReverseLayout ? getLastChildPosition()
4712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                : getFirstChildPosition();
4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (layoutFromEnd) {
4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            final int target = mPrimaryOrientation.getEndAfterPadding() -
4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    mPendingScrollPositionOffset;
4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = target - mPrimaryOrientation.getDecoratedEnd(child);
4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            final int target = mPrimaryOrientation.getStartAfterPadding() +
4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    mPendingScrollPositionOffset;
4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = target - mPrimaryOrientation.getDecoratedStart(child);
4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    } else {
4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        final int startGap = mPrimaryOrientation.getDecoratedStart(child)
4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                - mPrimaryOrientation.getStartAfterPadding();
4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        final int endGap = mPrimaryOrientation.getEndAfterPadding() -
4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                mPrimaryOrientation.getDecoratedEnd(child);
4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child);
4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        // Use regular anchor item, just offset the layout.
4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        anchorItemPosition = mShouldReverseLayout ? getLastChildPosition()
4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                : getFirstChildPosition();
4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (childSize > mPrimaryOrientation.getTotalSpace()) {
4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            // Item does not fit. Fix depending on layout direction.
4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = layoutFromEnd ? mPrimaryOrientation.getEndAfterPadding()
4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    : mPrimaryOrientation.getStartAfterPadding();
4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else if (startGap < 0) {
4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = -startGap;
4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else if (endGap < 0) {
4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = endGap;
4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            // Nothing to do, just layout normal.
5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorItemPosition = mShouldReverseLayout ? getLastChildPosition()
5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    : getFirstChildPosition();
5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = INVALID_OFFSET;
5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // Child is not visible. Set anchor coordinate depending on in which direction
5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // child will be visible.
5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    anchorItemPosition = mPendingScrollPosition;
5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (mPendingScrollPositionOffset == INVALID_OFFSET) {
5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        final int position = calculateScrollDirectionForPosition(
5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                anchorItemPosition);
5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (position == LAYOUT_START) {
5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = mPrimaryOrientation.getStartAfterPadding();
5142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            layoutFromEnd = false;
5152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = mPrimaryOrientation.getEndAfterPadding();
5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            layoutFromEnd = true;
5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    } else {
5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (layoutFromEnd) {
5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = mPrimaryOrientation.getEndAfterPadding()
5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    - mPendingScrollPositionOffset;
5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            anchorOffset = mPrimaryOrientation.getStartAfterPadding()
5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    + mPendingScrollPositionOffset;
5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    invalidateSpanOffsets = true;
5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                anchorOffset = INVALID_OFFSET;
5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                anchorItemPosition = mPendingScrollPosition;
5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // We don't recycle views out of adapter order. This way, we can rely on the first or
5372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // last child as the anchor position.
538719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            anchorItemPosition = mShouldReverseLayout
539719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                    ? findLastReferenceChildPosition(state.getItemCount())
540719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                    : findFirstReferenceChildPosition(state.getItemCount());
5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            anchorOffset = INVALID_OFFSET;
5422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5430ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar        if (getChildCount() > 0 && (mPendingSavedState == null ||
5440ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                !mPendingSavedState.mHasSpanOffsets)) {
5450ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            if (invalidateSpanOffsets || mHasGaps) {
5462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
5472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // Scroll to position is set, clear.
5482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].clear();
5492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (anchorOffset != INVALID_OFFSET) {
5502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[i].setLine(anchorOffset);
5512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
5552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorOffset);
5562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (DEBUG) {
5582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int i = 0; i < mSpanCount; i++) {
5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        Log.d(TAG, "cached start-end lines for " + i + ":" +
5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                mSpans[i].mCachedStart + ":" + mSpans[i].mCachedEnd);
5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount;
5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        detachAndScrapAttachedViews(recycler);
5672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Layout start.
5682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        updateLayoutStateToFillStart(anchorItemPosition, state);
5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (!layoutFromEnd) {
5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        fill(recycler, mLayoutState, state);
5732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Layout end.
5752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        updateLayoutStateToFillEnd(anchorItemPosition, state);
5762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutFromEnd) {
5772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
5782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        fill(recycler, mLayoutState, state);
5802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
5822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout) {
5832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, true);
5842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, false);
5852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, true);
5872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, false);
5882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
5892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5916e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        if (!state.isPreLayout()) {
5926e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar            mPendingScrollPosition = RecyclerView.NO_POSITION;
5936e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
5946e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        }
5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLastLayoutFromEnd = layoutFromEnd;
5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingSavedState = null; // we don't need this anymore
5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Checks if a child is assigned to the non-optimal span.
6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
6022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param startChildIndex Starts checking after this child, inclusive
6032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param endChildIndex   Starts checking until this child, exclusive
6042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return The first View that is assigned to the wrong span.
6052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
6062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    View hasGapsToFix(int startChildIndex, int endChildIndex) {
6072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // quick reject
6082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (startChildIndex >= endChildIndex) {
6092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return null;
6102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int firstChildIndex, childLimit;
6122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int nextSpanDiff = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1;
6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mShouldReverseLayout) {
6152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            firstChildIndex = endChildIndex - 1;
6162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            childLimit = startChildIndex - 1;
6172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
6182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            firstChildIndex = startChildIndex;
6192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            childLimit = endChildIndex;
6202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1;
6222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) {
6232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(i);
6242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int start = mPrimaryOrientation.getDecoratedStart(child);
6252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int end = mPrimaryOrientation.getDecoratedEnd(child);
6262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
6272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutParams.mFullSpan) {
6282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                continue; // quick reject
6292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int nextSpanIndex = layoutParams.getSpanIndex() + nextSpanDiff;
6312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            while (nextSpanIndex >= 0 && nextSpanIndex < mSpanCount) {
6322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Span nextSpan = mSpans[nextSpanIndex];
6332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (nextSpan.isEmpty(start, end)) {
6342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return child;
6352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
6362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                nextSpanIndex += nextSpanDiff;
6372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // everything looks good
6402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return null;
6412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
6422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
6442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean supportsPredictiveItemAnimations() {
6456e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        return mPendingSavedState == null;
6462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
6472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
648333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
649333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first visible view for each span.
650333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
651333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
652333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
653333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
654333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
655333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
656333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
657333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
658333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
659333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
660333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @return The adapter position of the first visible item in each span. If a span does not have
661333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
662333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
663333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
664333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
665333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
666333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
667333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
668333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstVisibleItemPositions(int[] into) {
669333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
670333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
671333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
672333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
673333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
674333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
675333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        for (int i = 0; i < mSpanCount; i ++) {
676333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstVisibleItemPosition();
677333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
678333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
679333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
680333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
681333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
682333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first completely visible view for each span.
683333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
684333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
685333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
686333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
687333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
688333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
689333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
690333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
691333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
692333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
693333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @return The adapter position of the first fully visible item in each span. If a span does
694333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
695333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
696333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
697333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
698333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
699333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
700333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstCompletelyVisibleItemPositions(int[] into) {
701333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
702333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
703333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
704333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
705333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
706333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
707333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        for (int i = 0; i < mSpanCount; i ++) {
708333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition();
709333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
710333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
711333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
712333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
713333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
714333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last visible view for each span.
715333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
716333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
717333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
718333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
719333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
720333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
721333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
722333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
723333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
724333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
725333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @return The adapter position of the last visible item in each span. If a span does not have
726333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
727333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
728333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
729333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
730333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
731333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
732333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
733333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastVisibleItemPositions(int[] into) {
734333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
735333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
736333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
737333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
738333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
739333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
740333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        for (int i = 0; i < mSpanCount; i ++) {
741333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastVisibleItemPosition();
742333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
743333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
744333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
745333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
746333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
747333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last completely visible view for each span.
748333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
749333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
750333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
751333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
752333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
753333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
754333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
755333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
756333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
757333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
758333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @return The adapter position of the last fully visible item in each span. If a span does not
759333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
760333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
761333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
762333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
763333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
764333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
765333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
766333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastCompletelyVisibleItemPositions(int[] into) {
767333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
768333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
769333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
770333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
771333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
772333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
773333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        for (int i = 0; i < mSpanCount; i ++) {
774333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastCompletelyVisibleItemPosition();
775333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
776333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
777333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
778333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
7792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
7802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int heightSpec) {
7812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
7822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
7832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left,
7842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.rightMargin + insets.right);
7852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top,
7862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.bottomMargin + insets.bottom);
7872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        child.measure(widthSpec, heightSpec);
7882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
7902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int updateSpecWithExtra(int spec, int startInset, int endInset) {
7912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (startInset == 0 && endInset == 0) {
7922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return spec;
7932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
7942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mode = View.MeasureSpec.getMode(spec);
7952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
7962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return View.MeasureSpec.makeMeasureSpec(
7972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
7982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
7992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return spec;
8002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
8012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
8022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
8032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onRestoreInstanceState(Parcelable state) {
8042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (state instanceof SavedState) {
8052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState = (SavedState) state;
8062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
8072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (DEBUG) {
8082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "invalid saved state class");
8092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
8112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
8122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
8132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public Parcelable onSaveInstanceState() {
8142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
8152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new SavedState(mPendingSavedState);
8162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState state = new SavedState();
8182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mOrientation = mOrientation;
8192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mReverseLayout = mReverseLayout;
8202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mSpanCount = mSpanCount;
8212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mAnchorLayoutFromEnd = mLastLayoutFromEnd;
8222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mGapStrategy = mGapStrategy;
8232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
8242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLazySpanLookup != null && mLazySpanLookup.mData != null) {
8252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookup = mLazySpanLookup.mData;
8262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = state.mSpanLookup.length;
8272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
8282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = 0;
8292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
8312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
8322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition()
8332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : getFirstChildPosition();
834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt();
8352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mHasSpanOffsets = true;
8362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanOffsets = new int[mSpanCount];
8372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
8386b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar                state.mSpanOffsets[i] = mLastLayoutFromEnd ? mSpans[i].getEndLine(Span.INVALID_LINE)
8396b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar                        : mSpans[i].getStartLine(Span.INVALID_LINE);
8402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
8412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
8422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mAnchorPosition = RecyclerView.NO_POSITION;
843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            state.mVisibleAnchorPosition = RecyclerView.NO_POSITION;
8442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mHasSpanOffsets = false;
8452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
8472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "saved state:\n" + state);
8482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return state;
8502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
8512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Finds the first fully visible child to be used as an anchor child if span count changes when
854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * state is restored.
855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
856333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    int findFirstVisibleItemPositionInt() {
857333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int start, end, diff;
858333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (mLastLayoutFromEnd) {
859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            start = getChildCount() - 1;
860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            end = -1;
861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            diff = -1;
862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else {
863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            start = 0;
864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            end = getChildCount();
865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            diff = 1;
866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
868333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
869333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        for (int i = start; i != end; i += diff) {
870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final View child = getChildAt(i);
871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart
872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    && mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) {
873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                return getPosition(child);
874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return RecyclerView.NO_POSITION;
877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
8792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
8802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
8812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
8822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
8832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
8842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
8852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = -scrollBy(-gap, recycler, state);
8862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
8872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
8882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
8902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
8912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(gap);
8922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
8932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
8942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
8952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
8962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
8972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding());
8982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
8992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
9002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
9012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = scrollBy(gap, recycler, state);
9022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
9032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
9042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
9062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
9072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(-gap);
9082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) {
9122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
9132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
9142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
9152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
9162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos < anchorPosition) {
9172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
9182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
9192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
9202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
9212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
9222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
9232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_START;
9252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
9262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_HEAD;
9272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) {
9302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
9312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
9322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
9332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
9342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos > anchorPosition) {
9352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
9362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
9372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
9382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
9392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
9402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
9412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_END;
9432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
9442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_TAIL;
9452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
9482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenHorizontal(int dx) {
9492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenHorizontal(dx);
9502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
9512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dx);
9522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
9562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenVertical(int dy) {
9572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenVertical(dy);
9582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
9592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dy);
9602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
9642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
9652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (!considerSpanInvalidate(positionStart, itemCount)) {
9662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // If positions are not invalidated, move span offsets.
9672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLazySpanLookup.offsetForRemoval(positionStart, itemCount);
9682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
9722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
9732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (!considerSpanInvalidate(positionStart, itemCount)) {
9742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // If positions are not invalidated, move span offsets.
9752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLazySpanLookup.offsetForAddition(positionStart, itemCount);
9762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
9802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Checks whether it should invalidate span assignments in response to an adapter change.
9812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
9822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean considerSpanInvalidate(int positionStart, int itemCount) {
9832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition();
9842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (positionStart + itemCount <= minPosition) {
9852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return false;// nothing to update.
9862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition();
9882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.invalidateAfter(positionStart);
9892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (positionStart <= maxPosition) {
9902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
9912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return true;
9932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
9962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mRemainingSpans.set(0, mSpanCount, true);
9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // The target position we are trying to reach.
9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int targetLine;
10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /*
10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * The line until which we can recycle, as long as we add views.
10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * Keep in mind, it is still the line in layout direction which means; to calculate the
10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * actual recycle line, we should subtract/add the size in orientation.
10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        */
10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int recycleLine;
10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Line of the furthest row.
10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
10093ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
10100ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable;
10110ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding();
10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getStartAfterPadding();
10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span span = mSpans[i];
10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int line = span.getEndLine(defaultLine);
10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (line > targetLine) {
10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mRemainingSpans.set(i, false);
10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // LAYOUT_START
10213ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
10220ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable;
10230ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine - mLayoutState.mExtra -
10240ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                    mPrimaryOrientation.getStartAfterPadding();
10252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span span = mSpans[i];
10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int defaultLine = mPrimaryOrientation.getEndAfterPadding();
10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int line = span.getStartLine(defaultLine);
10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (line < targetLine) {
10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mRemainingSpans.set(i, false);
10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int widthSpec, heightSpec;
10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mOrientation == VERTICAL) {
10372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            widthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
10382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
10392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
10402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            heightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
10412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
10422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) {
10452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View view = layoutState.next(recycler);
10462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = ((LayoutParams) view.getLayoutParams());
10472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
10482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                addView(view);
10492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                addView(view, 0);
10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (lp.mFullSpan) {
10532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int fullSizeSpec = View.MeasureSpec.makeMeasureSpec(
10542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY);
10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mOrientation == VERTICAL) {
10562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    measureChildWithDecorationsAndMargin(view, fullSizeSpec, heightSpec);
10572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
10582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    measureChildWithDecorationsAndMargin(view, widthSpec, fullSizeSpec);
10592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
10602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
10612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                measureChildWithDecorationsAndMargin(view, widthSpec, heightSpec);
10622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int position = getPosition(view);
10652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanIndex = mLazySpanLookup.getSpan(position);
10662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span currentSpan;
10672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanIndex == LayoutParams.INVALID_SPAN_ID) {
10682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
10692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // assign full span items to first span
10702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    currentSpan = mSpans[0];
10712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
10722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    currentSpan = getNextSpan(layoutState);
10732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
10742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.setSpan(position, currentSpan);
10752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
10762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                currentSpan = mSpans[spanIndex];
10772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int start;
10792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int end;
10802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
10812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int def = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding()
10822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        : mPrimaryOrientation.getStartAfterPadding();
10832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                start = lp.mFullSpan ? getMaxEnd(def) : currentSpan.getEndLine(def);
10842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                end = start + mPrimaryOrientation.getDecoratedMeasurement(view);
10852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
10862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int i = 0; i < mSpanCount; i++) {
10872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[i].appendToSpan(view);
10882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
10892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
10902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    currentSpan.appendToSpan(view);
10912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
10922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
10932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int def = mShouldReverseLayout ? mPrimaryOrientation.getEndAfterPadding()
10942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        : mPrimaryOrientation.getStartAfterPadding();
10952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                end = lp.mFullSpan ? getMinStart(def) : currentSpan.getStartLine(def);
10962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                start = end - mPrimaryOrientation.getDecoratedMeasurement(view);
10972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
10982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int i = 0; i < mSpanCount; i++) {
10992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[i].prependToSpan(view);
11002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
11012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
11022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    currentSpan.prependToSpan(view);
11032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
11042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = currentSpan;
11072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (DEBUG) {
11092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Log.d(TAG, "adding view item " + lp.getViewPosition() + " between " + start + ","
11102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        + end);
11112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
11142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : currentSpan.mIndex * mSizePerSpan + mSecondaryOrientation
11152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            .getStartAfterPadding();
11162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
11172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mOrientation == VERTICAL) {
11182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
11192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
11202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd);
11212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (lp.mFullSpan) {
11232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
11242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    updateRemainingSpans(mSpans[i], mLayoutState.mLayoutDirection, targetLine);
11252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
11262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
11272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
11282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mLayoutState.mLayoutDirection == LAYOUT_START) {
11302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // calculate recycle line
11312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int maxStart = getMaxStart(currentSpan.getStartLine());
11320ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                recycleFromEnd(recycler, Math.max(recycleLine, maxStart) +
11330ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                        (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
11342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
11352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // calculate recycle line
11362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int minEnd = getMinEnd(currentSpan.getEndLine());
11370ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                recycleFromStart(recycler, Math.min(recycleLine, minEnd) -
11380ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar                        (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
11392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
11422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "fill, " + getChildCount());
11432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLayoutState.mLayoutDirection == LAYOUT_START) {
11452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding());
11460ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart));
11472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
11482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
11490ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (max - recycleLine));
11502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void layoutDecoratedWithMargins(View child, int left, int top, int right,
11542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int bottom) {
11552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
11562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin
11572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                , bottom - lp.bottomMargin);
11582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateRemainingSpans(Span span, int layoutDir, int targetLine) {
11612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int deletedSize = span.getDeletedSize();
11622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutDir == LAYOUT_START) {
11632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getStartLine();
11642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line + deletedSize < targetLine) {
11652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
11662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
11682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getEndLine();
11692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line - deletedSize > targetLine) {
11702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
11712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxStart(int def) {
11762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxStart = mSpans[0].getStartLine(def);
11772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
11782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
11792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart > maxStart) {
11802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxStart = spanStart;
11812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxStart;
11842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinStart(int def) {
11872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minStart = mSpans[0].getStartLine(def);
11882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
11892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
11902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart < minStart) {
11912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minStart = spanStart;
11922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minStart;
11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxEnd(int def) {
11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxEnd = mSpans[0].getEndLine(def);
11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd > maxEnd) {
12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxEnd = spanEnd;
12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxEnd;
12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinEnd(int def) {
12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minEnd = mSpans[0].getEndLine(def);
12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd < minEnd) {
12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minEnd = spanEnd;
12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minEnd;
12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromStart(RecyclerView.Recycler recycler, int line) {
12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "recycling from start for line " + line);
12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (getChildCount() > 0) {
12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(0);
12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedEnd(child) < line) {
12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popStart();
12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popStart();
12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromEnd(RecyclerView.Recycler recycler, int line) {
12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int i;
12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (i = childCount - 1; i >= 0; i--) {
12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(i);
12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) > line) {
12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
12482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popEnd();
12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
12532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popEnd();
12542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
12552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
12562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
12582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
12632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Finds the span for the next view.
12642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
12652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span getNextSpan(LayoutState layoutState) {
12662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final boolean preferLastSpan = mOrientation == VERTICAL && isLayoutRTL();
12672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
12682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span min = mSpans[0];
12692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int minLine = min.getEndLine(mPrimaryOrientation.getStartAfterPadding());
12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getStartAfterPadding();
12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 1; i < mSpanCount; i++) {
12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int otherLine = other.getEndLine(defaultLine);
12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (otherLine < minLine || (otherLine == minLine && preferLastSpan)) {
12752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    min = other;
12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    minLine = otherLine;
12772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
12782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return min;
12802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span max = mSpans[0];
12822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int maxLine = max.getStartLine(mPrimaryOrientation.getEndAfterPadding());
12832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getEndAfterPadding();
12842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 1; i < mSpanCount; i++) {
12852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
12862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int otherLine = other.getStartLine(defaultLine);
12872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (otherLine > maxLine || (otherLine == maxLine && !preferLastSpan)) {
12882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    max = other;
12892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    maxLine = otherLine;
12902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
12912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return max;
12932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollVertically() {
12982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == VERTICAL;
12992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollHorizontally() {
13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == HORIZONTAL;
13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
13082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
13092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dx, recycler, state);
13102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
13132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
13142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
13152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dy, recycler, state);
13162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int calculateScrollDirectionForPosition(int position) {
13192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() == 0) {
13202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START;
13212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int firstChildPos = getFirstChildPosition();
13232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
13242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
13272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
13282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int position) {
13292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) {
13302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
13312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public PointF computeScrollVectorForPosition(int targetPosition) {
13322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int direction = calculateScrollDirectionForPosition(targetPosition);
13332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (direction == 0) {
13342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return null;
13352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
13362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mOrientation == HORIZONTAL) {
13372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(direction, 0);
13382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
13392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(0, direction);
13402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
13422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        scroller.setTargetPosition(position);
13442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        startSmoothScroll(scroller);
13452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPosition(int position) {
13492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) {
13502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
13512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
13532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
13542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
13552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Scroll to the specified adapter position with the given offset from layout start.
13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
13602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Note that scroll position change will not be reflected until the next layout call.
13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
13622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
13632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
13642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param position Index (starting at 0) of the reference item.
13652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param offset   The distance (in pixels) between the start edge of the item view and
13662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                 start edge of the RecyclerView.
13672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
13682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #scrollToPosition(int)
13692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
13702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPositionWithOffset(int position, int offset) {
13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
13722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
13732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
13752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = offset;
13762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
13772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
13802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
13812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int referenceChildPosition;
13822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (dt > 0) { // layout towards end
13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_END;
13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
13852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_TAIL;
13862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getLastChildPosition();
13872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_START;
13892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
13902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_HEAD;
13912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getFirstChildPosition();
13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
13942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int absDt = Math.abs(dt);
13952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = absDt;
13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0;
13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int consumed = fill(recycler, mLayoutState, state);
13982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int totalScroll;
13992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (absDt < consumed) {
14002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = dt;
14012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (dt < 0) {
14022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = -consumed;
14032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // dt > 0
14042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = consumed;
14052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
14072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "asked " + dt + " scrolled" + totalScroll);
14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mGapStrategy == GAP_HANDLING_LAZY
14112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                && mLayoutState.mItemDirection == ITEM_DIRECTION_HEAD) {
14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetStart = mPrimaryOrientation.getStartAfterPadding();
14132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetEnd = mPrimaryOrientation.getEndAfterPadding();
14142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lazyOffsetSpans(-totalScroll, targetStart, targetEnd);
14152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
14162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(-totalScroll);
14172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // always reset this if we scroll for a proper save instance state
14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLastLayoutFromEnd = mShouldReverseLayout;
14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (totalScroll != 0 && mGapStrategy != GAP_HANDLING_NONE
14222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                && mLayoutState.mItemDirection == ITEM_DIRECTION_HEAD && !mHasGaps) {
14232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int addedChildCount = Math.abs(mLayoutState.mCurrentPosition
14242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    - (referenceChildPosition + mLayoutState.mItemDirection));
14252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (addedChildCount > 0) {
14262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // check if any child has been attached to wrong span. If so, trigger a re-layout
14272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // after scroll
14282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View viewInWrongSpan;
14292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View referenceView = findViewByPosition(referenceChildPosition);
14302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (referenceView == null) {
14312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    viewInWrongSpan = hasGapsToFix(0, getChildCount());
14322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
14332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (mLayoutState.mLayoutDirection == LAYOUT_START) {
14342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        viewInWrongSpan = hasGapsToFix(0, addedChildCount);
14352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    } else {
14362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        viewInWrongSpan = hasGapsToFix(getChildCount() - addedChildCount,
14372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                getChildCount());
14382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
14392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
14402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mHasGaps = viewInWrongSpan != null;
14412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
14422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return totalScroll;
14442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
14472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * The actual method that implements {@link #GAP_HANDLING_LAZY}
14482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
14492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void lazyOffsetSpans(int offset, int targetStart, int targetEnd) {
14502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // For each span offset children one by one.
14512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // When a fullSpan item is reached, stop and wait for other spans to reach to that span.
14522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // When all reach, offset fullSpan to max of others and continue.
14532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int childrenToOffset = getChildCount();
14542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] indexPerSpan = new int[mSpanCount];
14552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] offsetPerSpan = new int[mSpanCount];
14562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childOrder = offset > 0 ? ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD;
14582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (offset > 0) {
14592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(indexPerSpan, 0);
14602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
14612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
14622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                indexPerSpan[i] = mSpans[i].mViews.size() - 1;
14632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
14642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
14672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            offsetPerSpan[i] = mSpans[i].getNormalizedOffset(offset, targetStart, targetEnd);
14682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
14702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "lazy offset start. normalized: " + Arrays.toString(offsetPerSpan));
14712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (childrenToOffset > 0) {
14742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View fullSpanView = null;
14752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) {
14762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Span span = mSpans[spanIndex];
14772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int viewIndex;
14782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (viewIndex = indexPerSpan[spanIndex];
14792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        viewIndex < span.mViews.size() && viewIndex >= 0; viewIndex += childOrder) {
14802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    View view = span.mViews.get(viewIndex);
14812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (DEBUG) {
14822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        Log.d(TAG, "span " + spanIndex + ", view:" + viewIndex + ", pos:"
14832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                + getPosition(view));
14842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
14852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
14862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (lp.mFullSpan) {
14872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (DEBUG) {
14882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            Log.d(TAG, "stopping on full span view on index " + viewIndex
14892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    + " in span " + spanIndex);
14902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
14912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        fullSpanView = view;
14922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        viewIndex += childOrder;// move to next view
14932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        break;
14942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
14952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // offset this child normally
14962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mPrimaryOrientation.offsetChild(view, offsetPerSpan[spanIndex]);
14972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    final int nextChildIndex = viewIndex + childOrder;
14982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (nextChildIndex < span.mViews.size() && nextChildIndex >= 0) {
14992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        View nextView = span.mViews.get(nextChildIndex);
15002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        // find gap between, before offset
15012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (childOrder == ITEM_DIRECTION_HEAD) {// negative
15022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            offsetPerSpan[spanIndex] = Math
15032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    .min(0, mPrimaryOrientation.getDecoratedStart(view)
15042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                            - mPrimaryOrientation.getDecoratedEnd(nextView));
15052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
15062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            offsetPerSpan[spanIndex] = Math
15072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    .max(0, mPrimaryOrientation.getDecoratedEnd(view) -
15082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                            mPrimaryOrientation.getDecoratedStart(nextView));
15092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
15102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (DEBUG) {
15112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            Log.d(TAG, "offset diff:" + offsetPerSpan[spanIndex] + " between "
15122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    + getPosition(nextView) + " and " + getPosition(view));
15132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
15142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
15152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    childrenToOffset--;
15162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
15172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                indexPerSpan[spanIndex] = viewIndex;
15182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (fullSpanView != null) {
15202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                // we have to offset this view. We'll offset it as the biggest amount necessary
15212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int winnerSpan = 0;
15222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int winnerSpanOffset = Math.abs(offsetPerSpan[winnerSpan]);
15232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 1; i < mSpanCount; i++) {
15242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    final int spanOffset = Math.abs(offsetPerSpan[i]);
15252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (spanOffset > winnerSpanOffset) {
15262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        winnerSpan = i;
15272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        winnerSpanOffset = spanOffset;
15282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
15292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
15302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (DEBUG) {
15312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    Log.d(TAG, "winner offset:" + offsetPerSpan[winnerSpan] + " of " + winnerSpan);
15322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
15332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mPrimaryOrientation.offsetChild(fullSpanView, offsetPerSpan[winnerSpan]);
15342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                childrenToOffset--;
15352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) {
15372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    final int nextViewIndex = indexPerSpan[spanIndex];
15382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    final Span span = mSpans[spanIndex];
15392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    if (nextViewIndex < span.mViews.size() && nextViewIndex > 0) {
15402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        View nextView = span.mViews.get(nextViewIndex);
15412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        // find gap between, before offset
15422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        if (childOrder == ITEM_DIRECTION_HEAD) {// negative
15432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            offsetPerSpan[spanIndex] = Math
15442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    .min(0, mPrimaryOrientation.getDecoratedStart(fullSpanView)
15452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                            - mPrimaryOrientation.getDecoratedEnd(nextView));
15462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        } else {
15472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                            offsetPerSpan[spanIndex] = Math
15482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                    .max(0, mPrimaryOrientation.getDecoratedEnd(fullSpanView) -
15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                                            mPrimaryOrientation.getDecoratedStart(nextView));
15502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        }
15512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
15522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
15532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int spanIndex = 0; spanIndex < mSpanCount; spanIndex++) {
15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[spanIndex].invalidateCache();
15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getLastChildPosition() {
15612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
15622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1));
15632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getFirstChildPosition() {
15662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
15672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(0));
15682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1570719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1571719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the first View that can be used as an anchor View.
1572719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1573719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1574719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1575719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findFirstReferenceChildPosition(int itemCount) {
1576719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        final int limit = getChildCount();
1577719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = 0; i < limit; i++) {
1578719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1579719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1580719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1581719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1582719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1583719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1584719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1585719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1586719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1587719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1588719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the last View that can be used as an anchor View.
1589719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1590719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1591719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1592719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findLastReferenceChildPosition(int itemCount) {
1593719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
1594719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1595719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1596719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1597719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1598719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1599719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1600719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1601719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1602719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
16062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT);
16072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
16112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(c, attrs);
16122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
16162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (lp instanceof ViewGroup.MarginLayoutParams) {
16172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
16182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
16192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams(lp);
16202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
16252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return lp instanceof LayoutParams;
16262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getOrientation() {
16292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation;
16302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
16342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * LayoutParams used by StaggeredGridLayoutManager.
16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
16362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static class LayoutParams extends RecyclerView.LayoutParams {
16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
16392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Span Id for Views that are not laid out yet.
16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final int INVALID_SPAN_ID = -1;
16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Package scope to be able to access from tests.
16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        Span mSpan;
16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mFullSpan;
16472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(Context c, AttributeSet attrs) {
16492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(c, attrs);
16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(int width, int height) {
16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(width, height);
16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.MarginLayoutParams source) {
16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.LayoutParams source) {
16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(RecyclerView.LayoutParams source) {
16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * When set to true, the item will layout using all span area. That means, if orientation
16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * is vertical, the view will have full width; if orientation is horizontal, the view will
16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * have full height.
16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param fullSpan True if this item should traverse all spans.
16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void setFullSpan(boolean fullSpan) {
16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mFullSpan = fullSpan;
16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns the Span index to which this View is assigned.
16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return The Span index of the View. If View is not yet assigned to any span, returns
16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * {@link #INVALID_SPAN_ID}.
16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public final int getSpanIndex() {
16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpan == null) {
16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return INVALID_SPAN_ID;
16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mSpan.mIndex;
16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    // Package scoped to access from tests.
16942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    class Span {
16952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16966b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        static final int INVALID_LINE = Integer.MIN_VALUE;
16972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private ArrayList<View> mViews = new ArrayList<View>();
16992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedStart = INVALID_LINE;
17012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedEnd = INVALID_LINE;
17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mDeletedSize = 0;
17052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mIndex;
17072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private Span(int index) {
17092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mIndex = index;
17102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine(int def) {
17132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
17142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
17152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
17172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
17182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mPrimaryOrientation.getDecoratedStart(mViews.get(0));
17202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine() {
17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mPrimaryOrientation.getDecoratedStart(mViews.get(0));
17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
17302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine(int def) {
17332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
17352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 0) {
17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mPrimaryOrientation.getDecoratedEnd(mViews.get(size - 1));
17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine() {
17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mPrimaryOrientation.getDecoratedEnd(mViews.get(mViews.size() - 1));
17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void prependToSpan(View view) {
17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(0, view);
17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17617c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void appendToSpan(View view) {
17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(view);
17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
17752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Useful method to preserve positions on a re-layout.
17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void cacheReferenceLineAndClear(boolean reverseLayout, int offset) {
17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int reference;
17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reverseLayout) {
17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getEndLine(INVALID_LINE);
17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getStartLine(INVALID_LINE);
17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            clear();
17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reference == INVALID_LINE) {
17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (offset != INVALID_OFFSET) {
17922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference += offset;
17932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mCachedEnd = reference;
17952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
17982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.clear();
17992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateCache();
18002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mDeletedSize = 0;
18012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateCache() {
18042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
18052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
18062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setLine(int line) {
18092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mCachedStart = line;
18102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popEnd() {
18132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
18142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View end = mViews.remove(size - 1);
18152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(end);
18162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
18177c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
18182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end);
18192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 1) {
18212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
18222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popStart() {
18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View start = mViews.remove(0);
18282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(start);
18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18337c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start);
18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // TODO cache this.
18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int getDeletedSize() {
18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mDeletedSize;
18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams getLayoutParams(View view) {
18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return (LayoutParams) view.getLayoutParams();
18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void onOffset(int dt) {
18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart += dt;
18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd += dt;
18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // normalized offset is how much this span can scroll
18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getNormalizedOffset(int dt, int targetStart, int targetEnd) {
18592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return 0;
18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (dt < 0) {
18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int endSpace = getEndLine() - targetEnd;
18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (endSpace <= 0) {
18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return -dt > endSpace ? -endSpace : dt;
18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int startSpace = targetStart - getStartLine();
18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (startSpace <= 0) {
18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return startSpace < dt ? startSpace : dt;
18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
18782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns if there is no child between start-end lines
18792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
18802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param start The start line
18812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param end   The end line
18822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return true if a new child can be added between start and end
18832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
18842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean isEmpty(int start, int end) {
18852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int count = mViews.size();
18862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < count; i++) {
18872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View view = mViews.get(i);
18882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mPrimaryOrientation.getDecoratedStart(view) < end &&
18892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mPrimaryOrientation.getDecoratedEnd(view) > start) {
18902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return false;
18912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
18922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return true;
18942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstVisibleItemPosition() {
1897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
1898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(mViews.size() - 1, -1, false)
1899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), false);
1900333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1901333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstCompletelyVisibleItemPosition() {
1903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
1904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(mViews.size() -1, -1, true)
1905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), true);
1906333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1907333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1908333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastVisibleItemPosition() {
1909333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
1910333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), false)
1911333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, false);
1912333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1913333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1914333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastCompletelyVisibleItemPosition() {
1915333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
1916333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), true)
1917333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, true);
1918333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1919333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1920333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
1921333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int start = mPrimaryOrientation.getStartAfterPadding();
1922333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int end = mPrimaryOrientation.getEndAfterPadding();
1923333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int next = toIndex > fromIndex ? 1 : -1;
1924333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            for (int i = fromIndex; i != toIndex; i+=next) {
1925333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final View child = mViews.get(i);
1926333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
1927333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
1928333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                if (childStart < end && childEnd > start) {
1929333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    if (completelyVisible) {
1930333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        if (childStart >= start && childEnd <= end) {
1931333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                            return getPosition(child);
1932333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        }
1933333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    } else {
1934333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        return getPosition(child);
1935333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    }
1936333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                }
1937333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
1938333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return RecyclerView.NO_POSITION;
1939333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
19402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
19432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * An array of mappings from adapter position to span.
19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * This only grows when a write happens and it grows up to the size of the adapter.
19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
19462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class LazySpanLookup {
19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private static final int MIN_SIZE = 10;
19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mData;
19512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAdapterSize; // we don't want to grow beyond that, unless it grows
19532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateAfter(int position) {
19552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
19562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
19572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (position >= mData.length) {
19592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
19602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID);
19622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getSpan(int position) {
19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null || position >= mData.length) {
19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return LayoutParams.INVALID_SPAN_ID;
19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
19682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mData[position];
19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setSpan(int position, Span span) {
19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(position);
19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mData[position] = span.mIndex;
19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int sizeForPosition(int position) {
19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int len = mData.length;
19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            while (len <= position) {
19802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len *= 2;
19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (len > mAdapterSize) {
19832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len = mAdapterSize;
19842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return len;
19862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void ensureSize(int position) {
19892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
19902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[Math.max(position, MIN_SIZE) + 1];
19912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
19922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else if (position >= mData.length) {
19932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int[] old = mData;
19942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[sizeForPosition(position)];
19952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                System.arraycopy(old, 0, mData, 0, old.length);
19962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID);
19972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData != null) {
20022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForRemoval(int positionStart, int itemCount) {
20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart + itemCount, mData, positionStart,
20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, mData.length - itemCount, mData.length,
20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForAddition(int positionStart, int itemCount) {
20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
20162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart, mData, positionStart + itemCount,
20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, positionStart, positionStart + itemCount,
20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class SavedState implements Parcelable {
20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mOrientation;
20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mSpanCount;
20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mGapStrategy;
20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAnchorPosition;
20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2033333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        int mVisibleAnchorPosition; // if span count changes (span offsets are invalidated),
2034333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        // we use this one instead
2035333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanOffsets;
20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mSpanLookupSize;
20392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanLookup;
20412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mReverseLayout;
20432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mAnchorLayoutFromEnd;
20452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mHasSpanOffsets;
20472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState() {
20492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState(Parcel in) {
20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mOrientation = in.readInt();
20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = in.readInt();
20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mGapStrategy = in.readInt();
20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = in.readInt();
2056333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = in.readInt();
20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mHasSpanOffsets = in.readInt() == 1;
20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mHasSpanOffsets) {
20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpanOffsets = new int[mSpanCount];
20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanOffsets);
20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = in.readInt();
20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpanLookup = new int[mSpanLookupSize];
20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanLookup);
20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = in.readInt() == 1;
20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = in.readInt() == 1;
20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState(SavedState other) {
20732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mOrientation = other.mOrientation;
20742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = other.mSpanCount;
20752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mGapStrategy = other.mGapStrategy;
20762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = other.mAnchorPosition;
2077333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = other.mVisibleAnchorPosition;
20782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mHasSpanOffsets = other.mHasSpanOffsets;
20792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = other.mSpanOffsets;
20802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = other.mSpanLookupSize;
20812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = other.mSpanLookup;
20822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = other.mReverseLayout;
20832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
20842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateSpanInfo() {
20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mHasSpanOffsets = false;
20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = -1;
20902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = 0;
20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = null;
20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateAnchorPositionInfo() {
20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mHasSpanOffsets = false;
20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = RecyclerView.NO_POSITION;
2098333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = RecyclerView.NO_POSITION;
20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
21022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int describeContents() {
21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return 0;
21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void writeToParcel(Parcel dest, int flags) {
21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mOrientation);
21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mSpanCount);
21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mGapStrategy);
21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorPosition);
2112333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            dest.writeInt(mVisibleAnchorPosition);
21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mHasSpanOffsets ? 1 : 0);
21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mHasSpanOffsets) {
21152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanOffsets);
21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mSpanLookupSize);
21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanLookup);
21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mReverseLayout ? 1 : 0);
21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public String toString() {
21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return "SavedState{" +
21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    "mOrientation=" + mOrientation +
21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mSpanCount=" + mSpanCount +
21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mGapStrategy=" + mGapStrategy +
21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mAnchorPosition=" + mAnchorPosition +
2132333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ", mVisibleAnchorPosition=" + mVisibleAnchorPosition +
21332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mSpanOffsets=" + Arrays.toString(mSpanOffsets) +
21342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mSpanLookupSize=" + mSpanLookupSize +
21352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mSpanLookup=" + Arrays.toString(mSpanLookup) +
21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mReverseLayout=" + mReverseLayout +
21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mAnchorLayoutFromEnd=" + mAnchorLayoutFromEnd +
21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    ", mHasSpanOffsets=" + mHasSpanOffsets +
21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    '}';
21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final Parcelable.Creator<SavedState> CREATOR
21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                = new Parcelable.Creator<SavedState>() {
21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState createFromParcel(Parcel in) {
21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState(in);
21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState[] newArray(int size) {
21512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState[size];
21522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
21542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
21552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar}
2156