StaggeredGridLayoutManager.java revision 7499c6e5b853057aa81bfc20c39e6fa188805c55
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;
25a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityEventCompat;
26a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
27a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityRecordCompat;
282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.AttributeSet;
292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.Log;
302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.View;
312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.ViewGroup;
32a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent;
332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.ArrayList;
352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.Arrays;
362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.BitSet;
37d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport java.util.List;
382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START;
402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END;
412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_HEAD;
422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_TAIL;
43d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION;
44d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/**
462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * A LayoutManager that lays out children in a staggered grid formation.
472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It supports horizontal & vertical layout as well as an ability to layout children in reverse.
482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p>
492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps,
502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can
512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * control this behavior via {@link #setGapStrategy(int)}.
522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */
532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarpublic class StaggeredGridLayoutManager extends RecyclerView.LayoutManager {
542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final String TAG = "StaggeredGridLayoutManager";
562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private static final boolean DEBUG = false;
582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5903a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
6003a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
6103a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int VERTICAL = OrientationHelper.VERTICAL;
6203a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
64d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Does not do anything to hide gaps.
652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_NONE = 0;
672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
68d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Deprecated
692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_LAZY = 1;
702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
72d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * When scroll state is changed to {@link RecyclerView#SCROLL_STATE_IDLE}, StaggeredGrid will
73d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * check if there are gaps in the because of full span items. If it finds, it will re-layout
74d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * and move items to correct positions with animations.
752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For example, if LayoutManager ends up with the following layout due to adapter changes:
772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * _BC
802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * It will animate to the following state:
832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <code>
842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BC_
862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * </code>
882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private static final int INVALID_OFFSET = Integer.MIN_VALUE;
922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Number of spans
952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSpanCount = -1;
972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span[] mSpans;
992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Primary orientation is the layout's orientation, secondary orientation is the orientation
1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for spans. Having both makes code much cleaner for calculations.
1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mPrimaryOrientation;
1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mSecondaryOrientation;
1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mOrientation;
1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * The width or height per span, depending on the orientation.
1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSizePerSpan;
1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private LayoutState mLayoutState;
1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mReverseLayout = false;
1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Aggregated reverse layout value that takes RTL into account.
1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
121d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean mShouldReverseLayout = false;
1222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Temporary variable used during fill method to check which spans needs to be filled.
1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private BitSet mRemainingSpans;
1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout which will check this variable and re-layout accordingly.
1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
132d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    int mPendingScrollPosition = NO_POSITION;
1332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * called.
1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1386e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPositionOffset = INVALID_OFFSET;
1392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Keeps the mapping between the adapter positions and spans. This is necessary to provide
1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * a consistent experience when user scrolls the list.
1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    LazySpanLookup mLazySpanLookup = new LazySpanLookup();
1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * how we handle gaps in UI.
1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Saved state needs this information to properly layout on restore.
1532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mLastLayoutFromEnd;
1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
157d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Saved state and onLayout needs this information to re-layout properly
158d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLastLayoutRTL;
160d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
161d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
1622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * SavedState is not handled until a layout happens. This is where we keep it until next
1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout.
1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private SavedState mPendingSavedState;
1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
168d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used measurement specs. updated by onLayout.
1692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
170d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int mFullSizeSpec, mWidthSpec, mHeightSpec;
171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
172d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used anchor info.
174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
175d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private final AnchorInfo mAnchorInfo = new AnchorInfo();
176d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * If a full span item is invalid / or created in reverse direction; it may create gaps in
179d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the UI. While laying out, if such case is detected, we set this flag.
180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * After scrolling stops, we check this flag and if it is set, re-layout.
182d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
183d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLaidOutInvalidFullSpan = false;
184d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
185d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
186d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}.
187d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}
188d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
189d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mSmoothScrollbarEnabled = true;
190d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
191d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private final Runnable checkForGapsRunnable = new Runnable() {
192d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        @Override
193d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void run() {
194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
196d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    };
1972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Creates a StaggeredGridLayoutManager with given parameters.
2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount   If orientation is vertical, spanCount is number of columns. If
2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    orientation is horizontal, spanCount is number of rows.
2039bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar     * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL}
2042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public StaggeredGridLayoutManager(int spanCount, int orientation) {
2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        setSpanCount(spanCount);
2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
210d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps in the UI that may be caused by adapter changes.
212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * When a full span item is laid out in reverse direction, it sets a flag which we check when
214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll is stopped (or re-layout happens) and re-layout after first valid item.
215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void checkForGaps() {
217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE) {
218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int minPos, maxPos;
221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getLastChildPosition();
223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getFirstChildPosition();
224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getFirstChildPosition();
226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getLastChildPosition();
227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (minPos == 0) {
229d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View gapView = hasGapsToFix();
230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (gapView != null) {
231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestSimpleAnimationsInNextLayout();
233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestLayout();
234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (!mLaidOutInvalidFullSpan) {
238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup
242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir);
243d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (invalidFsi == null) {
244d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLaidOutInvalidFullSpan = false;
245d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(maxPos + 1);
246d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
247d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup
249d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition,
250d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        invalidGapDir * -1);
251d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (validFsi == null) {
252d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition);
253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1);
255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestSimpleAnimationsInNextLayout();
257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onScrollStateChanged(int state) {
262d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state == RecyclerView.SCROLL_STATE_IDLE) {
263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
270d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].clear();
271d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
272d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
273d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
274d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps if we've reached to the top of the list.
276d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field.
278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    View hasGapsToFix() {
280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int startChildIndex = 0;
281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int endChildIndex = getChildCount() - 1;
282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        BitSet mSpansToCheck = new BitSet(mSpanCount);
283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mSpansToCheck.set(0, mSpanCount, true);
284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int firstChildIndex, childLimit;
286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1;
287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            firstChildIndex = endChildIndex - 1;
290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            childLimit = startChildIndex - 1;
291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            firstChildIndex = startChildIndex;
293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            childLimit = endChildIndex;
294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1;
296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) {
297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View child = getChildAt(i);
298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            LayoutParams lp = (LayoutParams) child.getLayoutParams();
299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpansToCheck.get(lp.mSpan.mIndex)) {
300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (checkSpanForGap(lp.mSpan)) {
301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return child;
302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mSpansToCheck.clear(lp.mSpan.mIndex);
304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue; // quick reject
307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (i + nextChildDiff != childLimit) {
310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                View nextChild = getChildAt(i + nextChildDiff);
311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                boolean compareSpans = false;
312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mShouldReverseLayout) {
313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // ensure child's end is below nextChild's end
314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myEnd = mPrimaryOrientation.getDecoratedEnd(child);
315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild);
316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myEnd < nextEnd) {
317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;//i should have a better position
318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myEnd == nextEnd) {
319d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myStart = mPrimaryOrientation.getDecoratedStart(child);
323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild);
324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myStart > nextStart) {
325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;//i should have a better position
326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myStart == nextStart) {
327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (compareSpans) {
331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // equal, check span indices.
332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams();
333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) {
334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;
335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // everything looks good
340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return null;
341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean checkSpanForGap(Span span) {
344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) {
346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return true;
347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) {
349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return true;
350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return false;
3522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the number of spans for the layout. This will invalidate all of the span assignments
3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for Views.
3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calling this method will automatically result in a new layout request unless the spanCount
3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * parameter is equal to current span count.
3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount Number of spans to layout
3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setSpanCount(int spanCount) {
3640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (spanCount != mSpanCount) {
3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateSpanAssignments();
3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = spanCount;
3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mRemainingSpans = new BitSet(mSpanCount);
3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans = new Span[mSpanCount];
3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpans[i] = new Span(i);
3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep
379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll position if this method is called after views are laid out.
3802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
3822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setOrientation(int orientation) {
3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation != HORIZONTAL && orientation != VERTICAL) {
3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid orientation.");
3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3870bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation == mOrientation) {
3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation != null && mSecondaryOrientation != null) {
3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // swap
3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            OrientationHelper tmp = mPrimaryOrientation;
3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = mSecondaryOrientation;
3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = tmp;
3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets whether LayoutManager should start laying out items from the end of the UI. The order
4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * items are traversed is not affected by this call.
4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * For vertical layout, if it is set to <code>true</code>, first item will be at the bottom of
406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the list.
4072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For horizontal layouts, it depends on the layout direction.
4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if
4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link RecyclerView}} is RTL, it will layout from LTR.
4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param reverseLayout Whether layout should be in reverse or not
4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setReverseLayout(boolean reverseLayout) {
4150bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) {
4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mReverseLayout = reverseLayout;
4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mReverseLayout = reverseLayout;
4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the current gap handling strategy for StaggeredGridLayoutManager.
4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps,
427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and
428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details.
4292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}.
4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Current gap handling strategy.
4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setGapStrategy(int)
4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_NONE
4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getGapStrategy() {
4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mGapStrategy;
4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter
4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * is different than the current strategy, calling this method will trigger a layout request.
4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param gapStrategy The new gap handling strategy. Should be
446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link
447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    #GAP_HANDLING_NONE}.
4482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #getGapStrategy()
4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setGapStrategy(int gapStrategy) {
4510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gapStrategy == mGapStrategy) {
4532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (gapStrategy != GAP_HANDLING_NONE &&
4562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE "
458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
4592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mGapStrategy = gapStrategy;
4612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4640bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    @Override
4650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void assertNotInLayoutOrScroll(String message) {
4660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        if (mPendingSavedState == null) {
4670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            super.assertNotInLayoutOrScroll(message);
4680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
4690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
4700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
4712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the number of spans laid out by StaggeredGridLayoutManager.
4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Number of spans in the layout
4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getSpanCount() {
4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mSpanCount;
4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items.
4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you need to cancel current assignments, you can call this method which will clear all
4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * assignments and request a new layout.
4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void invalidateSpanAssignments() {
4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.clear();
4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void ensureOrientationHelper() {
4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation == null) {
4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation);
4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = OrientationHelper
4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    .createOrientationHelper(this, 1 - mOrientation);
4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState = new LayoutState();
4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calculates the views' layout order. (e.g. from end to start or start to end)
5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * RTL layout support is applied automatically. So if layout is RTL and
5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void resolveShouldLayoutReverse() {
5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // A == B is the same result, but we rather keep it readable
5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mOrientation == VERTICAL || !isLayoutRTL()) {
5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = mReverseLayout;
5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = !mReverseLayout;
5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
514d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean isLayoutRTL() {
5152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns whether views are laid out in reverse order or not.
5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Not that this value is not affected by RecyclerView's layout direction.
5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return True if layout is reversed, false otherwise
5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean getReverseLayout() {
5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mReverseLayout;
5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Update adapter size.
5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.mAdapterSize = state.getItemCount();
5352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final AnchorInfo anchorInfo = mAnchorInfo;
537d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.reset();
5382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            applyPendingSavedState(anchorInfo);
5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            resolveShouldLayoutReverse();
543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
5442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateAnchorInfoForLayout(state, anchorInfo);
5472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState == null) {
549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd ||
550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    isLayoutRTL() != mLastLayoutRTL) {
551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
5542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
5560ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar        if (getChildCount() > 0 && (mPendingSavedState == null ||
557b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar                mPendingSavedState.mSpanOffsetsSize < 1)) {
558d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (anchorInfo.mInvalidateOffsets) {
5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // Scroll to position is set, clear.
5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].clear();
562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mOffset != INVALID_OFFSET) {
563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mSpans[i].setLine(anchorInfo.mOffset);
5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset);
5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        detachAndScrapAttachedViews(recycler);
573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLaidOutInvalidFullSpan = false;
574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateMeasureSpecs();
575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (anchorInfo.mLayoutFromEnd) {
576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillStart(anchorInfo.mPosition, state);
578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
579d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
580d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillEnd(anchorInfo.mPosition, state);
5812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillEnd(anchorInfo.mPosition, state);
586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
588d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillStart(anchorInfo.mPosition, state);
5892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
590d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
5912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
5942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout) {
5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, true);
5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, false);
5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, true);
5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, false);
6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6036e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        if (!state.isPreLayout()) {
604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (getChildCount() > 0 && mPendingScrollPosition != NO_POSITION &&
605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLaidOutInvalidFullSpan) {
606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ViewCompat.postOnAnimation(getChildAt(0), checkForGapsRunnable);
607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = NO_POSITION;
6096e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
6106e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        }
611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = isLayoutRTL();
6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingSavedState = null; // we don't need this anymore
6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
6152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void applyPendingSavedState(AnchorInfo anchorInfo) {
617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
618d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "found saved state: " + mPendingSavedState);
6192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanOffsetsSize > 0) {
621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) {
622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].clear();
624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int line = mPendingSavedState.mSpanOffsets[i];
625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        if (mPendingSavedState.mAnchorLayoutFromEnd) {
627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getEndAfterPadding();
628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        } else {
629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getStartAfterPadding();
630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        }
631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].setLine(line);
633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
635d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.invalidateSpanInfo();
636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition;
637d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL;
640d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        setReverseLayout(mPendingSavedState.mReverseLayout);
641d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        resolveShouldLayoutReverse();
6422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
643d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mAnchorPosition != NO_POSITION) {
644d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
645d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
6462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
647d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
6482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanLookupSize > 1) {
650d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mData = mPendingSavedState.mSpanLookup;
651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems;
652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
653d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
655d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) {
656d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromPendingData(state, anchorInfo)) {
657d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
658d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
659d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromChildren(state, anchorInfo)) {
660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
662d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
663d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "Deciding anchor info from fresh state");
664d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
665d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.assignCoordinateFromPadding();
666d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = 0;
667d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
668d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
669d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) {
670d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // We don't recycle views out of adapter order. This way, we can rely on the first or
671d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // last child as the anchor position.
672d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Layout direction may change but we should select the child depending on the latest
673d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // layout direction. Otherwise, we'll choose the wrong child.
674d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = mLastLayoutFromEnd
675d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? findLastReferenceChildPosition(state.getItemCount())
676d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : findFirstReferenceChildPosition(state.getItemCount());
677d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mOffset = INVALID_OFFSET;
678d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
679d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
680d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
681d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) {
682d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate scroll position if exists.
683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) {
684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
685d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
686d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate it.
687d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
688d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = NO_POSITION;
689d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
690d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
691d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION
694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                || mPendingSavedState.mSpanOffsetsSize < 1) {
695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // If item is visible, make it fully visible.
696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = findViewByPosition(mPendingScrollPosition);
697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (child != null) {
698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Use regular anchor position, offset according to pending offset and target
699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child
700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition()
701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : getFirstChildPosition();
702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset != INVALID_OFFSET) {
704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mLayoutFromEnd) {
705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        final int target = mPrimaryOrientation.getEndAfterPadding() -
706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                                mPendingScrollPositionOffset;
707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child);
708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        final int target = mPrimaryOrientation.getStartAfterPadding() +
710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                                mPendingScrollPositionOffset;
711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child);
712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // no offset provided. Decide according to the child location
717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child);
718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (childSize > mPrimaryOrientation.getTotalSpace()) {
719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // Item does not fit. Fix depending on layout direction.
720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = anchorInfo.mLayoutFromEnd
721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            ? mPrimaryOrientation.getEndAfterPadding()
722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            : mPrimaryOrientation.getStartAfterPadding();
723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int startGap = mPrimaryOrientation.getDecoratedStart(child)
727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        - mPrimaryOrientation.getStartAfterPadding();
728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (startGap < 0) {
729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = -startGap;
730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
732d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int endGap = mPrimaryOrientation.getEndAfterPadding() -
733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mPrimaryOrientation.getDecoratedEnd(child);
734d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (endGap < 0) {
735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = endGap;
736d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
7372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
738d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child already visible. just layout as usual
739d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mOffset = INVALID_OFFSET;
740d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
741d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Child is not visible. Set anchor coordinate depending on in which direction
742d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child will be visible.
743d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mPendingScrollPosition;
744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset == INVALID_OFFSET) {
745d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    final int position = calculateScrollDirectionForPosition(
746d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            anchorInfo.mPosition);
747d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mLayoutFromEnd = position == LAYOUT_END;
748d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding();
749d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
750d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset);
751d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
752d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
7532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
754d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
755d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mOffset = INVALID_OFFSET;
756d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mPosition = mPendingScrollPosition;
757d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
758d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
759d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
760d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
761d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    void updateMeasureSpecs() {
762d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount;
763d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
764d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY);
765d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mOrientation == VERTICAL) {
766d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mWidthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
767d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mHeightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
768d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
769d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mHeightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
770d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mWidthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
7712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
7722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
7742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
7752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean supportsPredictiveItemAnimations() {
7766e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        return mPendingSavedState == null;
7772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
779333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
780333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first visible view for each span.
781333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
782333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
783333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
784333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
785333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
786333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
787333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
788333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
789333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
790333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
791333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
792333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
793d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first visible item in each span. If a span does not have
794d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
795333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
796333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
797333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
798333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstVisibleItemPositions(int[] into) {
799333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
800333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
801333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
802333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
803333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
804333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
805d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
806333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstVisibleItemPosition();
807333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
808333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
809333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
810333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
811333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
812333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first completely visible view for each span.
813333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
814333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
815333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
816333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
817333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
818333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
819333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
820333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
821333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
822333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
823333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
824333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first fully visible item in each span. If a span does
826d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
827333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
828333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
829333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
830333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstCompletelyVisibleItemPositions(int[] into) {
831333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
832333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
833333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
835333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
836333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
837d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
838333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition();
839333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
840333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
841333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
842333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
844333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last visible view for each span.
845333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
846333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
847333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
848333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
849333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
850333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
851333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
856333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
857d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last visible item in each span. If a span does not have
858d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastVisibleItemPositions(int[] into) {
863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
868333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
869d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastVisibleItemPosition();
871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last completely visible view for each span.
877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
879333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
880333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
881333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
882333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
883333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
884333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
885333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
886333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
887333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
888333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
889d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last fully visible item in each span. If a span does not
890d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
891333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
892333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
893333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
894333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastCompletelyVisibleItemPositions(int[] into) {
895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
900333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
901d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastCompletelyVisibleItemPosition();
903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
906333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollOffset(RecyclerView.State state) {
909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollOffset(state);
910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
911d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
912d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollOffset(RecyclerView.State state) {
913d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
915d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation,
917d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled)
918d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
919d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled, mShouldReverseLayout);
920d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
921d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
922d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
923d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollOffset(RecyclerView.State state) {
924d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollOffset(state);
925d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
926d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
927d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
928d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollExtent(RecyclerView.State state) {
929d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollExtent(state);
930d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
931d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
932d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollExtent(RecyclerView.State state) {
933d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
934d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
935d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
936d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation,
937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled)
938d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
939d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
940d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
941d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
942d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollExtent(RecyclerView.State state) {
944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollExtent(state);
945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollRange(RecyclerView.State state) {
949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollRange(RecyclerView.State state) {
953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation,
957d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled)
958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
959d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollRange(RecyclerView.State state) {
964d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
965d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
966d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
967d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) {
968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (lp.mFullSpan) {
969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mOrientation == VERTICAL) {
970d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                measureChildWithDecorationsAndMargin(child, mFullSizeSpec, mHeightSpec);
971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
972d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                measureChildWithDecorationsAndMargin(child, mWidthSpec, mFullSizeSpec);
973d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
975d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            measureChildWithDecorationsAndMargin(child, mWidthSpec, mHeightSpec);
976d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
977d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
978d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
9792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
9802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int heightSpec) {
9812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
9822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
9832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left,
9842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.rightMargin + insets.right);
9852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top,
9862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.bottomMargin + insets.bottom);
9872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        child.measure(widthSpec, heightSpec);
9882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int updateSpecWithExtra(int spec, int startInset, int endInset) {
9912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (startInset == 0 && endInset == 0) {
9922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return spec;
9932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mode = View.MeasureSpec.getMode(spec);
9952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
9962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return View.MeasureSpec.makeMeasureSpec(
9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return spec;
10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onRestoreInstanceState(Parcelable state) {
10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (state instanceof SavedState) {
10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState = (SavedState) state;
10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (DEBUG) {
10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "invalid saved state class");
10092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public Parcelable onSaveInstanceState() {
10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new SavedState(mPendingSavedState);
10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState state = new SavedState();
10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mReverseLayout = mReverseLayout;
10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mAnchorLayoutFromEnd = mLastLayoutFromEnd;
1020d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        state.mLastLayoutRTL = mLastLayoutRTL;
10212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLazySpanLookup != null && mLazySpanLookup.mData != null) {
10232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookup = mLazySpanLookup.mData;
10242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = state.mSpanLookup.length;
1025d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mFullSpanItems = mLazySpanLookup.mFullSpanItems;
10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = 0;
10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition()
10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : getFirstChildPosition();
1033333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt();
1034b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = mSpanCount;
10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanOffsets = new int[mSpanCount];
10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
1037d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int line;
1038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mLastLayoutFromEnd) {
1039d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getEndLine(Span.INVALID_LINE);
1040d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1041d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getEndAfterPadding();
1042d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
1044d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getStartLine(Span.INVALID_LINE);
1045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getStartAfterPadding();
1047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
1049d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                state.mSpanOffsets[i] = line;
10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1052d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mAnchorPosition = NO_POSITION;
1053d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mVisibleAnchorPosition = NO_POSITION;
1054b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = 0;
10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
10572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "saved state:\n" + state);
10582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return state;
10602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1062a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1063a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
1064a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
1065a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        ViewGroup.LayoutParams lp = host.getLayoutParams();
1066a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (!(lp instanceof LayoutParams)) {
1067a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            super.onInitializeAccessibilityNodeInfoForItem(host, info);
1068a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return;
1069a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1070a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        LayoutParams sglp = (LayoutParams) lp;
1071a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1072a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1073a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1074a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1075a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1076a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        } else { // VERTICAL
1077a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1078a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1079a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1080a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1081a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1082a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1083a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1084a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1085a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1086a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        super.onInitializeAccessibilityEvent(event);
1087a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (getChildCount() > 0) {
1088a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final AccessibilityRecordCompat record = AccessibilityEventCompat
1089a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    .asRecord(event);
1090a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final View start = findFirstVisibleItemClosestToStart(false);
1091a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final View end = findFirstVisibleItemClosestToEnd(false);
1092a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (start == null || end == null) {
1093a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                return;
1094a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1095a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int startPos = getPosition(start);
1096a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int endPos = getPosition(end);
1097a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (startPos < endPos) {
1098a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setFromIndex(startPos);
1099a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setToIndex(endPos);
1100a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            } else {
1101a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setFromIndex(endPos);
1102a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setToIndex(startPos);
1103a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1104a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1105a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1106a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1107333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
1108333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Finds the first fully visible child to be used as an anchor child if span count changes when
1109333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * state is restored.
1110333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
1111333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    int findFirstVisibleItemPositionInt() {
1112d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true) :
1113d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                findFirstVisibleItemClosestToStart(true);
1114d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return first == null ? NO_POSITION : getPosition(first);
1115d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1116d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1117a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1118a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
1119a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getRowCountForAccessibility(recycler, state);
1124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1126a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1127a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
1128a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1129a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == VERTICAL) {
1130a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1131a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1132a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getColumnCountForAccessibility(recycler, state);
1133a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1134a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    View findFirstVisibleItemClosestToStart(boolean fullyVisible) {
1136333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1137333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
1138d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int limit = getChildCount();
1139d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < limit; i ++) {
1140333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final View child = getChildAt(i);
1141d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if ((!fullyVisible || mPrimaryOrientation.getDecoratedStart(child) >= boundsStart)
1142333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    && mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) {
1143d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return child;
1144d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1145d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1146d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return null;
1147d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1148d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1149d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    View findFirstVisibleItemClosestToEnd(boolean fullyVisible) {
1150d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1151d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
1152d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = getChildCount() - 1; i >= 0; i --) {
1153d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = getChildAt(i);
1154d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart && (!fullyVisible
1155d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    || mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd)) {
1156d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return child;
1157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
1158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return null;
1160333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1161333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
11622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
11632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
11642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
11652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
11662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
11672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
11682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = -scrollBy(-gap, recycler, state);
11692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
11702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
11712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
11732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
11742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(gap);
11752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
11792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
11802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding());
11812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
11822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
11832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
11842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = scrollBy(gap, recycler, state);
11852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
11862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
11872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
11892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
11902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(-gap);
11912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) {
11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos < anchorPosition) {
12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_START;
12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_HEAD;
12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) {
12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos > anchorPosition) {
12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_END;
12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_TAIL;
12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenHorizontal(int dx) {
12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenHorizontal(dx);
12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dx);
12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenVertical(int dy) {
12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenVertical(dy);
12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dy);
12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
1248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE);
12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
1253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD);
1254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsChanged(RecyclerView recyclerView) {
1258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLazySpanLookup.clear();
1259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
1260d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1261d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1262d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
1264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE);
1265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
1269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE);
12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Checks whether it should invalidate span assignments in response to an adapter change.
12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) {
12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition();
1277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLazySpanLookup.invalidateAfter(positionStart);
1278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        switch (cmd) {
1279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.ADD:
1280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition);
1281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.REMOVE:
1283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition);
1284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.MOVE:
1286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // TODO optimize
1287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, 1);
1288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1);
1289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (positionStart + itemCountOrToPosition <= minPosition) {
1293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
1294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
12952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition();
12972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (positionStart <= maxPosition) {
12982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
12992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mRemainingSpans.set(0, mSpanCount, true);
13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // The target position we are trying to reach.
13062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int targetLine;
13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /*
13082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * The line until which we can recycle, as long as we add views.
13092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * Keep in mind, it is still the line in layout direction which means; to calculate the
13102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * actual recycle line, we should subtract/add the size in orientation.
13112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        */
13122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int recycleLine;
13132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Line of the furthest row.
13142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
13153ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
13160ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable;
13170ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding();
1318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
13192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // LAYOUT_START
13203ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
13210ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable;
13220ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine - mLayoutState.mExtra -
1323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mPrimaryOrientation.getStartAfterPadding();
13242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
13262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // the default coordinate to add new view.
1328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int defaultNewViewLine = mShouldReverseLayout
1329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? mPrimaryOrientation.getEndAfterPadding()
1330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : mPrimaryOrientation.getStartAfterPadding();
13312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) {
13332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View view = layoutState.next(recycler);
13342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = ((LayoutParams) view.getLayoutParams());
13352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
13362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                addView(view);
13372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
13382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                addView(view, 0);
13392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            measureChildWithDecorationsAndMargin(view, lp);
13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int position = lp.getViewPosition();
13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanIndex = mLazySpanLookup.getSpan(position);
13442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span currentSpan;
1345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID;
1346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (assignSpan) {
1347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState);
13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.setSpan(position, currentSpan);
1349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position);
1351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1353d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "using " + spanIndex + " for pos " + position);
1355d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                currentSpan = mSpans[spanIndex];
13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int start;
13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int end;
1360d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
1362d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine)
1363d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getEndLine(defaultNewViewLine);
13642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                end = start + mPrimaryOrientation.getDecoratedMeasurement(view);
1365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1366d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1367d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromEnd(start);
1368d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_START;
1369d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
13722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1373d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                end = lp.mFullSpan ? getMinStart(defaultNewViewLine)
1374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getStartLine(defaultNewViewLine);
13752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                start = end - mPrimaryOrientation.getDecoratedMeasurement(view);
1376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1378d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromStart(end);
1379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_END;
1380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
13822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // check if this item may create gaps in the future
1386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD && assignSpan) {
1387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLaidOutInvalidFullSpan = true;
13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
13892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            lp.mSpan = currentSpan;
1391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            attachViewToSpans(view, lp, layoutState);
13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
1393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : currentSpan.mIndex * mSizePerSpan +
1394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            mSecondaryOrientation.getStartAfterPadding();
13952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mOrientation == VERTICAL) {
13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
13982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
13992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd);
14002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1401d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
14022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (lp.mFullSpan) {
1403d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine);
14042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
14052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
14062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycle(recycler, mLayoutState, currentSpan, recycleLine);
14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
14102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "fill, " + getChildCount());
14112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLayoutState.mLayoutDirection == LAYOUT_START) {
14132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding());
14140ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart));
14152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
14162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
14170ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (max - recycleLine));
14182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) {
1422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop);
1426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) {
1431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom;
1435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) {
1440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) {
1441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                appendViewToAllSpans(view);
1443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.appendToSpan(view);
1445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                prependViewToAllSpans(view);
1449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.prependToSpan(view);
1451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState,
1456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span updatedSpan, int recycleLine) {
1457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_START) {
1458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // calculate recycle line
1459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int maxStart = getMaxStart(updatedSpan.getStartLine());
1460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycleFromEnd(recycler, Math.max(recycleLine, maxStart) +
1461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
1462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // calculate recycle line
1464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int minEnd = getMinEnd(updatedSpan.getEndLine());
1465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycleFromStart(recycler, Math.min(recycleLine, minEnd) -
1466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
1467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void appendViewToAllSpans(View view) {
1471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].appendToSpan(view);
1474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void prependViewToAllSpans(View view) {
1478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].prependToSpan(view);
1481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void layoutDecoratedWithMargins(View child, int left, int top, int right, int bottom) {
14852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
1486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
1487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "layout decorated pos: " + lp.getViewPosition() + ", span:"
1488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + lp.getSpanIndex() + ", fullspan:" + lp.mFullSpan
1489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + ". l:" + left + ",t:" + top
1490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + ", r:" + right + ", b:" + bottom);
1491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
14922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin
14932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                , bottom - lp.bottomMargin);
14942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void updateAllRemainingSpans(int layoutDir, int targetLine) {
1497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpans[i].mViews.isEmpty()) {
1499d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue;
1500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1501d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateRemainingSpans(mSpans[i], layoutDir, targetLine);
1502d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
15052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateRemainingSpans(Span span, int layoutDir, int targetLine) {
15062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int deletedSize = span.getDeletedSize();
15072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutDir == LAYOUT_START) {
15082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getStartLine();
15092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line + deletedSize < targetLine) {
15102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
15112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
15132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getEndLine();
15142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line - deletedSize > targetLine) {
15152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
15162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxStart(int def) {
15212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxStart = mSpans[0].getStartLine(def);
15222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
15242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart > maxStart) {
15252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxStart = spanStart;
15262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxStart;
15292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinStart(int def) {
15322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minStart = mSpans[0].getStartLine(def);
15332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
15352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart < minStart) {
15362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minStart = spanStart;
15372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minStart;
15402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxEnd(int def) {
15432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxEnd = mSpans[0].getEndLine(def);
15442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
15462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd > maxEnd) {
15472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxEnd = spanEnd;
15482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxEnd;
15512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinEnd(int def) {
15542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minEnd = mSpans[0].getEndLine(def);
15552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd < minEnd) {
15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minEnd = spanEnd;
15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minEnd;
15622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromStart(RecyclerView.Recycler recycler, int line) {
15652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
15662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "recycling from start for line " + line);
15672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (getChildCount() > 0) {
15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(0);
15702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedEnd(child) < line) {
15712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
15722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
15732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
15742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popStart();
15752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
15762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
15772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popStart();
15782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
15792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
15802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
15812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
15822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromEnd(RecyclerView.Recycler recycler, int line) {
15872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
15882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int i;
15892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (i = childCount - 1; i >= 0; i--) {
15902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(i);
15912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) > line) {
15922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
15932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
15942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
15952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popEnd();
15962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
15972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
15982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popEnd();
15992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
16012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
16022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return True if last span is the first one we want to fill
1609d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
1610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean preferLastSpan(int layoutDir) {
1611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mOrientation == HORIZONTAL) {
1612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return (layoutDir == LAYOUT_START) != mShouldReverseLayout;
1613d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1614d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL();
1615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
16182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Finds the span for the next view.
16192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
16202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span getNextSpan(LayoutState layoutState) {
1621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection);
1622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int startIndex, endIndex, diff;
1623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (preferLastSpan) {
1624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = mSpanCount - 1;
1625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = -1;
1626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = -1;
1627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = 0;
1629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = mSpanCount;
1630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = 1;
1631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
1633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span min = null;
1634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int minLine = Integer.MAX_VALUE;
16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getStartAfterPadding();
1636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getEndLine(defaultLine);
1639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine < minLine) {
16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    min = other;
16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    minLine = otherLine;
16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return min;
16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span max = null;
1647d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int maxLine = Integer.MIN_VALUE;
16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getEndAfterPadding();
1649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getStartLine(defaultLine);
1652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine > maxLine) {
16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    max = other;
16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    maxLine = otherLine;
16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return max;
16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollVertically() {
16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == VERTICAL;
16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollHorizontally() {
16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == HORIZONTAL;
16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dx, recycler, state);
16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dy, recycler, state);
16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int calculateScrollDirectionForPosition(int position) {
16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() == 0) {
16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START;
16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int firstChildPos = getFirstChildPosition();
16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
16922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
16932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int position) {
16942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) {
16952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
16962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public PointF computeScrollVectorForPosition(int targetPosition) {
16972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int direction = calculateScrollDirectionForPosition(targetPosition);
16982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (direction == 0) {
16992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return null;
17002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mOrientation == HORIZONTAL) {
17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(direction, 0);
17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(0, direction);
17052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
17082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        scroller.setTargetPosition(position);
17092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        startSmoothScroll(scroller);
17102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPosition(int position) {
17142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) {
17152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
17182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
17202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
17232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Scroll to the specified adapter position with the given offset from layout start.
17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Note that scroll position change will not be reflected until the next layout call.
17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param position Index (starting at 0) of the reference item.
17302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param offset   The distance (in pixels) between the start edge of the item view and
17312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                 start edge of the RecyclerView.
17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
17332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #scrollToPosition(int)
17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
17352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPositionWithOffset(int position, int offset) {
17362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = offset;
17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int referenceChildPosition;
17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (dt > 0) { // layout towards end
17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_END;
17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_TAIL;
17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getLastChildPosition();
17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_START;
17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_HEAD;
17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getFirstChildPosition();
17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int absDt = Math.abs(dt);
17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = absDt;
17612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0;
17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int consumed = fill(recycler, mLayoutState, state);
17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int totalScroll;
17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (absDt < consumed) {
17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = dt;
17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (dt < 0) {
17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = -consumed;
17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // dt > 0
17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = consumed;
17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "asked " + dt + " scrolled" + totalScroll);
17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1775d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mPrimaryOrientation.offsetChildren(-totalScroll);
17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // always reset this if we scroll for a proper save instance state
17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLastLayoutFromEnd = mShouldReverseLayout;
17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return totalScroll;
17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getLastChildPosition() {
17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1));
17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getFirstChildPosition() {
17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(0));
17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1791719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1792719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the first View that can be used as an anchor View.
1793719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1794719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1795719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1796719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findFirstReferenceChildPosition(int itemCount) {
1797719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        final int limit = getChildCount();
1798719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = 0; i < limit; i++) {
1799719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1800719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1801719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1802719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1803719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1804719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1805719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1806719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1807719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1808719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1809719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the last View that can be used as an anchor View.
1810719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1811719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1812719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1813719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findLastReferenceChildPosition(int itemCount) {
1814719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
1815719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1816719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1817719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1818719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1819719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1820719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1821719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1822719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1823719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT);
18282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(c, attrs);
18332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (lp instanceof ViewGroup.MarginLayoutParams) {
18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams(lp);
18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return lp instanceof LayoutParams;
18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getOrientation() {
18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation;
18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * LayoutParams used by StaggeredGridLayoutManager.
18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static class LayoutParams extends RecyclerView.LayoutParams {
18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Span Id for Views that are not laid out yet.
18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final int INVALID_SPAN_ID = -1;
18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Package scope to be able to access from tests.
18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        Span mSpan;
18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mFullSpan;
18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(Context c, AttributeSet attrs) {
18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(c, attrs);
18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(int width, int height) {
18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(width, height);
18752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.MarginLayoutParams source) {
18782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
18792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.LayoutParams source) {
18822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
18832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(RecyclerView.LayoutParams source) {
18862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
18872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
18902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * When set to true, the item will layout using all span area. That means, if orientation
18912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * is vertical, the view will have full width; if orientation is horizontal, the view will
18922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * have full height.
18932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
18942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param fullSpan True if this item should traverse all spans.
18957499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #isFullSpan()
18962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
18972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void setFullSpan(boolean fullSpan) {
18982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mFullSpan = fullSpan;
18992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
19027499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * Returns whether this View occupies all available spans or just one.
19037499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         *
19047499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @return True if the View occupies all spans or false otherwise.
19057499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #setFullSpan(boolean)
19067499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         */
19077499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        public boolean isFullSpan() {
19087499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar            return mFullSpan;
19097499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        }
19107499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar
19117499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        /**
19122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns the Span index to which this View is assigned.
19132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
19142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return The Span index of the View. If View is not yet assigned to any span, returns
19152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * {@link #INVALID_SPAN_ID}.
19162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
19172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public final int getSpanIndex() {
19182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpan == null) {
19192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return INVALID_SPAN_ID;
19202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mSpan.mIndex;
19222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    // Package scoped to access from tests.
19262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    class Span {
19272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19286b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        static final int INVALID_LINE = Integer.MIN_VALUE;
19292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private ArrayList<View> mViews = new ArrayList<View>();
19302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedStart = INVALID_LINE;
19312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedEnd = INVALID_LINE;
19322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mDeletedSize = 0;
19332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mIndex;
19342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private Span(int index) {
19362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mIndex = index;
19372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine(int def) {
19402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
19412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
19422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedStart() {
1951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View startView = mViews.get(0);
1952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(startView);
1953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedStart = mPrimaryOrientation.getDecoratedStart(startView);
1954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
1956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        .getFullSpanItem(lp.getViewPosition());
1957d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_START) {
1958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedStart -= fsi.getGapForSpan(mIndex);
1959d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
1960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine() {
19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine(int def) {
19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 0) {
19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1980d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1984d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedEnd() {
1985d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View endView = mViews.get(mViews.size() - 1);
1986d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(endView);
1987d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView);
1988d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1989d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
1990d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        .getFullSpanItem(lp.getViewPosition());
1991d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_END) {
1992d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedEnd += fsi.getGapForSpan(mIndex);
1993d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
1994d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1996d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
19972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
19982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine() {
19992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2002d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void prependToSpan(View view) {
20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(0, view);
20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20147c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
20162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void appendToSpan(View view) {
20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(view);
20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20277c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Useful method to preserve positions on a re-layout.
20332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void cacheReferenceLineAndClear(boolean reverseLayout, int offset) {
20342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int reference;
20352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reverseLayout) {
20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getEndLine(INVALID_LINE);
20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
20382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getStartLine(INVALID_LINE);
20392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            clear();
20412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reference == INVALID_LINE) {
20422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
20432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2044d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) ||
2045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding()) ) {
2046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
20482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (offset != INVALID_OFFSET) {
20492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference += offset;
20502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mCachedEnd = reference;
20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.clear();
20562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateCache();
20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mDeletedSize = 0;
20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateCache() {
20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setLine(int line) {
20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mCachedStart = line;
20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popEnd() {
20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View end = mViews.remove(size - 1);
20722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(end);
20732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
20747c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
20752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end);
20762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 1) {
20782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
20792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
20812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popStart() {
20842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View start = mViews.remove(0);
20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(start);
20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20907c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start);
20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int getDeletedSize() {
20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mDeletedSize;
20982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams getLayoutParams(View view) {
21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return (LayoutParams) view.getLayoutParams();
21022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void onOffset(int dt) {
21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart += dt;
21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd += dt;
21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // normalized offset is how much this span can scroll
21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getNormalizedOffset(int dt, int targetStart, int targetEnd) {
21152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return 0;
21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (dt < 0) {
21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int endSpace = getEndLine() - targetEnd;
21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (endSpace <= 0) {
21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return -dt > endSpace ? -endSpace : dt;
21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int startSpace = targetStart - getStartLine();
21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (startSpace <= 0) {
21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return startSpace < dt ? startSpace : dt;
21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
21342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns if there is no child between start-end lines
21352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param start The start line
21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param end   The end line
21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return true if a new child can be added between start and end
21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean isEmpty(int start, int end) {
21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int count = mViews.size();
21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < count; i++) {
21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View view = mViews.get(i);
21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mPrimaryOrientation.getDecoratedStart(view) < end &&
21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mPrimaryOrientation.getDecoratedEnd(view) > start) {
21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return false;
21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return true;
21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2151333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2152333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstVisibleItemPosition() {
2153333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2154d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    ? findOneVisibleChild(mViews.size() -1, -1, false)
2155333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), false);
2156333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstCompletelyVisibleItemPosition() {
2159333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2160333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(mViews.size() -1, -1, true)
2161333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), true);
2162333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2163333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2164333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastVisibleItemPosition() {
2165333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2166333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), false)
2167d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : findOneVisibleChild(mViews.size() -1, -1, false);
2168333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2169333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2170333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastCompletelyVisibleItemPosition() {
2171333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2172333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), true)
2173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : findOneVisibleChild(mViews.size() -1, -1, true);
2174333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2175333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2176333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
2177333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int start = mPrimaryOrientation.getStartAfterPadding();
2178333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int end = mPrimaryOrientation.getEndAfterPadding();
2179333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int next = toIndex > fromIndex ? 1 : -1;
2180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = fromIndex; i != toIndex; i += next) {
2181333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final View child = mViews.get(i);
2182333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
2183333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
2184333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                if (childStart < end && childEnd > start) {
2185333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    if (completelyVisible) {
2186333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        if (childStart >= start && childEnd <= end) {
2187333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                            return getPosition(child);
2188333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        }
2189333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    } else {
2190333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        return getPosition(child);
2191333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    }
2192333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                }
2193333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
2194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return NO_POSITION;
2195333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
21962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
21972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
21992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * An array of mappings from adapter position to span.
22002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * This only grows when a write happens and it grows up to the size of the adapter.
22012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
22022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class LazySpanLookup {
22032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private static final int MIN_SIZE = 10;
22052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mData;
22062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAdapterSize; // we don't want to grow beyond that, unless it grows
2207d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<FullSpanItem> mFullSpanItems;
2208d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2209d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2210d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Invalidates everything after this position, including full span information
2212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int forceInvalidateAfter(int position) {
2214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems != null) {
2215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    FullSpanItem fsi = mFullSpanItems.get(i);
2217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (fsi.mPosition >= position) {
2218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return invalidateAfter(position);
2223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
22242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * returns end position for invalidation.
2227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidateAfter(int position) {
22292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
2230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
22312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (position >= mData.length) {
2233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int endPosition = invalidateFullSpansAfter(position);
2236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (endPosition == RecyclerView.NO_POSITION) {
2237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID);
2238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mData.length;
2239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
2240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // just invalidate items in between
2241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID);
2242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return endPosition + 1;
22432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getSpan(int position) {
22472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null || position >= mData.length) {
22482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return LayoutParams.INVALID_SPAN_ID;
22492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
22502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mData[position];
22512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setSpan(int position, Span span) {
22552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(position);
22562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mData[position] = span.mIndex;
22572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int sizeForPosition(int position) {
22602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int len = mData.length;
22612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            while (len <= position) {
22622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len *= 2;
22632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (len > mAdapterSize) {
22652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len = mAdapterSize;
22662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return len;
22682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void ensureSize(int position) {
22712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
22722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[Math.max(position, MIN_SIZE) + 1];
22732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
22742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else if (position >= mData.length) {
22752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int[] old = mData;
22762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[sizeForPosition(position)];
22772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                System.arraycopy(old, 0, mData, 0, old.length);
22782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID);
22792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
22832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData != null) {
22842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
22852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
22872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForRemoval(int positionStart, int itemCount) {
2290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
22932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
22942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart + itemCount, mData, positionStart,
22952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
22962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, mData.length - itemCount, mData.length,
22972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForRemoval(positionStart, itemCount);
2299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForRemoval(int positionStart, int itemCount) {
2302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int end = positionStart + itemCount;
2306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < end) {
2312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.remove(i);
2313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
2314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fsi.mPosition -= itemCount;
2315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
23172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForAddition(int positionStart, int itemCount) {
2320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
23232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
23242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart, mData, positionStart + itemCount,
23252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
23262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, positionStart, positionStart + itemCount,
23272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForAddition(positionStart, itemCount);
2329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForAddition(int positionStart, int itemCount) {
2332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                fsi.mPosition += itemCount;
2341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returns when invalidation should end. e.g. hitting a full span position.
2346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returned position SHOULD BE invalidated.
2347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private int invalidateFullSpansAfter(int position) {
2349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2352d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final FullSpanItem item = getFullSpanItem(position);
2353d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if there is an fsi at this position, get rid of it.
2354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (item != null) {
2355d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(item);
2356d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2357d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int nextFsiIndex = -1;
2358d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int count = mFullSpanItems.size();
2359d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < count; i++) {
2360d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2361d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= position) {
2362d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    nextFsiIndex = i;
2363d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    break;
2364d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2366d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (nextFsiIndex != -1) {
2367d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex);
2368d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(nextFsiIndex);
2369d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return fsi.mPosition;
2370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2371d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return RecyclerView.NO_POSITION;
2372d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2373d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void addFullSpanItem(FullSpanItem fullSpanItem) {
2375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems = new ArrayList<FullSpanItem>();
2377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2378d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int size = mFullSpanItems.size();
2379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < size; i++) {
2380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem other = mFullSpanItems.get(i);
2381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition == fullSpanItem.mPosition) {
2382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (DEBUG) {
2383d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        throw new IllegalStateException("two fsis for same position");
2384d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
2385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2388d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition >= fullSpanItem.mPosition) {
2389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.add(i, fullSpanItem);
2390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return;
2391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2392d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if it is not added to a position.
2394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems.add(fullSpanItem);
2395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2396d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2397d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public FullSpanItem getFullSpanItem(int position) {
2398d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2399d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
2400d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2401d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2402d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final FullSpanItem fsi = mFullSpanItems.get(i);
2403d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition == position) {
2404d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
2405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
2408d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2409d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2410d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2411d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param minPos inclusive
2412d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param maxPos exclusive
2413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param gapDir if not 0, returns FSIs on in that direction
2414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir) {
2416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
2418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2419d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < mFullSpanItems.size(); i++) {
2420d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= maxPos) {
2422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return null;
2423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= minPos && (gapDir == 0 || fsi.mGapDir == gapDir)) {
2425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
2426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
2429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * We keep information about full span items because they may create gaps in the UI.
2433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        static class FullSpanItem implements Parcelable {
2435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mPosition;
2437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mGapDir;
2438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int[] mGapPerSpan;
2439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public FullSpanItem(Parcel in) {
2441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPosition = in.readInt();
2442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mGapDir = in.readInt();
2443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int spanCount = in.readInt();
2444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (spanCount > 0) {
2445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mGapPerSpan = new int[spanCount];
2446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    in.readIntArray(mGapPerSpan);
2447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public FullSpanItem() {
2451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int getGapForSpan(int spanIndex) {
2454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
2455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public void invalidateSpanGaps() {
2458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mGapPerSpan = null;
2459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public int describeContents() {
2463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return 0;
2464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public void writeToParcel(Parcel dest, int flags) {
2468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mPosition);
2469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mGapDir);
2470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mGapPerSpan != null && mGapPerSpan.length > 0) {
2471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(mGapPerSpan.length);
2472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeIntArray(mGapPerSpan);
2473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
2474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(0);
2475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public String toString() {
2480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return "FullSpanItem{" +
2481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        "mPosition=" + mPosition +
2482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        ", mGapDir=" + mGapDir +
2483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) +
2484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        '}';
2485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public static final Parcelable.Creator<FullSpanItem> CREATOR
2488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    = new Parcelable.Creator<FullSpanItem>() {
2489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                @Override
2490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                public FullSpanItem createFromParcel(Parcel in) {
2491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return new FullSpanItem(in);
2492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                @Override
2495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                public FullSpanItem[] newArray(int size) {
2496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return new FullSpanItem[size];
2497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            };
24992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
25012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class SavedState implements Parcelable {
25032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAnchorPosition;
2505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
2506b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar        int mSpanOffsetsSize;
25072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanOffsets;
25082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mSpanLookupSize;
25092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanLookup;
2510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<LazySpanLookup.FullSpanItem> mFullSpanItems;
25112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mReverseLayout;
25122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mAnchorLayoutFromEnd;
2513d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLastLayoutRTL;
25142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState() {
25162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState(Parcel in) {
25192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = in.readInt();
2520333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = in.readInt();
2521b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = in.readInt();
2522b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
2523b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar                mSpanOffsets = new int[mSpanOffsetsSize];
25242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanOffsets);
25252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = in.readInt();
25282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
25292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpanLookup = new int[mSpanLookupSize];
25302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanLookup);
25312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = in.readInt() == 1;
25332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = in.readInt() == 1;
2534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = in.readInt() == 1;
2535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = in.readArrayList(
2536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem.class.getClassLoader());
25372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState(SavedState other) {
2540b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = other.mSpanOffsetsSize;
25412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = other.mAnchorPosition;
2542333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = other.mVisibleAnchorPosition;
25432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = other.mSpanOffsets;
25442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = other.mSpanLookupSize;
25452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = other.mSpanLookup;
25462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = other.mReverseLayout;
25472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
2548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = other.mLastLayoutRTL;
2549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = other.mFullSpanItems;
25502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateSpanInfo() {
25532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
2554b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
25552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = 0;
25562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = null;
2557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
25582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateAnchorPositionInfo() {
25612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
2562b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
2563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mAnchorPosition = NO_POSITION;
2564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mVisibleAnchorPosition = NO_POSITION;
25652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
25682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int describeContents() {
25692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return 0;
25702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
25732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void writeToParcel(Parcel dest, int flags) {
25742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorPosition);
2575333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            dest.writeInt(mVisibleAnchorPosition);
2576b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            dest.writeInt(mSpanOffsetsSize);
2577b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
25782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanOffsets);
25792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mSpanLookupSize);
25812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
25822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanLookup);
25832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mReverseLayout ? 1 : 0);
25852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
2586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeInt(mLastLayoutRTL ? 1 : 0);
2587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeList(mFullSpanItems);
25882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final Parcelable.Creator<SavedState> CREATOR
25912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                = new Parcelable.Creator<SavedState>() {
25922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
25932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState createFromParcel(Parcel in) {
25942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState(in);
25952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
25982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState[] newArray(int size) {
25992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState[size];
26002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
26022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2603d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
2605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Data class to hold the information about an anchor position which is used in onLayout call.
2606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
2607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private class AnchorInfo {
2608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2609d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mPosition;
2610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mOffset;
2611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLayoutFromEnd;
2612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mInvalidateOffsets;
2613d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2614d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void reset() {
2615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPosition = NO_POSITION;
2616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = INVALID_OFFSET;
2617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLayoutFromEnd = false;
2618d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mInvalidateOffsets = false;
2619d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding() {
2622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding()
2623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : mPrimaryOrientation.getStartAfterPadding();
2624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding(int addedDistance) {
2627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mLayoutFromEnd) {
2628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance;
2629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
2630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance;
2631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
26342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar}
2635