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:
77115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <pre>
782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * _BC
802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
81115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * </pre>
82115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <p>
832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * It will animate to the following state:
84115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <pre>
852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BC_
872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
88115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * </pre>
892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private static final int INVALID_OFFSET = Integer.MIN_VALUE;
932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Number of spans
962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSpanCount = -1;
982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span[] mSpans;
1002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Primary orientation is the layout's orientation, secondary orientation is the orientation
1032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for spans. Having both makes code much cleaner for calculations.
1042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mPrimaryOrientation;
1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mSecondaryOrientation;
1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mOrientation;
1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * The width or height per span, depending on the orientation.
1122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSizePerSpan;
1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private LayoutState mLayoutState;
1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mReverseLayout = false;
1182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Aggregated reverse layout value that takes RTL into account.
1212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
122d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean mShouldReverseLayout = false;
1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Temporary variable used during fill method to check which spans needs to be filled.
1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private BitSet mRemainingSpans;
1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
1312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout which will check this variable and re-layout accordingly.
1322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
133d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    int mPendingScrollPosition = NO_POSITION;
1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * called.
1382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1396e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPositionOffset = INVALID_OFFSET;
1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Keeps the mapping between the adapter positions and spans. This is necessary to provide
1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * a consistent experience when user scrolls the list.
1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    LazySpanLookup mLazySpanLookup = new LazySpanLookup();
1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * how we handle gaps in UI.
1492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Saved state needs this information to properly layout on restore.
1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mLastLayoutFromEnd;
1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
158d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Saved state and onLayout needs this information to re-layout properly
159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
160d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLastLayoutRTL;
161d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
162d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * SavedState is not handled until a layout happens. This is where we keep it until next
1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout.
1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private SavedState mPendingSavedState;
1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
169d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used measurement specs. updated by onLayout.
1702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int mFullSizeSpec, mWidthSpec, mHeightSpec;
172d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used anchor info.
175d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
176d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private final AnchorInfo mAnchorInfo = new AnchorInfo();
177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
179d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * If a full span item is invalid / or created in reverse direction; it may create gaps in
180d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the UI. While laying out, if such case is detected, we set this flag.
181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
182d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * After scrolling stops, we check this flag and if it is set, re-layout.
183d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
184d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLaidOutInvalidFullSpan = false;
185d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
186d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
187d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}.
188d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}
189d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
190d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mSmoothScrollbarEnabled = true;
191d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
192d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private final Runnable checkForGapsRunnable = new Runnable() {
193d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        @Override
194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void run() {
195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
196d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
197d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    };
1982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Creates a StaggeredGridLayoutManager with given parameters.
2012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount   If orientation is vertical, spanCount is number of columns. If
2032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    orientation is horizontal, spanCount is number of rows.
2049bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar     * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL}
2052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public StaggeredGridLayoutManager(int spanCount, int orientation) {
2072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
2082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        setSpanCount(spanCount);
2092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps in the UI that may be caused by adapter changes.
213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * When a full span item is laid out in reverse direction, it sets a flag which we check when
215d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll is stopped (or re-layout happens) and re-layout after first valid item.
216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void checkForGaps() {
218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE) {
219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int minPos, maxPos;
222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getLastChildPosition();
224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getFirstChildPosition();
225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getFirstChildPosition();
227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getLastChildPosition();
228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
229d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (minPos == 0) {
230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View gapView = hasGapsToFix();
231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (gapView != null) {
232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestSimpleAnimationsInNextLayout();
234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestLayout();
235d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
236d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
237d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
238d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (!mLaidOutInvalidFullSpan) {
239d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
240d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
241d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
242d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup
243f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir, true);
244d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (invalidFsi == null) {
245d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLaidOutInvalidFullSpan = false;
246d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(maxPos + 1);
247d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
248d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
249d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup
250d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition,
251f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        invalidGapDir * -1, true);
252d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (validFsi == null) {
253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition);
254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1);
256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestSimpleAnimationsInNextLayout();
258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
260d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
2622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onScrollStateChanged(int state) {
263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state == RecyclerView.SCROLL_STATE_IDLE) {
264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
269d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
270d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
271d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].clear();
272d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
273d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
274d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
276d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps if we've reached to the top of the list.
277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field.
279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    View hasGapsToFix() {
281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int startChildIndex = 0;
282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int endChildIndex = getChildCount() - 1;
283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        BitSet mSpansToCheck = new BitSet(mSpanCount);
284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mSpansToCheck.set(0, mSpanCount, true);
285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int firstChildIndex, childLimit;
287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1;
288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            firstChildIndex = endChildIndex - 1;
291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            childLimit = startChildIndex - 1;
292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            firstChildIndex = startChildIndex;
294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            childLimit = endChildIndex;
295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1;
297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) {
298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View child = getChildAt(i);
299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            LayoutParams lp = (LayoutParams) child.getLayoutParams();
300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpansToCheck.get(lp.mSpan.mIndex)) {
301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (checkSpanForGap(lp.mSpan)) {
302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return child;
303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mSpansToCheck.clear(lp.mSpan.mIndex);
305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue; // quick reject
308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (i + nextChildDiff != childLimit) {
311d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                View nextChild = getChildAt(i + nextChildDiff);
312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                boolean compareSpans = false;
313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mShouldReverseLayout) {
314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // ensure child's end is below nextChild's end
315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myEnd = mPrimaryOrientation.getDecoratedEnd(child);
316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild);
317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myEnd < nextEnd) {
318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;//i should have a better position
319d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myEnd == nextEnd) {
320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myStart = mPrimaryOrientation.getDecoratedStart(child);
324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild);
325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myStart > nextStart) {
326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;//i should have a better position
327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myStart == nextStart) {
328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (compareSpans) {
332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // equal, check span indices.
333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams();
334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) {
335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;
336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
3392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // everything looks good
341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return null;
342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean checkSpanForGap(Span span) {
345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
346d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) {
347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return true;
348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) {
350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return true;
351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
352d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return false;
3532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the number of spans for the layout. This will invalidate all of the span assignments
3572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for Views.
3582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
3592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calling this method will automatically result in a new layout request unless the spanCount
3602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * parameter is equal to current span count.
3612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
3622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount Number of spans to layout
3632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setSpanCount(int spanCount) {
3650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (spanCount != mSpanCount) {
3672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateSpanAssignments();
3682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = spanCount;
3692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mRemainingSpans = new BitSet(mSpanCount);
3702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans = new Span[mSpanCount];
3712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
3722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpans[i] = new Span(i);
3732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
3742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
3752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
3792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep
380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll position if this method is called after views are laid out.
3812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
3832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
3842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setOrientation(int orientation) {
3852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation != HORIZONTAL && orientation != VERTICAL) {
3862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid orientation.");
3872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation == mOrientation) {
3902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
3912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
3932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation != null && mSecondaryOrientation != null) {
3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            // swap
3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            OrientationHelper tmp = mPrimaryOrientation;
3962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = mSecondaryOrientation;
3972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = tmp;
3982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
3992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets whether LayoutManager should start laying out items from the end of the UI. The order
4042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * items are traversed is not affected by this call.
4052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * For vertical layout, if it is set to <code>true</code>, first item will be at the bottom of
407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the list.
4082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For horizontal layouts, it depends on the layout direction.
4102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if
4112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link RecyclerView}} is RTL, it will layout from LTR.
4122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param reverseLayout Whether layout should be in reverse or not
4142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setReverseLayout(boolean reverseLayout) {
4160bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) {
4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mReverseLayout = reverseLayout;
4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mReverseLayout = reverseLayout;
4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the current gap handling strategy for StaggeredGridLayoutManager.
4262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps,
428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and
429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details.
4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}.
4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Current gap handling strategy.
4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setGapStrategy(int)
4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_NONE
4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getGapStrategy() {
4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mGapStrategy;
4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter
4442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * is different than the current strategy, calling this method will trigger a layout request.
4452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param gapStrategy The new gap handling strategy. Should be
447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link
448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    #GAP_HANDLING_NONE}.
4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #getGapStrategy()
4502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setGapStrategy(int gapStrategy) {
4520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gapStrategy == mGapStrategy) {
4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
4552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (gapStrategy != GAP_HANDLING_NONE &&
4572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
4582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE "
459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mGapStrategy = gapStrategy;
4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4650bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    @Override
4660bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void assertNotInLayoutOrScroll(String message) {
4670bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        if (mPendingSavedState == null) {
4680bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            super.assertNotInLayoutOrScroll(message);
4690bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
4700bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
4710bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the number of spans laid out by StaggeredGridLayoutManager.
4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Number of spans in the layout
4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getSpanCount() {
4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mSpanCount;
4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items.
4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you need to cancel current assignments, you can call this method which will clear all
4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * assignments and request a new layout.
4862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void invalidateSpanAssignments() {
4882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.clear();
4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void ensureOrientationHelper() {
4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPrimaryOrientation == null) {
4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation);
4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSecondaryOrientation = OrientationHelper
4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    .createOrientationHelper(this, 1 - mOrientation);
4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState = new LayoutState();
4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calculates the views' layout order. (e.g. from end to start or start to end)
5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * RTL layout support is applied automatically. So if layout is RTL and
5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
5052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void resolveShouldLayoutReverse() {
5072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // A == B is the same result, but we rather keep it readable
5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mOrientation == VERTICAL || !isLayoutRTL()) {
5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = mReverseLayout;
5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = !mReverseLayout;
5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean isLayoutRTL() {
5162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns whether views are laid out in reverse order or not.
5212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Not that this value is not affected by RecyclerView's layout direction.
5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return True if layout is reversed, false otherwise
5252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
5262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean getReverseLayout() {
5282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mReverseLayout;
5292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final AnchorInfo anchorInfo = mAnchorInfo;
536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.reset();
5372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            applyPendingSavedState(anchorInfo);
5402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            resolveShouldLayoutReverse();
542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
5432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateAnchorInfoForLayout(state, anchorInfo);
5462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState == null) {
548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd ||
549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    isLayoutRTL() != mLastLayoutRTL) {
550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
5550ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar        if (getChildCount() > 0 && (mPendingSavedState == null ||
556b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar                mPendingSavedState.mSpanOffsetsSize < 1)) {
557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (anchorInfo.mInvalidateOffsets) {
5582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // Scroll to position is set, clear.
5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].clear();
561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mOffset != INVALID_OFFSET) {
562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mSpans[i].setLine(anchorInfo.mOffset);
5632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset);
5682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        detachAndScrapAttachedViews(recycler);
572d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLaidOutInvalidFullSpan = false;
573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateMeasureSpecs();
574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (anchorInfo.mLayoutFromEnd) {
575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillStart(anchorInfo.mPosition, state);
577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
579d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillEnd(anchorInfo.mPosition, state);
5802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
581d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillEnd(anchorInfo.mPosition, state);
585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateLayoutStateToFillStart(anchorInfo.mPosition, state);
5882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
589d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
5902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
5932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout) {
5942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, true);
5952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, false);
5962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
5972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, true);
5982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, false);
5992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6026e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        if (!state.isPreLayout()) {
603d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (getChildCount() > 0 && mPendingScrollPosition != NO_POSITION &&
604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLaidOutInvalidFullSpan) {
605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ViewCompat.postOnAnimation(getChildAt(0), checkForGapsRunnable);
606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = NO_POSITION;
6086e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
6096e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        }
610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = isLayoutRTL();
6122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingSavedState = null; // we don't need this anymore
6132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
6142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void applyPendingSavedState(AnchorInfo anchorInfo) {
616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "found saved state: " + mPendingSavedState);
6182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
619d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanOffsetsSize > 0) {
620d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) {
621d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
622d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].clear();
623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int line = mPendingSavedState.mSpanOffsets[i];
624d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
625d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        if (mPendingSavedState.mAnchorLayoutFromEnd) {
626d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getEndAfterPadding();
627d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        } else {
628d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getStartAfterPadding();
629d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        }
630d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].setLine(line);
632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
634d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.invalidateSpanInfo();
635d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition;
636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
637d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
638d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL;
639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        setReverseLayout(mPendingSavedState.mReverseLayout);
640d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        resolveShouldLayoutReverse();
6412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
642d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mAnchorPosition != NO_POSITION) {
643d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
644d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
6452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
6472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
648d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanLookupSize > 1) {
649d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mData = mPendingSavedState.mSpanLookup;
650d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems;
651d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
652d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
653d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) {
655d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromPendingData(state, anchorInfo)) {
656d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
657d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
658d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromChildren(state, anchorInfo)) {
659d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
662d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "Deciding anchor info from fresh state");
663d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
664d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.assignCoordinateFromPadding();
665d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = 0;
666d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
667d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
668d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) {
669d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // We don't recycle views out of adapter order. This way, we can rely on the first or
670d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // last child as the anchor position.
671d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Layout direction may change but we should select the child depending on the latest
672d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // layout direction. Otherwise, we'll choose the wrong child.
673d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = mLastLayoutFromEnd
674d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? findLastReferenceChildPosition(state.getItemCount())
675d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : findFirstReferenceChildPosition(state.getItemCount());
676d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mOffset = INVALID_OFFSET;
677d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
678d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
679d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
680d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) {
681d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate scroll position if exists.
682d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) {
683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
685d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate it.
686d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
687d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = NO_POSITION;
688d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
689d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
690d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
691d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION
693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                || mPendingSavedState.mSpanOffsetsSize < 1) {
694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // If item is visible, make it fully visible.
695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = findViewByPosition(mPendingScrollPosition);
696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (child != null) {
697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Use regular anchor position, offset according to pending offset and target
698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child
699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition()
700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : getFirstChildPosition();
701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset != INVALID_OFFSET) {
703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mLayoutFromEnd) {
704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        final int target = mPrimaryOrientation.getEndAfterPadding() -
705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                                mPendingScrollPositionOffset;
706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child);
707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        final int target = mPrimaryOrientation.getStartAfterPadding() +
709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                                mPendingScrollPositionOffset;
710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child);
711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // no offset provided. Decide according to the child location
716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child);
717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (childSize > mPrimaryOrientation.getTotalSpace()) {
718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // Item does not fit. Fix depending on layout direction.
719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = anchorInfo.mLayoutFromEnd
720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            ? mPrimaryOrientation.getEndAfterPadding()
721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            : mPrimaryOrientation.getStartAfterPadding();
722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int startGap = mPrimaryOrientation.getDecoratedStart(child)
726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        - mPrimaryOrientation.getStartAfterPadding();
727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (startGap < 0) {
728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = -startGap;
729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int endGap = mPrimaryOrientation.getEndAfterPadding() -
732d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mPrimaryOrientation.getDecoratedEnd(child);
733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (endGap < 0) {
734d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = endGap;
735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
7362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
737d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child already visible. just layout as usual
738d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mOffset = INVALID_OFFSET;
739d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
740d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Child is not visible. Set anchor coordinate depending on in which direction
741d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child will be visible.
742d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mPendingScrollPosition;
743d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset == INVALID_OFFSET) {
744d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    final int position = calculateScrollDirectionForPosition(
745d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            anchorInfo.mPosition);
746d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mLayoutFromEnd = position == LAYOUT_END;
747d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding();
748d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
749d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset);
750d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
751d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
7522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
753d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
754d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mOffset = INVALID_OFFSET;
755d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mPosition = mPendingScrollPosition;
756d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
757d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
758d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
759d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
760d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    void updateMeasureSpecs() {
761d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mSizePerSpan = mSecondaryOrientation.getTotalSpace() / mSpanCount;
762d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
763d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mSecondaryOrientation.getTotalSpace(), View.MeasureSpec.EXACTLY);
764d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mOrientation == VERTICAL) {
765d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mWidthSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
766d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mHeightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
767d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
768d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mHeightSpec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan, View.MeasureSpec.EXACTLY);
769d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mWidthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
7702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
7712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
7732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
7742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean supportsPredictiveItemAnimations() {
7756e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        return mPendingSavedState == null;
7762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
778333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
779333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first visible view for each span.
780333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
781333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
782333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
783333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
784333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
785333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
786333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
787333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
788333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
789333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
790333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
791333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
792d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first visible item in each span. If a span does not have
793d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
794333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
795333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
796333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
797333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstVisibleItemPositions(int[] into) {
798333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
799333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
800333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
801333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
802333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
803333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
804d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
805333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstVisibleItemPosition();
806333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
807333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
808333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
809333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
810333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
811333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first completely visible view for each span.
812333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
813333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
814333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
815333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
816333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
817333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
818333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
819333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
820333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
821333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
822333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
823333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
824d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first fully visible item in each span. If a span does
825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
826333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
827333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
828333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
829333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstCompletelyVisibleItemPositions(int[] into) {
830333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
831333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
832333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
833333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
834333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
835333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
836d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
837333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition();
838333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
839333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
840333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
841333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
842333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
843333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last visible view for each span.
844333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
845333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
846333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
847333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
848333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
849333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
850333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
851333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
852333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
853333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
854333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
855333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
856d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last visible item in each span. If a span does not have
857d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
858333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
859333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
860333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
861333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastVisibleItemPositions(int[] into) {
862333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
863333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
864333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
865333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
866333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
867333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
868d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
869333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastVisibleItemPosition();
870333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
871333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
872333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
873333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
874333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
875333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last completely visible view for each span.
876333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
877333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
878333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
879333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
880333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
881333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
882333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
883333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
884333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
885333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
886333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
887333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
888d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last fully visible item in each span. If a span does not
889d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
890333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
891333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
892333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
893333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastCompletelyVisibleItemPositions(int[] into) {
894333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
895333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
896333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
897333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
898333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
899333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
900d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
901333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastCompletelyVisibleItemPosition();
902333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
903333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
904333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
905333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
906d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollOffset(RecyclerView.State state) {
908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollOffset(state);
909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
911d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollOffset(RecyclerView.State state) {
912d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
913d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
915ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureOrientationHelper();
916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation,
9176490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
9186490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
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        }
936ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureOrientationHelper();
937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation,
9386490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
9396490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
940d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
941d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
942d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollExtent(RecyclerView.State state) {
945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollExtent(state);
946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollRange(RecyclerView.State state) {
950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollRange(RecyclerView.State state) {
954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
957ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureOrientationHelper();
958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation,
9596490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true)
9606490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true),
961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
964d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
965d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollRange(RecyclerView.State state) {
966d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
967d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp) {
970d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (lp.mFullSpan) {
971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mOrientation == VERTICAL) {
97242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child, mFullSizeSpec,
97342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                        getSpecForDimension(lp.height, mHeightSpec));
974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
97542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child,
97642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                        getSpecForDimension(lp.width, mWidthSpec), mFullSizeSpec);
977d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
978d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
97942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            if (mOrientation == VERTICAL) {
98042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child, mWidthSpec,
98142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                        getSpecForDimension(lp.height, mHeightSpec));
98242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            } else {
98342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child,
98442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                        getSpecForDimension(lp.width, mWidthSpec), mHeightSpec);
98542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            }
98642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        }
98742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar    }
98842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar
98942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar    private int getSpecForDimension(int dim, int defaultSpec) {
99042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        if (dim < 0) {
99142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            return defaultSpec;
99242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        } else {
99342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            return View.MeasureSpec.makeMeasureSpec(dim, View.MeasureSpec.EXACTLY);
994d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
996d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
9972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
9982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int heightSpec) {
9992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
10002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
10012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + insets.left,
10022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.rightMargin + insets.right);
10032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + insets.top,
10042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                lp.bottomMargin + insets.bottom);
10052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        child.measure(widthSpec, heightSpec);
10062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int updateSpecWithExtra(int spec, int startInset, int endInset) {
10092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (startInset == 0 && endInset == 0) {
10102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return spec;
10112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mode = View.MeasureSpec.getMode(spec);
10132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
10142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return View.MeasureSpec.makeMeasureSpec(
10152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    View.MeasureSpec.getSize(spec) - startInset - endInset, mode);
10162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return spec;
10182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
10212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onRestoreInstanceState(Parcelable state) {
10222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (state instanceof SavedState) {
10232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState = (SavedState) state;
10242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
10252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (DEBUG) {
10262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "invalid saved state class");
10272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
10312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public Parcelable onSaveInstanceState() {
10322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
10332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new SavedState(mPendingSavedState);
10342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState state = new SavedState();
10362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mReverseLayout = mReverseLayout;
10372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mAnchorLayoutFromEnd = mLastLayoutFromEnd;
1038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        state.mLastLayoutRTL = mLastLayoutRTL;
10392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLazySpanLookup != null && mLazySpanLookup.mData != null) {
10412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookup = mLazySpanLookup.mData;
10422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = state.mSpanLookup.length;
1043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mFullSpanItems = mLazySpanLookup.mFullSpanItems;
10442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
10452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = 0;
10462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
10482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
1049ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar            ensureOrientationHelper();
10502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition()
10512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : getFirstChildPosition();
1052333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt();
1053b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = mSpanCount;
10542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanOffsets = new int[mSpanCount];
10552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
1056d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int line;
1057d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mLastLayoutFromEnd) {
1058d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getEndLine(Span.INVALID_LINE);
1059d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1060d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getEndAfterPadding();
1061d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1062d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
1063d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getStartLine(Span.INVALID_LINE);
1064d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1065d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getStartAfterPadding();
1066d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1067d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
1068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                state.mSpanOffsets[i] = line;
10692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
10702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1071d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mAnchorPosition = NO_POSITION;
1072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mVisibleAnchorPosition = NO_POSITION;
1073b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = 0;
10742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
10762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "saved state:\n" + state);
10772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
10782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return state;
10792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
10802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1081a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1082a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
1083a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
1084a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        ViewGroup.LayoutParams lp = host.getLayoutParams();
1085a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (!(lp instanceof LayoutParams)) {
1086a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            super.onInitializeAccessibilityNodeInfoForItem(host, info);
1087a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return;
1088a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1089a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        LayoutParams sglp = (LayoutParams) lp;
1090a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1091a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1092a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1093a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1094a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1095a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        } else { // VERTICAL
1096a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1097a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1098a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1099a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1100a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1101a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1102a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1103a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1104a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1105a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        super.onInitializeAccessibilityEvent(event);
1106a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (getChildCount() > 0) {
1107a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final AccessibilityRecordCompat record = AccessibilityEventCompat
1108a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    .asRecord(event);
11096490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            final View start = findFirstVisibleItemClosestToStart(false, true);
11106490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            final View end = findFirstVisibleItemClosestToEnd(false, true);
1111a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (start == null || end == null) {
1112a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                return;
1113a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1114a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int startPos = getPosition(start);
1115a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int endPos = getPosition(end);
1116a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (startPos < endPos) {
1117a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setFromIndex(startPos);
1118a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setToIndex(endPos);
1119a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            } else {
1120a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setFromIndex(endPos);
1121a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                record.setToIndex(startPos);
1122a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1123a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1124a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1125a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1126333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
1127333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Finds the first fully visible child to be used as an anchor child if span count changes when
11286490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * state is restored. If no children is fully visible, returns a partially visible child instead
11296490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * of returning null.
1130333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
1131333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    int findFirstVisibleItemPositionInt() {
11326490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true, true) :
11336490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleItemClosestToStart(true, true);
1134d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return first == null ? NO_POSITION : getPosition(first);
1135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1136d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1137a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1138a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
1139a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1140a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1141a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1142a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1143a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getRowCountForAccessibility(recycler, state);
1144a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1145a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1146a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1147a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
1148a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1149a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == VERTICAL) {
1150a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1151a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1152a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getColumnCountForAccessibility(recycler, state);
1153a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1154a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
11556490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    View findFirstVisibleItemClosestToStart(boolean fullyVisible, boolean acceptPartiallyVisible) {
1156ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureOrientationHelper();
1157333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1158333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
1159d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int limit = getChildCount();
11606490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        View partiallyVisible = null;
116142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        for (int i = 0; i < limit; i++) {
1162333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final View child = getChildAt(i);
11636490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            if (mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) {
11646490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                if ((!fullyVisible
11656490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                        || mPrimaryOrientation.getDecoratedStart(child) >= boundsStart)) {
11666490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    return child;
11676490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                } else if (acceptPartiallyVisible && partiallyVisible == null) {
11686490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    partiallyVisible = child;
11696490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                }
1170d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
11726490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        return partiallyVisible;
1173d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
11756490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    View findFirstVisibleItemClosestToEnd(boolean fullyVisible, boolean acceptPartiallyVisible) {
1176ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureOrientationHelper();
1177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
11796490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        View partiallyVisible = null;
118042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
1181d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = getChildAt(i);
11826490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) >= boundsStart) {
11836490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                if (!fullyVisible || mPrimaryOrientation.getDecoratedEnd(child) <= boundsEnd) {
11846490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    return child;
11856490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                } else if (acceptPartiallyVisible && partiallyVisible == null) {
11866490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    partiallyVisible = child;
11876490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                }
1188333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
1189333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
11906490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        return partiallyVisible;
1191333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1192333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int maxEndLine = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
11992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = -scrollBy(-gap, recycler, state);
12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
12042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(gap);
12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int minStartLine = getMinStart(mPrimaryOrientation.getStartAfterPadding());
12122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
12132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = scrollBy(gap, recycler, state);
12162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
12182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
12202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
12212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(-gap);
12222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillStart(int anchorPosition, RecyclerView.State state) {
12262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
12272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
12282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos < anchorPosition) {
12312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
12322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_START;
12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_HEAD;
12412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateLayoutStateToFillEnd(int anchorPosition, RecyclerView.State state) {
12442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
12452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
12462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
12472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
12482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout == targetPos > anchorPosition) {
12492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = 0;
12502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
12512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLayoutState.mExtra = mPrimaryOrientation.getTotalSpace();
12522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mExtra = 0;
12552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mLayoutDirection = LAYOUT_END;
12572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
12582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                : ITEM_DIRECTION_TAIL;
12592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenHorizontal(int dx) {
12632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenHorizontal(dx);
12642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
12652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dx);
12662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenVertical(int dy) {
12712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenVertical(dy);
12722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
12732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dy);
12742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
1279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE);
12802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
12832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
1284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD);
1285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1287d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsChanged(RecyclerView recyclerView) {
1289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLazySpanLookup.clear();
1290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
1291d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
1295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE);
1296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
1300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE);
13012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
13042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Checks whether it should invalidate span assignments in response to an adapter change.
13052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) {
13072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition();
1308f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        final int affectedRangeEnd;// exclusive
1309f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        final int affectedRangeStart;// inclusive
1310f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1311f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (cmd == AdapterHelper.UpdateOp.MOVE) {
1312f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (positionStart < itemCountOrToPosition) {
1313f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeEnd = itemCountOrToPosition + 1;
1314f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeStart = positionStart;
1315f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            } else {
1316f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeEnd = positionStart + 1;
1317f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeStart = itemCountOrToPosition;
1318f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1319f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        } else {
1320f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            affectedRangeStart = positionStart;
1321f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            affectedRangeEnd = positionStart + itemCountOrToPosition;
1322f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1323f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1324f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        mLazySpanLookup.invalidateAfter(affectedRangeStart);
1325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        switch (cmd) {
1326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.ADD:
1327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition);
1328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.REMOVE:
1330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition);
1331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.MOVE:
1333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // TODO optimize
1334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, 1);
1335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1);
1336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1339f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (affectedRangeEnd <= minPosition) {
1340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
13412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1342f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
13432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition();
1344f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (affectedRangeStart <= maxPosition) {
13452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
13462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
13502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
13512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mRemainingSpans.set(0, mSpanCount, true);
13522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // The target position we are trying to reach.
13532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int targetLine;
13542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /*
13552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * The line until which we can recycle, as long as we add views.
13562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * Keep in mind, it is still the line in layout direction which means; to calculate the
13572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        * actual recycle line, we should subtract/add the size in orientation.
13582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        */
13592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int recycleLine;
13602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Line of the furthest row.
13612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
13623ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
13630ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getEndAfterPadding() + mLayoutState.mAvailable;
13640ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine + mLayoutState.mExtra + mPrimaryOrientation.getEndPadding();
1365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
13662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // LAYOUT_START
13673ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar            // ignore padding for recycler
13680ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            recycleLine = mPrimaryOrientation.getStartAfterPadding() - mLayoutState.mAvailable;
13690ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            targetLine = recycleLine - mLayoutState.mExtra -
1370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mPrimaryOrientation.getStartAfterPadding();
13712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1372d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
13732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // the default coordinate to add new view.
1375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int defaultNewViewLine = mShouldReverseLayout
1376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? mPrimaryOrientation.getEndAfterPadding()
1377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : mPrimaryOrientation.getStartAfterPadding();
13782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty()) {
13802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View view = layoutState.next(recycler);
13812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = ((LayoutParams) view.getLayoutParams());
1382115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            final int position = lp.getViewLayoutPosition();
13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanIndex = mLazySpanLookup.getSpan(position);
13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span currentSpan;
1385f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID;
1386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (assignSpan) {
1387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState);
13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.setSpan(position, currentSpan);
1389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position);
1391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "using " + spanIndex + " for pos " + position);
1395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
13962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                currentSpan = mSpans[spanIndex];
13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1398ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            // assign span before measuring so that item decorators can get updated span index
1399ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            lp.mSpan = currentSpan;
1400ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
1401ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar                addView(view);
1402ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            } else {
1403ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar                addView(view, 0);
1404ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            }
1405ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            measureChildWithDecorationsAndMargin(view, lp);
1406ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar
14072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int start;
14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int end;
14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
1410d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine)
1411d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getEndLine(defaultNewViewLine);
14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                end = start + mPrimaryOrientation.getDecoratedMeasurement(view);
1413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromEnd(start);
1416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_START;
1417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
14192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
14202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                end = lp.mFullSpan ? getMinStart(defaultNewViewLine)
1422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getStartLine(defaultNewViewLine);
14232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                start = end - mPrimaryOrientation.getDecoratedMeasurement(view);
1424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromStart(end);
1427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_END;
1428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
14302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
14312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
14322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // check if this item may create gaps in the future
1434f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD) {
1435f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                if (assignSpan) {
1436f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    mLaidOutInvalidFullSpan = true;
1437f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                } else {
1438f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    final boolean hasInvalidGap;
1439f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    if (layoutState.mLayoutDirection == LAYOUT_END) {
1440f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        hasInvalidGap = !areAllEndsEqual();
1441f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    } else { // layoutState.mLayoutDirection == LAYOUT_START
1442f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        hasInvalidGap = !areAllStartsEqual();
1443f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    }
1444f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    if (hasInvalidGap) {
1445f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup
1446f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                                .getFullSpanItem(position);
1447f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        if (fullSpanItem != null) {
1448f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                            fullSpanItem.mHasUnwantedGapAfter = true;
1449f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        }
1450f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        mLaidOutInvalidFullSpan = true;
1451f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    }
1452f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                }
1453f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
14542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            attachViewToSpans(view, lp, layoutState);
14562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
1457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : currentSpan.mIndex * mSizePerSpan +
1458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            mSecondaryOrientation.getStartAfterPadding();
14592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
14602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mOrientation == VERTICAL) {
14612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
14622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
14632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd);
14642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
14662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (lp.mFullSpan) {
1467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine);
14682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
14692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
14702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycle(recycler, mLayoutState, currentSpan, recycleLine);
14722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
14742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "fill, " + getChildCount());
14752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLayoutState.mLayoutDirection == LAYOUT_START) {
14772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding());
14780ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (recycleLine - minStart));
14792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
14802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int max = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
14810ae47e8ceb8062ba460c74149b009cf7914388eaYigit Boyar            return Math.max(0, mLayoutState.mAvailable + (max - recycleLine));
14822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) {
1486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop);
1490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) {
1495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1498d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom;
1499d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1501d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1502d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) {
1504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) {
1505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1506d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                appendViewToAllSpans(view);
1507d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1508d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.appendToSpan(view);
1509d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1511d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1512d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                prependViewToAllSpans(view);
1513d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1514d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.prependToSpan(view);
1515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1516d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1517d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1519d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState,
1520d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span updatedSpan, int recycleLine) {
1521d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_START) {
1522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // calculate recycle line
1523d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int maxStart = getMaxStart(updatedSpan.getStartLine());
1524d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycleFromEnd(recycler, Math.max(recycleLine, maxStart) +
1525d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
1526d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // calculate recycle line
1528d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int minEnd = getMinEnd(updatedSpan.getEndLine());
1529d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            recycleFromStart(recycler, Math.min(recycleLine, minEnd) -
1530d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    (mPrimaryOrientation.getEnd() - mPrimaryOrientation.getStartAfterPadding()));
1531d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1532d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1533d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void appendViewToAllSpans(View view) {
1535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1537d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].appendToSpan(view);
1538d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1541d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void prependViewToAllSpans(View view) {
1542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1544d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].prependToSpan(view);
1545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void layoutDecoratedWithMargins(View child, int left, int top, int right, int bottom) {
15492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
1550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
1551115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            Log.d(TAG, "layout decorated pos: " + lp.getViewLayoutPosition() + ", span:"
1552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + lp.getSpanIndex() + ", fullspan:" + lp.mFullSpan
1553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + ". l:" + left + ",t:" + top
1554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + ", r:" + right + ", b:" + bottom);
1555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
15562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin
15572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                , bottom - lp.bottomMargin);
15582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1560d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void updateAllRemainingSpans(int layoutDir, int targetLine) {
1561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpans[i].mViews.isEmpty()) {
1563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue;
1564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1565d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateRemainingSpans(mSpans[i], layoutDir, targetLine);
1566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
15692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateRemainingSpans(Span span, int layoutDir, int targetLine) {
15702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int deletedSize = span.getDeletedSize();
15712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutDir == LAYOUT_START) {
15722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getStartLine();
15732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line + deletedSize < targetLine) {
15742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
15752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
15772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getEndLine();
15782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (line - deletedSize > targetLine) {
15792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
15802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxStart(int def) {
15852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxStart = mSpans[0].getStartLine(def);
15862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
15882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart > maxStart) {
15892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxStart = spanStart;
15902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
15912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxStart;
15932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinStart(int def) {
15962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minStart = mSpans[0].getStartLine(def);
15972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
15982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
15992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart < minStart) {
16002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minStart = spanStart;
16012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minStart;
16042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1606f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    boolean areAllEndsEqual() {
1607f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        int end = mSpans[0].getEndLine(Span.INVALID_LINE);
1608f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        for (int i = 1; i < mSpanCount; i++) {
1609f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (mSpans[i].getEndLine(Span.INVALID_LINE) != end) {
1610f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                return false;
1611f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1612f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1613f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        return true;
1614f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    }
1615f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1616f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    boolean areAllStartsEqual() {
1617f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        int start = mSpans[0].getStartLine(Span.INVALID_LINE);
1618f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        for (int i = 1; i < mSpanCount; i++) {
1619f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (mSpans[i].getStartLine(Span.INVALID_LINE) != start) {
1620f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                return false;
1621f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1622f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1623f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        return true;
1624f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    }
1625f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
16262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxEnd(int def) {
16272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxEnd = mSpans[0].getEndLine(def);
16282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
16292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
16302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd > maxEnd) {
16312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxEnd = spanEnd;
16322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxEnd;
16352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinEnd(int def) {
16382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minEnd = mSpans[0].getEndLine(def);
16392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
16402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
16412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd < minEnd) {
16422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minEnd = spanEnd;
16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minEnd;
16462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromStart(RecyclerView.Recycler recycler, int line) {
16492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
16502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "recycling from start for line " + line);
16512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (getChildCount() > 0) {
16532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(0);
16542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedEnd(child) < line) {
16552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
16562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
16572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
16582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popStart();
16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popStart();
16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
16642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
16662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromEnd(RecyclerView.Recycler recycler, int line) {
16712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
16722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int i;
16732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (i = childCount - 1; i >= 0; i--) {
16742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(i);
16752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mPrimaryOrientation.getDecoratedStart(child) > line) {
16762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
16772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
16782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popEnd();
16802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
16812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popEnd();
16832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
16862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;// done
16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
16892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
16912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1692d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return True if last span is the first one we want to fill
1693d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
1694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean preferLastSpan(int layoutDir) {
1695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mOrientation == HORIZONTAL) {
1696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return (layoutDir == LAYOUT_START) != mShouldReverseLayout;
1697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL();
1699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
17022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Finds the span for the next view.
17032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
17042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span getNextSpan(LayoutState layoutState) {
1705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection);
1706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int startIndex, endIndex, diff;
1707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (preferLastSpan) {
1708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = mSpanCount - 1;
1709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = -1;
1710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = -1;
1711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = 0;
1713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = mSpanCount;
1714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = 1;
1715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
17162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
1717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span min = null;
1718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int minLine = Integer.MAX_VALUE;
17192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getStartAfterPadding();
1720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
17212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getEndLine(defaultLine);
1723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine < minLine) {
17242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    min = other;
17252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    minLine = otherLine;
17262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return min;
17292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span max = null;
1731d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int maxLine = Integer.MIN_VALUE;
17322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getEndAfterPadding();
1733d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
17342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1735d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getStartLine(defaultLine);
1736d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine > maxLine) {
17372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    max = other;
17382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    maxLine = otherLine;
17392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return max;
17422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollVertically() {
17472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == VERTICAL;
17482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollHorizontally() {
17522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == HORIZONTAL;
17532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
17572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
17582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dx, recycler, state);
17592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
17632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
17642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dy, recycler, state);
17652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int calculateScrollDirectionForPosition(int position) {
17682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() == 0) {
17692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START;
17702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
17712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int firstChildPos = getFirstChildPosition();
17722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
17732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
17772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int position) {
17782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) {
17792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
17802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public PointF computeScrollVectorForPosition(int targetPosition) {
17812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int direction = calculateScrollDirectionForPosition(targetPosition);
17822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (direction == 0) {
17832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return null;
17842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mOrientation == HORIZONTAL) {
17862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(direction, 0);
17872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
17882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return new PointF(0, direction);
17892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
17922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        scroller.setTargetPosition(position);
17932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        startSmoothScroll(scroller);
17942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
17952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
17962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
17972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPosition(int position) {
17982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) {
17992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
18002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
18022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
18032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
18042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
18072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Scroll to the specified adapter position with the given offset from layout start.
18082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
18092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Note that scroll position change will not be reflected until the next layout call.
18102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
18112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
18122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
18132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param position Index (starting at 0) of the reference item.
18142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param offset   The distance (in pixels) between the start edge of the item view and
18152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                 start edge of the RecyclerView.
18162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
18172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #scrollToPosition(int)
18182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
18192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPositionWithOffset(int position, int offset) {
18202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
18212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
18222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = offset;
18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1828d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
18292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        ensureOrientationHelper();
18302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int referenceChildPosition;
18312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (dt > 0) { // layout towards end
18322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_END;
18332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_HEAD
18342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_TAIL;
18352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getLastChildPosition();
18362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
18372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mLayoutDirection = LAYOUT_START;
18382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? ITEM_DIRECTION_TAIL
18392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : ITEM_DIRECTION_HEAD;
18402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getFirstChildPosition();
18412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
18432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int absDt = Math.abs(dt);
18442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = absDt;
18452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mExtra = isSmoothScrolling() ? mPrimaryOrientation.getTotalSpace() : 0;
18462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int consumed = fill(recycler, mLayoutState, state);
18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int totalScroll;
18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (absDt < consumed) {
18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = dt;
18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (dt < 0) {
18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = -consumed;
18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // dt > 0
18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = consumed;
18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "asked " + dt + " scrolled" + totalScroll);
18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1859d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mPrimaryOrientation.offsetChildren(-totalScroll);
18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // always reset this if we scroll for a proper save instance state
18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLastLayoutFromEnd = mShouldReverseLayout;
18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return totalScroll;
18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getLastChildPosition() {
18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1));
18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getFirstChildPosition() {
18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
18722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(0));
18732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1875719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1876719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the first View that can be used as an anchor View.
1877719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1878719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1879719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1880719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findFirstReferenceChildPosition(int itemCount) {
1881719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        final int limit = getChildCount();
1882719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = 0; i < limit; i++) {
1883719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1884719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1885719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1886719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1887719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1888719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1889719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1890719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1891719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1892719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1893719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the last View that can be used as an anchor View.
1894719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1895719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
1896719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1897719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findLastReferenceChildPosition(int itemCount) {
1898719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
1899719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1900719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1901719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1902719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
1903719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1904719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
1905719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
1906719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1907719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
19082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
19102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
19112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT);
19122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
19162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(c, attrs);
19172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
19212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (lp instanceof ViewGroup.MarginLayoutParams) {
19222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
19232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
19242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams(lp);
19252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
19302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return lp instanceof LayoutParams;
19312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getOrientation() {
19342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation;
19352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
19392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * LayoutParams used by StaggeredGridLayoutManager.
194042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * <p>
194142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the
194242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is
194342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * expected to fill all of the space given to it.
19442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
19452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static class LayoutParams extends RecyclerView.LayoutParams {
19462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
19482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Span Id for Views that are not laid out yet.
19492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
19502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final int INVALID_SPAN_ID = -1;
19512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Package scope to be able to access from tests.
19532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        Span mSpan;
19542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mFullSpan;
19562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(Context c, AttributeSet attrs) {
19582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(c, attrs);
19592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(int width, int height) {
19622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(width, height);
19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.MarginLayoutParams source) {
19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.LayoutParams source) {
19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
19712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(RecyclerView.LayoutParams source) {
19742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * When set to true, the item will layout using all span area. That means, if orientation
19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * is vertical, the view will have full width; if orientation is horizontal, the view will
19802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * have full height.
19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param fullSpan True if this item should traverse all spans.
19837499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #isFullSpan()
19842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
19852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void setFullSpan(boolean fullSpan) {
19862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mFullSpan = fullSpan;
19872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
19907499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * Returns whether this View occupies all available spans or just one.
19917499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         *
19927499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @return True if the View occupies all spans or false otherwise.
19937499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #setFullSpan(boolean)
19947499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         */
19957499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        public boolean isFullSpan() {
19967499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar            return mFullSpan;
19977499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        }
19987499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar
19997499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        /**
20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns the Span index to which this View is assigned.
20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
20022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return The Span index of the View. If View is not yet assigned to any span, returns
20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * {@link #INVALID_SPAN_ID}.
20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public final int getSpanIndex() {
20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpan == null) {
20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return INVALID_SPAN_ID;
20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mSpan.mIndex;
20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    // Package scoped to access from tests.
20142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    class Span {
20152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20166b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        static final int INVALID_LINE = Integer.MIN_VALUE;
20172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private ArrayList<View> mViews = new ArrayList<View>();
20182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedStart = INVALID_LINE;
20192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedEnd = INVALID_LINE;
20202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mDeletedSize = 0;
20212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mIndex;
20222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private Span(int index) {
20242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mIndex = index;
20252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine(int def) {
20282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
20292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
20302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
20332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2034d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
20352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedStart() {
2039d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View startView = mViews.get(0);
2040d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(startView);
2041d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedStart = mPrimaryOrientation.getDecoratedStart(startView);
2042d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
2043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
2044115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        .getFullSpanItem(lp.getViewLayoutPosition());
2045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_START) {
2046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedStart -= fsi.getGapForSpan(mIndex);
2047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2049d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2050d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine() {
20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2056d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine(int def) {
20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 0) {
20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
20702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedEnd() {
2073d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View endView = mViews.get(mViews.size() - 1);
2074d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(endView);
2075d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView);
2076d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
2077d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
2078115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        .getFullSpanItem(lp.getViewLayoutPosition());
2079d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_END) {
2080d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedEnd += fsi.getGapForSpan(mIndex);
2081d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2082d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2083d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2084d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
20852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
20862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine() {
20872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
20882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
20892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2090d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
20912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
20922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void prependToSpan(View view) {
20952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
20962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
20972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(0, view);
20982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
20992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
21002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
21012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21027c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
21032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
21042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void appendToSpan(View view) {
21082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
21092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
21102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(view);
21112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
21122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
21132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
21142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21157c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
21162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
21172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Useful method to preserve positions on a re-layout.
21212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void cacheReferenceLineAndClear(boolean reverseLayout, int offset) {
21222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int reference;
21232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reverseLayout) {
21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getEndLine(INVALID_LINE);
21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
21262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getStartLine(INVALID_LINE);
21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            clear();
21292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reference == INVALID_LINE) {
21302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
21312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2132d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) ||
213342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) {
2134d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
21362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (offset != INVALID_OFFSET) {
21372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference += offset;
21382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mCachedEnd = reference;
21402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
21432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.clear();
21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateCache();
21452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mDeletedSize = 0;
21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateCache() {
21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
21512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setLine(int line) {
21542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mCachedStart = line;
21552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popEnd() {
21582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
21592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View end = mViews.remove(size - 1);
21602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(end);
21612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
21627c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
21632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end);
21642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 1) {
21662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
21672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
21692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popStart() {
21722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View start = mViews.remove(0);
21732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(start);
21742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
21752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
21762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
21772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21787c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
21792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start);
21802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
21822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int getDeletedSize() {
21852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mDeletedSize;
21862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams getLayoutParams(View view) {
21892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return (LayoutParams) view.getLayoutParams();
21902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
21922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void onOffset(int dt) {
21932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
21942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart += dt;
21952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
21972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd += dt;
21982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
21992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // normalized offset is how much this span can scroll
22022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getNormalizedOffset(int dt, int targetStart, int targetEnd) {
22032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
22042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return 0;
22052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (dt < 0) {
22072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int endSpace = getEndLine() - targetEnd;
22082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (endSpace <= 0) {
22092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
22102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
22112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return -dt > endSpace ? -endSpace : dt;
22122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
22132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final int startSpace = targetStart - getStartLine();
22142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (startSpace <= 0) {
22152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return 0;
22162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
22172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return startSpace < dt ? startSpace : dt;
22182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
22222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns if there is no child between start-end lines
22232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
22242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param start The start line
22252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param end   The end line
22262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return true if a new child can be added between start and end
22272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
22282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean isEmpty(int start, int end) {
22292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int count = mViews.size();
22302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < count; i++) {
22312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final View view = mViews.get(i);
22322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (mPrimaryOrientation.getDecoratedStart(view) < end &&
22332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mPrimaryOrientation.getDecoratedEnd(view) > start) {
22342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    return false;
22352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
22362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
22372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return true;
22382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
2239333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2240333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstVisibleItemPosition() {
2241333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
224242e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    ? findOneVisibleChild(mViews.size() - 1, -1, false)
2243333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), false);
2244333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2245333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2246333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstCompletelyVisibleItemPosition() {
2247333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
224842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    ? findOneVisibleChild(mViews.size() - 1, -1, true)
2249333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), true);
2250333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2251333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2252333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastVisibleItemPosition() {
2253333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2254333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), false)
225542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, false);
2256333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2257333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2258333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastCompletelyVisibleItemPosition() {
2259333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2260333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), true)
226142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, true);
2262333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2263333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2264333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
2265333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int start = mPrimaryOrientation.getStartAfterPadding();
2266333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int end = mPrimaryOrientation.getEndAfterPadding();
2267333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int next = toIndex > fromIndex ? 1 : -1;
2268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = fromIndex; i != toIndex; i += next) {
2269333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final View child = mViews.get(i);
2270333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
2271333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
2272333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                if (childStart < end && childEnd > start) {
2273333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    if (completelyVisible) {
2274333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        if (childStart >= start && childEnd <= end) {
2275333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                            return getPosition(child);
2276333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        }
2277333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    } else {
2278333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        return getPosition(child);
2279333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    }
2280333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                }
2281333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
2282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return NO_POSITION;
2283333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
22842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
22872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * An array of mappings from adapter position to span.
22882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * This only grows when a write happens and it grows up to the size of the adapter.
22892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
22902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class LazySpanLookup {
22912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private static final int MIN_SIZE = 10;
22932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mData;
2294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<FullSpanItem> mFullSpanItems;
2295d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Invalidates everything after this position, including full span information
2299d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int forceInvalidateAfter(int position) {
2301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems != null) {
2302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2303d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    FullSpanItem fsi = mFullSpanItems.get(i);
2304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (fsi.mPosition >= position) {
2305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return invalidateAfter(position);
2310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
23112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * returns end position for invalidation.
2314d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2315d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidateAfter(int position) {
23162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
2317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
23182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
23192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (position >= mData.length) {
2320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int endPosition = invalidateFullSpansAfter(position);
2323d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (endPosition == RecyclerView.NO_POSITION) {
2324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID);
2325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mData.length;
2326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
2327d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // just invalidate items in between
2328d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID);
2329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return endPosition + 1;
23302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
23312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getSpan(int position) {
23342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null || position >= mData.length) {
23352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return LayoutParams.INVALID_SPAN_ID;
23362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
23372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mData[position];
23382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
23392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setSpan(int position, Span span) {
23422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(position);
23432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mData[position] = span.mIndex;
23442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int sizeForPosition(int position) {
23472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int len = mData.length;
23482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            while (len <= position) {
23492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len *= 2;
23502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
23512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return len;
23522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void ensureSize(int position) {
23552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
23562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[Math.max(position, MIN_SIZE) + 1];
23572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
23582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else if (position >= mData.length) {
23592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int[] old = mData;
23602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[sizeForPosition(position)];
23612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                System.arraycopy(old, 0, mData, 0, old.length);
23622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID);
23632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
23642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
23672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData != null) {
23682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
23692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
23712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
23722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForRemoval(int positionStart, int itemCount) {
2374d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
23772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
23782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart + itemCount, mData, positionStart,
23792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
23802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, mData.length - itemCount, mData.length,
23812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2382d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForRemoval(positionStart, itemCount);
2383d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2384d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForRemoval(int positionStart, int itemCount) {
2386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2388d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int end = positionStart + itemCount;
2390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2392d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2394d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2395d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < end) {
2396d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.remove(i);
2397d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
2398d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fsi.mPosition -= itemCount;
2399d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2400d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
24012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForAddition(int positionStart, int itemCount) {
2404d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2405d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2406d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
24072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
24082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart, mData, positionStart + itemCount,
24092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
24102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, positionStart, positionStart + itemCount,
24112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2412d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForAddition(positionStart, itemCount);
2413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2415d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForAddition(int positionStart, int itemCount) {
2416d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2417d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2418d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2419d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2420d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2421d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2422d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2423d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2424d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                fsi.mPosition += itemCount;
2425d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2426d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2427d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2428d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2429d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returns when invalidation should end. e.g. hitting a full span position.
2430d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returned position SHOULD BE invalidated.
2431d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2432d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private int invalidateFullSpansAfter(int position) {
2433d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2434d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2435d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2436d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final FullSpanItem item = getFullSpanItem(position);
2437d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if there is an fsi at this position, get rid of it.
2438d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (item != null) {
2439d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(item);
2440d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2441d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int nextFsiIndex = -1;
2442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int count = mFullSpanItems.size();
2443d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < count; i++) {
2444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2445d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= position) {
2446d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    nextFsiIndex = i;
2447d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    break;
2448d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2449d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2450d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (nextFsiIndex != -1) {
2451d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex);
2452d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(nextFsiIndex);
2453d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return fsi.mPosition;
2454d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2455d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return RecyclerView.NO_POSITION;
2456d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2457d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2458d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void addFullSpanItem(FullSpanItem fullSpanItem) {
2459d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2460d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems = new ArrayList<FullSpanItem>();
2461d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2462d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int size = mFullSpanItems.size();
2463d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < size; i++) {
2464d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem other = mFullSpanItems.get(i);
2465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition == fullSpanItem.mPosition) {
2466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (DEBUG) {
2467d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        throw new IllegalStateException("two fsis for same position");
2468d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
2469d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition >= fullSpanItem.mPosition) {
2473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.add(i, fullSpanItem);
2474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return;
2475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if it is not added to a position.
2478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems.add(fullSpanItem);
2479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public FullSpanItem getFullSpanItem(int position) {
2482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
2484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2485d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final FullSpanItem fsi = mFullSpanItems.get(i);
2487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition == position) {
2488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
2489d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2490d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2491d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
2492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param minPos inclusive
2496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param maxPos exclusive
2497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param gapDir if not 0, returns FSIs on in that direction
2498f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar         * @param hasUnwantedGapAfter If true, when full span item has unwanted gaps, it will be
2499f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar         *                        returned even if its gap direction does not match.
2500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2501f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir,
2502f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                boolean hasUnwantedGapAfter) {
2503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
2505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2506f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            final int limit = mFullSpanItems.size();
2507f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            for (int i = 0; i < limit; i++) {
2508d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2509d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= maxPos) {
2510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return null;
2511d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2512f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                if (fsi.mPosition >= minPos
2513f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        && (gapDir == 0 || fsi.mGapDir == gapDir ||
2514f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) {
2515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
2516d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2517d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
2519d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2520d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2521d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * We keep information about full span items because they may create gaps in the UI.
2523d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2524d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        static class FullSpanItem implements Parcelable {
2525d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2526d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mPosition;
2527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mGapDir;
2528d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int[] mGapPerSpan;
2529f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // A full span may be laid out in primary direction but may have gaps due to
2530f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // invalidation of views after it. This is recorded during a reverse scroll and if
2531f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // view is still on the screen after scroll stops, we have to recalculate layout
2532f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            boolean mHasUnwantedGapAfter;
2533d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public FullSpanItem(Parcel in) {
2535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPosition = in.readInt();
2536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mGapDir = in.readInt();
2537f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                mHasUnwantedGapAfter = in.readInt() == 1;
2538d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int spanCount = in.readInt();
2539d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (spanCount > 0) {
2540d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mGapPerSpan = new int[spanCount];
2541d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    in.readIntArray(mGapPerSpan);
2542d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2543d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2544d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2545d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public FullSpanItem() {
2546d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2547d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2548d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int getGapForSpan(int spanIndex) {
2549d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
2550d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2551d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2552d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public void invalidateSpanGaps() {
2553d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mGapPerSpan = null;
2554d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2555d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2556d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public int describeContents() {
2558d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return 0;
2559d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2560d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2561d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2562d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public void writeToParcel(Parcel dest, int flags) {
2563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mPosition);
2564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mGapDir);
2565f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                dest.writeInt(mHasUnwantedGapAfter ? 1 : 0);
2566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mGapPerSpan != null && mGapPerSpan.length > 0) {
2567d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(mGapPerSpan.length);
2568d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeIntArray(mGapPerSpan);
2569d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
2570d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(0);
2571d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2572d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2573d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2574d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
2575d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public String toString() {
2576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return "FullSpanItem{" +
2577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        "mPosition=" + mPosition +
2578d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        ", mGapDir=" + mGapDir +
2579f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter +
2580d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) +
2581d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        '}';
2582d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public static final Parcelable.Creator<FullSpanItem> CREATOR
2585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    = new Parcelable.Creator<FullSpanItem>() {
2586d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                @Override
2587d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                public FullSpanItem createFromParcel(Parcel in) {
2588d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return new FullSpanItem(in);
2589d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2590d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2591d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                @Override
2592d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                public FullSpanItem[] newArray(int size) {
2593d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return new FullSpanItem[size];
2594d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2595d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            };
25962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
25982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class SavedState implements Parcelable {
26002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAnchorPosition;
2602d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
2603b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar        int mSpanOffsetsSize;
26042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanOffsets;
26052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mSpanLookupSize;
26062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanLookup;
2607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<LazySpanLookup.FullSpanItem> mFullSpanItems;
26082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mReverseLayout;
26092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mAnchorLayoutFromEnd;
2610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLastLayoutRTL;
26112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState() {
26132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState(Parcel in) {
26162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = in.readInt();
2617333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = in.readInt();
2618b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = in.readInt();
2619b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
2620b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar                mSpanOffsets = new int[mSpanOffsetsSize];
26212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanOffsets);
26222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = in.readInt();
26252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
26262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpanLookup = new int[mSpanLookupSize];
26272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanLookup);
26282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = in.readInt() == 1;
26302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = in.readInt() == 1;
2631d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = in.readInt() == 1;
2632d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = in.readArrayList(
2633d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem.class.getClassLoader());
26342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState(SavedState other) {
2637b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = other.mSpanOffsetsSize;
26382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = other.mAnchorPosition;
2639333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = other.mVisibleAnchorPosition;
26402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = other.mSpanOffsets;
26412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = other.mSpanLookupSize;
26422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = other.mSpanLookup;
26432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = other.mReverseLayout;
26442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
2645d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = other.mLastLayoutRTL;
2646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = other.mFullSpanItems;
26472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateSpanInfo() {
26502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
2651b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
26522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = 0;
26532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = null;
2654d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
26552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateAnchorPositionInfo() {
26582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
2659b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
2660d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mAnchorPosition = NO_POSITION;
2661d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mVisibleAnchorPosition = NO_POSITION;
26622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
26652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int describeContents() {
26662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return 0;
26672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
26702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void writeToParcel(Parcel dest, int flags) {
26712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorPosition);
2672333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            dest.writeInt(mVisibleAnchorPosition);
2673b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            dest.writeInt(mSpanOffsetsSize);
2674b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
26752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanOffsets);
26762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mSpanLookupSize);
26782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
26792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanLookup);
26802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mReverseLayout ? 1 : 0);
26822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
2683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeInt(mLastLayoutRTL ? 1 : 0);
2684d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeList(mFullSpanItems);
26852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final Parcelable.Creator<SavedState> CREATOR
26882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                = new Parcelable.Creator<SavedState>() {
26892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
26902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState createFromParcel(Parcel in) {
26912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState(in);
26922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            @Override
26952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            public SavedState[] newArray(int size) {
26962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return new SavedState[size];
26972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        };
26992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
2702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Data class to hold the information about an anchor position which is used in onLayout call.
2703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
2704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private class AnchorInfo {
2705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mPosition;
2707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mOffset;
2708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLayoutFromEnd;
2709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mInvalidateOffsets;
2710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void reset() {
2712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPosition = NO_POSITION;
2713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = INVALID_OFFSET;
2714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLayoutFromEnd = false;
2715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mInvalidateOffsets = false;
2716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding() {
2719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding()
2720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : mPrimaryOrientation.getStartAfterPadding();
2721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding(int addedDistance) {
2724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mLayoutFromEnd) {
2725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance;
2726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
2727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance;
2728d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2729d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2730d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
27312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar}
2732