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
198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
206b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_HEAD;
216b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static android.support.v7.widget.LayoutState.ITEM_DIRECTION_TAIL;
226b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_END;
236b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static android.support.v7.widget.LayoutState.LAYOUT_START;
246b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyarimport static android.support.v7.widget.RecyclerView.NO_POSITION;
256b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar
262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.content.Context;
272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.PointF;
282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.graphics.Rect;
292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcel;
302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.os.Parcelable;
31f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyarimport android.support.annotation.NonNull;
32f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyarimport android.support.annotation.Nullable;
33c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo;
342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.support.v4.view.ViewCompat;
35a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.AttributeSet;
372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.util.Log;
382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.View;
392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport android.view.ViewGroup;
40a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent;
412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.ArrayList;
432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.Arrays;
442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyarimport java.util.BitSet;
45d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport java.util.List;
462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar/**
482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * A LayoutManager that lays out children in a staggered grid formation.
492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * It supports horizontal & vertical layout as well as an ability to layout children in reverse.
502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * <p>
512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps,
522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can
532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar * control this behavior via {@link #setGapStrategy(int)}.
542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar */
55c587f7dba5a337169e854e235da59f595255d6ccAga Madurskapublic class StaggeredGridLayoutManager extends RecyclerView.LayoutManager implements
56c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        RecyclerView.SmoothScroller.ScrollVectorProvider {
572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
58ec0c39bc2e86bb08f238956ebb744f54c46c3815Aurimas Liutikas    private static final String TAG = "StaggeredGridLayoutManager";
592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
603a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    static final boolean DEBUG = false;
612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6203a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
6303a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
6403a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar    public static final int VERTICAL = OrientationHelper.VERTICAL;
6503a57e1f233833f7d5706bfacb0d5c84d4a039e9Yigit Boyar
662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
67d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Does not do anything to hide gaps.
682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_NONE = 0;
702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
71d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    /**
72d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette     * @deprecated No longer supported.
73d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette     */
74f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    @SuppressWarnings("unused")
75d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Deprecated
762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_LAZY = 1;
772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
79d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * When scroll state is changed to {@link RecyclerView#SCROLL_STATE_IDLE}, StaggeredGrid will
80d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * check if there are gaps in the because of full span items. If it finds, it will re-layout
81d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * and move items to correct positions with animations.
822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For example, if LayoutManager ends up with the following layout due to adapter changes:
84115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <pre>
852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * _BC
872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
88115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * </pre>
89115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <p>
902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * It will animate to the following state:
91115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * <pre>
922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * AAA
932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * BC_
942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * DDD
95115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * </pre>
962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2;
982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
993a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    static final int INVALID_OFFSET = Integer.MIN_VALUE;
100f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    /**
101f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * While trying to find next view to focus, LayoutManager will not try to scroll more
102f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * than this factor times the total space of the list. If layout is vertical, total space is the
103f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * height minus padding, if layout is horizontal, total space is the width minus padding.
104f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     */
105f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    private static final float MAX_SCROLL_FACTOR = 1 / 3f;
1062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Number of spans
1092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSpanCount = -1;
1112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1123a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    Span[] mSpans;
1132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Primary orientation is the layout's orientation, secondary orientation is the orientation
1162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for spans. Having both makes code much cleaner for calculations.
1172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
118f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    @NonNull
1192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mPrimaryOrientation;
120f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    @NonNull
1212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    OrientationHelper mSecondaryOrientation;
1222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mOrientation;
1242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * The width or height per span, depending on the orientation.
1272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mSizePerSpan;
1292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
130f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    @NonNull
131f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    private final LayoutState mLayoutState;
1322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1333a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    boolean mReverseLayout = false;
1342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Aggregated reverse layout value that takes RTL into account.
1372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
138d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean mShouldReverseLayout = false;
1392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Temporary variable used during fill method to check which spans needs to be filled.
1422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private BitSet mRemainingSpans;
1442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
1472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout which will check this variable and re-layout accordingly.
1482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
149d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    int mPendingScrollPosition = NO_POSITION;
1502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
1532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * called.
1542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1556e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPositionOffset = INVALID_OFFSET;
1562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Keeps the mapping between the adapter positions and spans. This is necessary to provide
1592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * a consistent experience when user scrolls the list.
1602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    LazySpanLookup mLazySpanLookup = new LazySpanLookup();
1622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * how we handle gaps in UI.
1652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
1672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Saved state needs this information to properly layout on restore.
1702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private boolean mLastLayoutFromEnd;
1722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
174d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Saved state and onLayout needs this information to re-layout properly
175d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
176d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLastLayoutRTL;
177d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
178d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
1792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * SavedState is not handled until a layout happens. This is where we keep it until next
1802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * layout.
1812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private SavedState mPendingSavedState;
1832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
185d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used measurement specs. updated by onLayout.
1862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1874143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    private int mFullSizeSpec;
188d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
189d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
190c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar     * Re-used rectangle to get child decor offsets.
191c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar     */
192c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar    private final Rect mTmpRect = new Rect();
193c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar
194c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar    /**
195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Re-used anchor info.
196d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
197d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private final AnchorInfo mAnchorInfo = new AnchorInfo();
198d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
199d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
200d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * If a full span item is invalid / or created in reverse direction; it may create gaps in
201d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the UI. While laying out, if such case is detected, we set this flag.
202d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
203d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * After scrolling stops, we check this flag and if it is set, re-layout.
204d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
205d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mLaidOutInvalidFullSpan = false;
206d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
207d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
208d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}.
209d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}
210d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean mSmoothScrollbarEnabled = true;
212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
213945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    /**
2141e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik     * Temporary array used (solely in {@link #collectAdjacentPrefetchPositions}) for stashing and
2151e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik     * sorting distances to views being prefetched.
216945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik     */
217945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    private int[] mPrefetchDistances;
218945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik
219ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar    private final Runnable mCheckForGapsRunnable = new Runnable() {
220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        @Override
221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void run() {
222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    };
2252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
2270194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     * Constructor used when layout manager is set in XML by RecyclerView attribute
2280194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     * "layoutManager". Defaults to single column and vertical.
2290194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     */
230f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    @SuppressWarnings("unused")
2310194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    public StaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
2320194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta            int defStyleRes) {
2330194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
2340194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setOrientation(properties.orientation);
2350194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setSpanCount(properties.spanCount);
2360194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setReverseLayout(properties.reverseLayout);
2374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
238f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mLayoutState = new LayoutState();
239f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        createOrientationHelpers();
2400194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    }
2410194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta
2420194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    /**
2432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Creates a StaggeredGridLayoutManager with given parameters.
2442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
2452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount   If orientation is vertical, spanCount is number of columns. If
2462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                    orientation is horizontal, spanCount is number of rows.
2479bea36cf2e318e9b729ddc62d855cd0f93bc3866Yigit Boyar     * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL}
2482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
2492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public StaggeredGridLayoutManager(int spanCount, int orientation) {
2502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
2512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        setSpanCount(spanCount);
2524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
253f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mLayoutState = new LayoutState();
254f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        createOrientationHelpers();
255f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    }
256f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar
257f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    private void createOrientationHelpers() {
258f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation);
259f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mSecondaryOrientation = OrientationHelper
260f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar                .createOrientationHelper(this, 1 - mOrientation);
2612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
2622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps in the UI that may be caused by adapter changes.
265d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
266d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * When a full span item is laid out in reverse direction, it sets a flag which we check when
267d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll is stopped (or re-layout happens) and re-layout after first valid item.
268d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
2693a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    boolean checkForGaps() {
270ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar        if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE || !isAttachedToWindow()) {
271ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            return false;
272d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
273d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int minPos, maxPos;
274d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
275d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getLastChildPosition();
276d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getFirstChildPosition();
277d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
278d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            minPos = getFirstChildPosition();
279d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            maxPos = getLastChildPosition();
280d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
281d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (minPos == 0) {
282d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View gapView = hasGapsToFix();
283d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (gapView != null) {
284d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
285d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestSimpleAnimationsInNextLayout();
286d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                requestLayout();
287ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar                return true;
288d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
289d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
290d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (!mLaidOutInvalidFullSpan) {
291ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            return false;
292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup
295f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir, true);
296d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (invalidFsi == null) {
297d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLaidOutInvalidFullSpan = false;
298d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(maxPos + 1);
299ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            return false;
300d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
301d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup
302d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition,
303f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        invalidGapDir * -1, true);
304d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (validFsi == null) {
305d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition);
306d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
307d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1);
308d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
309d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestSimpleAnimationsInNextLayout();
310d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
311ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar        return true;
312d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
313d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
3152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onScrollStateChanged(int state) {
316d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state == RecyclerView.SCROLL_STATE_IDLE) {
317d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            checkForGaps();
318d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
319d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
320d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
321d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
323ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar        removeCallbacks(mCheckForGapsRunnable);
324d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
325d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].clear();
326d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
327a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        // SGLM will require fresh layout call to recover state after detach
328a90fb62f06861beb3af9f9b3356ef0bb0685547cYigit Boyar        view.requestLayout();
329d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
330d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
331d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
332d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Checks for gaps if we've reached to the top of the list.
333d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * <p>
334d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field.
335d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
336d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    View hasGapsToFix() {
337d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int startChildIndex = 0;
338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int endChildIndex = getChildCount() - 1;
339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        BitSet mSpansToCheck = new BitSet(mSpanCount);
340d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mSpansToCheck.set(0, mSpanCount, true);
341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int firstChildIndex, childLimit;
343d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1;
344d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
345d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
346ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            firstChildIndex = endChildIndex;
347d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            childLimit = startChildIndex - 1;
348d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
349d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            firstChildIndex = startChildIndex;
350ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            childLimit = endChildIndex + 1;
351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
352d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1;
353d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) {
354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            View child = getChildAt(i);
355d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            LayoutParams lp = (LayoutParams) child.getLayoutParams();
356d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpansToCheck.get(lp.mSpan.mIndex)) {
357d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (checkSpanForGap(lp.mSpan)) {
358d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return child;
359d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
360d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mSpansToCheck.clear(lp.mSpan.mIndex);
361d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
362d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
363d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue; // quick reject
364d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
365d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
366d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (i + nextChildDiff != childLimit) {
367d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                View nextChild = getChildAt(i + nextChildDiff);
368d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                boolean compareSpans = false;
369d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mShouldReverseLayout) {
370d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // ensure child's end is below nextChild's end
371d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myEnd = mPrimaryOrientation.getDecoratedEnd(child);
372d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild);
373d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myEnd < nextEnd) {
3741e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return child; //i should have a better position
375d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myEnd == nextEnd) {
376d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
377d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
378d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
379d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int myStart = mPrimaryOrientation.getDecoratedStart(child);
380d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild);
381d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (myStart > nextStart) {
3821e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return child; //i should have a better position
383d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else if (myStart == nextStart) {
384d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        compareSpans = true;
385d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
386d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
387d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (compareSpans) {
388d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // equal, check span indices.
389d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams();
390d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) {
391d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        return child;
392d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
393d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
3952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
396d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // everything looks good
397d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return null;
398d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
399d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
400d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean checkSpanForGap(Span span) {
401d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mShouldReverseLayout) {
402d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) {
4034143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                // if it is full span, it is OK
4044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                final View endView = span.mViews.get(span.mViews.size() - 1);
4054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                final LayoutParams lp = span.getLayoutParams(endView);
4064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                return !lp.mFullSpan;
407d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
408d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) {
4094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            // if it is full span, it is OK
4104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final View startView = span.mViews.get(0);
4114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final LayoutParams lp = span.getLayoutParams(startView);
4124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return !lp.mFullSpan;
413d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
414d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return false;
4152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the number of spans for the layout. This will invalidate all of the span assignments
4192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * for Views.
4202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calling this method will automatically result in a new layout request unless the spanCount
4222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * parameter is equal to current span count.
4232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param spanCount Number of spans to layout
4252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setSpanCount(int spanCount) {
4270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (spanCount != mSpanCount) {
4292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateSpanAssignments();
4302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanCount = spanCount;
4312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mRemainingSpans = new BitSet(mSpanCount);
4322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans = new Span[mSpanCount];
4332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
4342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpans[i] = new Span(i);
4352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
4362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
4372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep
442d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * scroll position if this method is called after views are laid out.
4432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
444d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
4452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setOrientation(int orientation) {
4472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation != HORIZONTAL && orientation != VERTICAL) {
4482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid orientation.");
4492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (orientation == mOrientation) {
4522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
4532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mOrientation = orientation;
455f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        OrientationHelper tmp = mPrimaryOrientation;
456f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mPrimaryOrientation = mSecondaryOrientation;
457f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar        mSecondaryOrientation = tmp;
4582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets whether LayoutManager should start laying out items from the end of the UI. The order
4632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * items are traversed is not affected by this call.
4642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * For vertical layout, if it is set to <code>true</code>, first item will be at the bottom of
466d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * the list.
4672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For horizontal layouts, it depends on the layout direction.
4692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if
4702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link RecyclerView}} is RTL, it will layout from LTR.
4712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param reverseLayout Whether layout should be in reverse or not
4732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setReverseLayout(boolean reverseLayout) {
4750bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
4762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) {
4772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.mReverseLayout = reverseLayout;
4782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
4792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mReverseLayout = reverseLayout;
4802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
4812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
4822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
4832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
4842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the current gap handling strategy for StaggeredGridLayoutManager.
4852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
486d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps,
487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and
488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details.
4892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
4902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}.
4912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
4922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Current gap handling strategy.
4932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setGapStrategy(int)
4942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_NONE
4952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
4962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
4972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getGapStrategy() {
4982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mGapStrategy;
4992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter
5032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * is different than the current strategy, calling this method will trigger a layout request.
5042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
505d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @param gapStrategy The new gap handling strategy. Should be
506d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link
507d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     *                    #GAP_HANDLING_NONE}.
5082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #getGapStrategy()
5092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void setGapStrategy(int gapStrategy) {
5110bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
5122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gapStrategy == mGapStrategy) {
5132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return;
5142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5151e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        if (gapStrategy != GAP_HANDLING_NONE
5161e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                && gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
5172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE "
518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS");
5192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mGapStrategy = gapStrategy;
5214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE);
5222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
5232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5250bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    @Override
5260bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void assertNotInLayoutOrScroll(String message) {
5270bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        if (mPendingSavedState == null) {
5280bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            super.assertNotInLayoutOrScroll(message);
5290bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
5300bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
5310bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
5322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns the number of spans laid out by StaggeredGridLayoutManager.
5342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
5352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return Number of spans in the layout
5362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getSpanCount() {
5382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mSpanCount;
5392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items.
5432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
5442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you need to cancel current assignments, you can call this method which will clear all
5452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * assignments and request a new layout.
5462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void invalidateSpanAssignments() {
5482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLazySpanLookup.clear();
5492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
5502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Calculates the views' layout order. (e.g. from end to start or start to end)
5542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * RTL layout support is applied automatically. So if layout is RTL and
5552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
5562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void resolveShouldLayoutReverse() {
5582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // A == B is the same result, but we rather keep it readable
5592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mOrientation == VERTICAL || !isLayoutRTL()) {
5602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = mReverseLayout;
5612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
5622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mShouldReverseLayout = !mReverseLayout;
5632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
5642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean isLayoutRTL() {
5672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
5682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
5702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
5712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Returns whether views are laid out in reverse order or not.
5722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
5732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Not that this value is not affected by RecyclerView's layout direction.
5742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
5752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @return True if layout is reversed, false otherwise
5762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
5772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
5782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean getReverseLayout() {
5792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mReverseLayout;
5802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
5814143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
5824143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    @Override
5834143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
5844143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        // we don't like it to wrap content in our non-scroll direction.
5854143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        final int width, height;
5866b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        final int horizontalPadding = getPaddingLeft() + getPaddingRight();
5876b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar        final int verticalPadding = getPaddingTop() + getPaddingBottom();
5884143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mOrientation == VERTICAL) {
5896b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            final int usedHeight = childrenBounds.height() + verticalPadding;
5904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            height = chooseSize(hSpec, usedHeight, getMinimumHeight());
5916b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            width = chooseSize(wSpec, mSizePerSpan * mSpanCount + horizontalPadding,
5926b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar                    getMinimumWidth());
5934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        } else {
5946b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            final int usedWidth = childrenBounds.width() + horizontalPadding;
5954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            width = chooseSize(wSpec, usedWidth, getMinimumWidth());
5966b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar            height = chooseSize(hSpec, mSizePerSpan * mSpanCount + verticalPadding,
5976b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar                    getMinimumHeight());
5984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
5994143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        setMeasuredDimension(width, height);
6004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
6014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
6032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
6044143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        onLayoutChildren(recycler, state, true);
6054143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
6064143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    private void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state,
6094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            boolean shouldCheckForGaps) {
610d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final AnchorInfo anchorInfo = mAnchorInfo;
6113d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev        if (mPendingSavedState != null || mPendingScrollPosition != NO_POSITION) {
6123d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev            if (state.getItemCount() == 0) {
6133d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev                removeAndRecycleAllViews(recycler);
6149aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar                anchorInfo.reset();
6153d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev                return;
6163d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev            }
6173d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev        }
6183d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev
6191e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        boolean recalculateAnchor = !anchorInfo.mValid || mPendingScrollPosition != NO_POSITION
6201e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || mPendingSavedState != null;
62187b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        if (recalculateAnchor) {
6229aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            anchorInfo.reset();
6239aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            if (mPendingSavedState != null) {
6249aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar                applyPendingSavedState(anchorInfo);
6259aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            } else {
6269aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar                resolveShouldLayoutReverse();
6279aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar                anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
6289aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            }
6299aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            updateAnchorInfoForLayout(state, anchorInfo);
6309aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            anchorInfo.mValid = true;
6319aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        }
6328cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        if (mPendingSavedState == null && mPendingScrollPosition == NO_POSITION) {
6331e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd
6341e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    || isLayoutRTL() != mLastLayoutRTL) {
635d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.clear();
636d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
637d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
6382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
639d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
6401e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        if (getChildCount() > 0 && (mPendingSavedState == null
6411e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || mPendingSavedState.mSpanOffsetsSize < 1)) {
642d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (anchorInfo.mInvalidateOffsets) {
6432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
6442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    // Scroll to position is set, clear.
6452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mSpans[i].clear();
646d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mOffset != INVALID_OFFSET) {
647d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mSpans[i].setLine(anchorInfo.mOffset);
6482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
6492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
6502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
65187b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                if (recalculateAnchor || mAnchorInfo.mSpanReferenceLines == null) {
65287b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                    for (int i = 0; i < mSpanCount; i++) {
65387b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                        mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout,
65487b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                                anchorInfo.mOffset);
65587b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                    }
65687b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                    mAnchorInfo.saveSpanReferenceLines(mSpans);
65787b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                } else {
65887b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                    for (int i = 0; i < mSpanCount; i++) {
65987b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                        final Span span = mSpans[i];
66087b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                        span.clear();
66187b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                        span.setLine(mAnchorInfo.mSpanReferenceLines[i]);
66287b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                    }
6632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
6642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        detachAndScrapAttachedViews(recycler);
6674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLayoutState.mRecycle = false;
668d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLaidOutInvalidFullSpan = false;
6694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        updateMeasureSpecs(mSecondaryOrientation.getTotalSpace());
670e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        updateLayoutState(anchorInfo.mPosition, state);
671d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (anchorInfo.mLayoutFromEnd) {
672d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
673e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            setLayoutStateDirection(LAYOUT_START);
674d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
675d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
676e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            setLayoutStateDirection(LAYOUT_END);
677e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection;
678d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
679d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
680d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout end.
681e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            setLayoutStateDirection(LAYOUT_END);
682d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
683d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // Layout start.
684e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            setLayoutStateDirection(LAYOUT_START);
685e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection;
686d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fill(recycler, mLayoutState, state);
6872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
6882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
6894143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        repositionToWrapContentIfNecessary();
6904143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
6912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
6922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mShouldReverseLayout) {
6932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, true);
6942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, false);
6952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
6962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixStartGap(recycler, state, true);
6972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                fixEndGap(recycler, state, false);
6982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
6992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
7004143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        boolean hasGaps = false;
7014143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (shouldCheckForGaps && !state.isPreLayout()) {
702ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE
703ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar                    && getChildCount() > 0
704ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar                    && (mLaidOutInvalidFullSpan || hasGapsToFix() != null);
705ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar            if (needToCheckForGaps) {
706ec60a348ce39889a99f7ca02da94a6867bfdf66fYigit Boyar                removeCallbacks(mCheckForGapsRunnable);
7074143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                if (checkForGaps()) {
7084143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    hasGaps = true;
7094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                }
710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
7116e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        }
7129aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        if (state.isPreLayout()) {
7139aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.reset();
7149aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        }
715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd;
716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = isLayoutRTL();
7174143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (hasGaps) {
7189aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.reset();
7194143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            onLayoutChildren(recycler, state, false);
7204143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7214143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
7224143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
7238cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    @Override
7248cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    public void onLayoutCompleted(RecyclerView.State state) {
7258cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        super.onLayoutCompleted(state);
7268cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        mPendingScrollPosition = NO_POSITION;
7278cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
7288cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        mPendingSavedState = null; // we don't need this anymore
7299aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        mAnchorInfo.reset();
7308cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    }
7318cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar
7324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    private void repositionToWrapContentIfNecessary() {
7334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mSecondaryOrientation.getMode() == View.MeasureSpec.EXACTLY) {
7344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return; // nothing to do
7354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        float maxSize = 0;
7374143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        final int childCount = getChildCount();
7381e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        for (int i = 0; i < childCount; i++) {
7394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            View child = getChildAt(i);
7404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            float size = mSecondaryOrientation.getDecoratedMeasurement(child);
7414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (size < maxSize) {
7424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                continue;
7434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
7444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
7454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (layoutParams.isFullSpan()) {
7464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                size = 1f * size / mSpanCount;
7474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
7484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            maxSize = Math.max(maxSize, size);
7494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int before = mSizePerSpan;
7514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        int desired = Math.round(maxSize * mSpanCount);
7524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mSecondaryOrientation.getMode() == View.MeasureSpec.AT_MOST) {
7534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            desired = Math.min(desired, mSecondaryOrientation.getTotalSpace());
7544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7554143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        updateMeasureSpecs(desired);
7564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mSizePerSpan == before) {
7574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return; // nothing has changed
7584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7591e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        for (int i = 0; i < childCount; i++) {
7604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            View child = getChildAt(i);
7614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
7624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (lp.mFullSpan) {
7634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                continue;
7644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
7654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (isLayoutRTL() && mOrientation == VERTICAL) {
7664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int newOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * mSizePerSpan;
7674143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int prevOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * before;
7684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                child.offsetLeftAndRight(newOffset - prevOffset);
7694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else {
7704143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int newOffset = lp.mSpan.mIndex * mSizePerSpan;
7714143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                int prevOffset = lp.mSpan.mIndex * before;
7724143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                if (mOrientation == VERTICAL) {
7734143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    child.offsetLeftAndRight(newOffset - prevOffset);
7744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                } else {
7754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    child.offsetTopAndBottom(newOffset - prevOffset);
7764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                }
7774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
7784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
7792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
7802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
781d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void applyPendingSavedState(AnchorInfo anchorInfo) {
782d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
783d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "found saved state: " + mPendingSavedState);
7842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
785d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanOffsetsSize > 0) {
786d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) {
787d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = 0; i < mSpanCount; i++) {
788d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].clear();
789d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    int line = mPendingSavedState.mSpanOffsets[i];
790d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
791d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        if (mPendingSavedState.mAnchorLayoutFromEnd) {
792d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getEndAfterPadding();
793d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        } else {
794d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            line += mPrimaryOrientation.getStartAfterPadding();
795d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        }
796d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
797d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mSpans[i].setLine(line);
798d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
799d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
800d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.invalidateSpanInfo();
801d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition;
802d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
803d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
804d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL;
805d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        setReverseLayout(mPendingSavedState.mReverseLayout);
806d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        resolveShouldLayoutReverse();
8072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
808d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mAnchorPosition != NO_POSITION) {
809d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
810d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
8112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
812d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
8132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
814d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState.mSpanLookupSize > 1) {
815d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mData = mPendingSavedState.mSpanLookup;
816d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems;
817d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
818d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
819d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
820d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) {
821d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromPendingData(state, anchorInfo)) {
822d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
823d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
824d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (updateAnchorFromChildren(state, anchorInfo)) {
825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
826d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
827d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (DEBUG) {
828d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Log.d(TAG, "Deciding anchor info from fresh state");
829d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
830d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.assignCoordinateFromPadding();
831d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = 0;
832d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
833d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
834d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) {
835d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // We don't recycle views out of adapter order. This way, we can rely on the first or
836d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // last child as the anchor position.
837d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Layout direction may change but we should select the child depending on the latest
838d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // layout direction. Otherwise, we'll choose the wrong child.
839d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mPosition = mLastLayoutFromEnd
840d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? findLastReferenceChildPosition(state.getItemCount())
841d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : findFirstReferenceChildPosition(state.getItemCount());
842d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        anchorInfo.mOffset = INVALID_OFFSET;
843d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
844d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
845d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
846d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) {
847d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate scroll position if exists.
848d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) {
849d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
850d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
851d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // Validate it.
852d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
853d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPosition = NO_POSITION;
854d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
855d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return false;
856d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
857d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
858d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION
859d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                || mPendingSavedState.mSpanOffsetsSize < 1) {
860d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // If item is visible, make it fully visible.
861d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = findViewByPosition(mPendingScrollPosition);
862d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (child != null) {
863d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Use regular anchor position, offset according to pending offset and target
864d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child
865d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition()
866d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : getFirstChildPosition();
867d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset != INVALID_OFFSET) {
868d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (anchorInfo.mLayoutFromEnd) {
8691e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        final int target = mPrimaryOrientation.getEndAfterPadding()
8701e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                                - mPendingScrollPositionOffset;
871d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child);
872d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
8731e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        final int target = mPrimaryOrientation.getStartAfterPadding()
8741e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                                + mPendingScrollPositionOffset;
875d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child);
876d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
877d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
878d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
879d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
880d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // no offset provided. Decide according to the child location
881d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child);
882d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (childSize > mPrimaryOrientation.getTotalSpace()) {
883d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    // Item does not fit. Fix depending on layout direction.
884d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = anchorInfo.mLayoutFromEnd
885d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            ? mPrimaryOrientation.getEndAfterPadding()
886d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            : mPrimaryOrientation.getStartAfterPadding();
887d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
888d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
889d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
890d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final int startGap = mPrimaryOrientation.getDecoratedStart(child)
891d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        - mPrimaryOrientation.getStartAfterPadding();
892d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (startGap < 0) {
893d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = -startGap;
894d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
895d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
8961e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                final int endGap = mPrimaryOrientation.getEndAfterPadding()
8971e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        - mPrimaryOrientation.getDecoratedEnd(child);
898d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (endGap < 0) {
899d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mOffset = endGap;
900d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return true;
9012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
902d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child already visible. just layout as usual
903d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mOffset = INVALID_OFFSET;
904d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
905d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // Child is not visible. Set anchor coordinate depending on in which direction
906d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // child will be visible.
907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mPosition = mPendingScrollPosition;
908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mPendingScrollPositionOffset == INVALID_OFFSET) {
909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    final int position = calculateScrollDirectionForPosition(
910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                            anchorInfo.mPosition);
911d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.mLayoutFromEnd = position == LAYOUT_END;
912d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding();
913d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset);
915d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                anchorInfo.mInvalidateOffsets = true;
9172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
918d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
919d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mOffset = INVALID_OFFSET;
920d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            anchorInfo.mPosition = mPendingScrollPosition;
921d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
922d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return true;
923d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
924d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
9254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    void updateMeasureSpecs(int totalSpace) {
9264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mSizePerSpan = totalSpace / mSpanCount;
9274143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        //noinspection ResourceType
928d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mFullSizeSpec = View.MeasureSpec.makeMeasureSpec(
9294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                totalSpace, mSecondaryOrientation.getMode());
9302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
9322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
9332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean supportsPredictiveItemAnimations() {
9346e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        return mPendingSavedState == null;
9352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
9362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
937333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
938333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first visible view for each span.
939333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
940333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
941333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
942333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
943333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
944333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
945333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
946333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
947333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
948333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
949333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
950333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first visible item in each span. If a span does not have
952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
953333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
954333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
955333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
956333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstVisibleItemPositions(int[] into) {
957333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
958333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
959333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
960333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
961333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
962333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
964333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstVisibleItemPosition();
965333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
966333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
967333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
968333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
969333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
970333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the first completely visible view for each span.
971333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
972333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
973333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
974333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
975333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
976333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
977333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
978333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
979333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
980333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
981333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
982333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
983d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the first fully visible item in each span. If a span does
984d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
985333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
986333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
987333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
988333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findFirstCompletelyVisibleItemPositions(int[] into) {
989333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
990333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
991333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
992333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
993333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
994333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
996333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition();
997333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
998333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
999333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1000333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1001333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
1002333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last visible view for each span.
1003333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1004333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
1005333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
1006333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
1007333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1008333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
1009333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1010333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
1011333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
1012333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
1013333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
1014333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
1015d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last visible item in each span. If a span does not have
1016d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * any items, {@link RecyclerView#NO_POSITION} is returned for that span.
1017333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastCompletelyVisibleItemPositions(int[])
1018333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstVisibleItemPositions(int[])
1019333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
1020333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastVisibleItemPositions(int[] into) {
1021333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
1022333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
1023333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
1024333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
1025333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
1026333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1027d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1028333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastVisibleItemPosition();
1029333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1030333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
1031333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1032333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1033333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
1034333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Returns the adapter position of the last completely visible view for each span.
1035333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1036333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
1037333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
1038333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * not in the layout.
1039333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1040333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
1041333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * <p>
1042333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those
1043333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * views are ignored in this method.
1044333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *
1045333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @param into An array to put the results into. If you don't provide any, LayoutManager will
1046333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     *             create a new one.
1047d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return The adapter position of the last fully visible item in each span. If a span does not
1048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * have any items, {@link RecyclerView#NO_POSITION} is returned for that span.
1049333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findFirstCompletelyVisibleItemPositions(int[])
1050333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * @see #findLastVisibleItemPositions(int[])
1051333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
1052333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    public int[] findLastCompletelyVisibleItemPositions(int[] into) {
1053333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        if (into == null) {
1054333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into = new int[mSpanCount];
1055333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        } else if (into.length < mSpanCount) {
1056333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
1057333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
1058333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1059d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1060333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            into[i] = mSpans[i].findLastCompletelyVisibleItemPosition();
1061333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
1062333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        return into;
1063333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1064333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
1065d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1066d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollOffset(RecyclerView.State state) {
1067d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollOffset(state);
1068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1069d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1070d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollOffset(RecyclerView.State state) {
1071d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
1072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
1073d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1074d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation,
1075e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
1076e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
1077d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled, mShouldReverseLayout);
1078d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1079d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1080d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1081d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollOffset(RecyclerView.State state) {
1082d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollOffset(state);
1083d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1084d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1085d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1086d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollExtent(RecyclerView.State state) {
1087d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollExtent(state);
1088d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1089d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1090d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollExtent(RecyclerView.State state) {
1091d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
1092d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
1093d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1094d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation,
1095e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
1096e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
1097d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
1098d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1099d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1100d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1101d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollExtent(RecyclerView.State state) {
1102d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollExtent(state);
1103d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1104d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1105d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1106d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeHorizontalScrollRange(RecyclerView.State state) {
1107d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
1108d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1109d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1110d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private int computeScrollRange(RecyclerView.State state) {
1111d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
1112d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
1113d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1114d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation,
1115e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled),
1116e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled),
1117d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                this, mSmoothScrollbarEnabled);
1118d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1119d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1120d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1121d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public int computeVerticalScrollRange(RecyclerView.State state) {
1122d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return computeScrollRange(state);
1123d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1124d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
11254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp,
11264143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            boolean alreadyMeasured) {
1127d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (lp.mFullSpan) {
1128d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mOrientation == VERTICAL) {
112942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child, mFullSizeSpec,
11304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
11314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        alreadyMeasured);
1132d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
113342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child,
11344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true),
11354143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        mFullSizeSpec, alreadyMeasured);
1136d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1137d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
113842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            if (mOrientation == VERTICAL) {
11394143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                measureChildWithDecorationsAndMargin(child,
11404143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(mSizePerSpan, getWidthMode(), 0, lp.width, false),
11414143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true),
11424143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        alreadyMeasured);
114342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            } else {
114442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                measureChildWithDecorationsAndMargin(child,
11454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true),
11464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        getChildMeasureSpec(mSizePerSpan, getHeightMode(), 0, lp.height, false),
11474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        alreadyMeasured);
114842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar            }
114942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        }
115042e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar    }
115142e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar
11522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void measureChildWithDecorationsAndMargin(View child, int widthSpec,
11534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            int heightSpec, boolean alreadyMeasured) {
1154c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar        calculateItemDecorationsForChild(child, mTmpRect);
11552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams lp = (LayoutParams) child.getLayoutParams();
1156c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar        widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mTmpRect.left,
1157c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar                lp.rightMargin + mTmpRect.right);
1158c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar        heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mTmpRect.top,
1159c67491396ca2989bd162bd2b243c45071e4b2e6eYigit Boyar                lp.bottomMargin + mTmpRect.bottom);
11604143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        final boolean measure = alreadyMeasured
11614143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                ? shouldReMeasureChild(child, widthSpec, heightSpec, lp)
11624143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                : shouldMeasureChild(child, widthSpec, heightSpec, lp);
11634143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (measure) {
11644143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            child.measure(widthSpec, heightSpec);
11654143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
11664143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
11672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int updateSpecWithExtra(int spec, int startInset, int endInset) {
11702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (startInset == 0 && endInset == 0) {
11712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return spec;
11722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mode = View.MeasureSpec.getMode(spec);
11742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) {
11752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return View.MeasureSpec.makeMeasureSpec(
1176121ba9616e5bed44d2490f1744f7b6a9d3e79866Yigit Boyar                    Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode);
11772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return spec;
11792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
11822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onRestoreInstanceState(Parcelable state) {
11832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (state instanceof SavedState) {
11842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState = (SavedState) state;
11852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
11862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (DEBUG) {
11872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "invalid saved state class");
11882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
11902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
11912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
11922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public Parcelable onSaveInstanceState() {
11932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
11942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new SavedState(mPendingSavedState);
11952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
11962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState state = new SavedState();
11972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mReverseLayout = mReverseLayout;
11982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        state.mAnchorLayoutFromEnd = mLastLayoutFromEnd;
1199d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        state.mLastLayoutRTL = mLastLayoutRTL;
12002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLazySpanLookup != null && mLazySpanLookup.mData != null) {
12022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookup = mLazySpanLookup.mData;
12032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = state.mSpanLookup.length;
1204d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mFullSpanItems = mLazySpanLookup.mFullSpanItems;
12052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
12062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanLookupSize = 0;
12072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
12092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() > 0) {
12102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition()
12112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    : getFirstChildPosition();
1212333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt();
1213b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = mSpanCount;
12142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            state.mSpanOffsets = new int[mSpanCount];
12152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            for (int i = 0; i < mSpanCount; i++) {
1216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int line;
1217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mLastLayoutFromEnd) {
1218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getEndLine(Span.INVALID_LINE);
1219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getEndAfterPadding();
1221d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1222d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
1223d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    line = mSpans[i].getStartLine(Span.INVALID_LINE);
1224d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (line != Span.INVALID_LINE) {
1225d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        line -= mPrimaryOrientation.getStartAfterPadding();
1226d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
1227d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
1228d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                state.mSpanOffsets[i] = line;
12292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
12302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mAnchorPosition = NO_POSITION;
1232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            state.mVisibleAnchorPosition = NO_POSITION;
1233b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            state.mSpanOffsetsSize = 0;
12342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
12362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "saved state:\n" + state);
12372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
12382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return state;
12392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
12402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1241a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1242a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
1243a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
1244a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        ViewGroup.LayoutParams lp = host.getLayoutParams();
1245a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (!(lp instanceof LayoutParams)) {
1246a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            super.onInitializeAccessibilityNodeInfoForItem(host, info);
1247a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return;
1248a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1249a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        LayoutParams sglp = (LayoutParams) lp;
1250a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1251a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1252a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1253a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1254a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1255a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        } else { // VERTICAL
1256a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
1257a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    -1, -1,
1258a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1,
1259a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                    sglp.mFullSpan, false));
1260a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1261a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1262a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1263a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1264a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1265a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        super.onInitializeAccessibilityEvent(event);
1266a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (getChildCount() > 0) {
1267e5874e666791a58d21eed482fb90e917445da873Chris Craik            final View start = findFirstVisibleItemClosestToStart(false);
1268e5874e666791a58d21eed482fb90e917445da873Chris Craik            final View end = findFirstVisibleItemClosestToEnd(false);
1269a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (start == null || end == null) {
1270a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar                return;
1271a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1272a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int startPos = getPosition(start);
1273a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            final int endPos = getPosition(end);
1274a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            if (startPos < endPos) {
127514d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas                event.setFromIndex(startPos);
127614d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas                event.setToIndex(endPos);
1277a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            } else {
127814d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas                event.setFromIndex(endPos);
127914d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas                event.setToIndex(startPos);
1280a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            }
1281a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1282a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1283a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1284333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    /**
1285333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     * Finds the first fully visible child to be used as an anchor child if span count changes when
12866490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * state is restored. If no children is fully visible, returns a partially visible child instead
12876490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * of returning null.
1288333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar     */
1289333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    int findFirstVisibleItemPositionInt() {
1290e5874e666791a58d21eed482fb90e917445da873Chris Craik        final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true) :
1291e5874e666791a58d21eed482fb90e917445da873Chris Craik                findFirstVisibleItemClosestToStart(true);
1292d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return first == null ? NO_POSITION : getPosition(first);
1293d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1294d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1295a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1296a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
1297a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1298a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == HORIZONTAL) {
1299a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1300a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1301a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getRowCountForAccessibility(recycler, state);
1302a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1303a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1304a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
1305a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
1306a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            RecyclerView.State state) {
1307a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (mOrientation == VERTICAL) {
1308a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar            return mSpanCount;
1309a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
1310a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        return super.getColumnCountForAccessibility(recycler, state);
1311a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
1312a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
1313006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar    /**
1314006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * This is for internal use. Not necessarily the child closest to start but the first child
1315006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * we find that matches the criteria.
1316006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * This method does not do any sorting based on child's start coordinate, instead, it uses
1317006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * children order.
1318006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     */
1319e5874e666791a58d21eed482fb90e917445da873Chris Craik    View findFirstVisibleItemClosestToStart(boolean fullyVisible) {
1320333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1321333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
1322d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int limit = getChildCount();
13236490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        View partiallyVisible = null;
132442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        for (int i = 0; i < limit; i++) {
1325333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final View child = getChildAt(i);
1326006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            final int childStart = mPrimaryOrientation.getDecoratedStart(child);
1327006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
13281e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if (childEnd <= boundsStart || childStart >= boundsEnd) {
1329006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                continue; // not visible at all
1330006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            }
1331006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            if (childStart >= boundsStart || !fullyVisible) {
1332006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                // when checking for start, it is enough even if part of the child's top is visible
1333006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                // as long as fully visible is not requested.
1334006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                return child;
1335006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            }
1336e5874e666791a58d21eed482fb90e917445da873Chris Craik            if (partiallyVisible == null) {
1337006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                partiallyVisible = child;
1338d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1339d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
13406490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        return partiallyVisible;
1341d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1342d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1343006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar    /**
1344006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * This is for internal use. Not necessarily the child closest to bottom but the first child
1345006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * we find that matches the criteria.
1346006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * This method does not do any sorting based on child's end coordinate, instead, it uses
1347006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     * children order.
1348006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar     */
1349e5874e666791a58d21eed482fb90e917445da873Chris Craik    View findFirstVisibleItemClosestToEnd(boolean fullyVisible) {
1350d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
1351d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
13526490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        View partiallyVisible = null;
135342e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
1354d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View child = getChildAt(i);
1355006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            final int childStart = mPrimaryOrientation.getDecoratedStart(child);
1356006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
13571e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if (childEnd <= boundsStart || childStart >= boundsEnd) {
1358006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                continue; // not visible at all
1359006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            }
1360006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            if (childEnd <= boundsEnd || !fullyVisible) {
1361006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                // when checking for end, it is enough even if part of the child's bottom is visible
1362006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                // as long as fully visible is not requested.
1363006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                return child;
1364006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar            }
1365e5874e666791a58d21eed482fb90e917445da873Chris Craik            if (partiallyVisible == null) {
1366006eb2ce2077b3374d2e16d44b726552a5e88bf6Yigit Boyar                partiallyVisible = child;
1367333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
1368333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
13696490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        return partiallyVisible;
1370333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar    }
1371333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
13722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state,
13732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
13744143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        final int maxEndLine = getMaxEnd(Integer.MIN_VALUE);
13754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (maxEndLine == Integer.MIN_VALUE) {
13764143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return;
13774143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
13782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine;
13792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
13802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
13812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = -scrollBy(-gap, recycler, state);
13822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
13832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
13842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
13862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
13872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(gap);
13882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
13892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
13902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
13912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state,
13922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            boolean canOffsetChildren) {
13934143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        final int minStartLine = getMinStart(Integer.MAX_VALUE);
13944143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (minStartLine == Integer.MAX_VALUE) {
13954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return;
13964143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
13972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding();
13982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int fixOffset;
13992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (gap > 0) {
14002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            fixOffset = scrollBy(gap, recycler, state);
14012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
14022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return; // nothing to fix
14032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        gap -= fixOffset;
14052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (canOffsetChildren && gap > 0) {
14062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPrimaryOrientation.offsetChildren(-gap);
14072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1410e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar    private void updateLayoutState(int anchorPosition, RecyclerView.State state) {
14112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mAvailable = 0;
14122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = anchorPosition;
1413e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        int startExtra = 0;
1414e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        int endExtra = 0;
14152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (isSmoothScrolling()) {
14162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int targetPos = state.getTargetScrollPosition();
1417e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            if (targetPos != NO_POSITION) {
1418e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                if (mShouldReverseLayout == targetPos < anchorPosition) {
1419e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    endExtra = mPrimaryOrientation.getTotalSpace();
1420e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                } else {
1421e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    startExtra = mPrimaryOrientation.getTotalSpace();
1422e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                }
14232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
14242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1426e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        // Line of the furthest row.
1427e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        final boolean clipToPadding = getClipToPadding();
1428e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        if (clipToPadding) {
1429e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mStartLine = mPrimaryOrientation.getStartAfterPadding() - startExtra;
1430e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mEndLine = mPrimaryOrientation.getEndAfterPadding() + endExtra;
14312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1432e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mEndLine = mPrimaryOrientation.getEnd() + endExtra;
1433e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            mLayoutState.mStartLine = -startExtra;
14342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1435f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        mLayoutState.mStopInFocusable = false;
14364143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLayoutState.mRecycle = true;
14371e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED
14381e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                && mPrimaryOrientation.getEnd() == 0;
1439e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar    }
1440e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar
1441e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar    private void setLayoutStateDirection(int direction) {
1442e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        mLayoutState.mLayoutDirection = direction;
14431e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        mLayoutState.mItemDirection = (mShouldReverseLayout == (direction == LAYOUT_START))
14441e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                ? ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD;
14452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
14482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenHorizontal(int dx) {
14492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenHorizontal(dx);
14502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
14512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dx);
14522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
14562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void offsetChildrenVertical(int dy) {
14572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        super.offsetChildrenVertical(dy);
14582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
14592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpans[i].onOffset(dy);
14602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
14612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
14642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
1465d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE);
14662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
14692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
1470d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD);
1471d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1472d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1473d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1474d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsChanged(RecyclerView recyclerView) {
1475d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mLazySpanLookup.clear();
1476d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        requestLayout();
1477d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1478d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1479d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
1480d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
1481d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE);
1482d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1483d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1484d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    @Override
148521b345f101abc385496f42d250e580d21f1287b6Dake Gu    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount,
148621b345f101abc385496f42d250e580d21f1287b6Dake Gu            Object payload) {
1487d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE);
14882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
14892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
14902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
14912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Checks whether it should invalidate span assignments in response to an adapter change.
14922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
1493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) {
14942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition();
14951e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        final int affectedRangeEnd; // exclusive
14961e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        final int affectedRangeStart; // inclusive
1497f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1498f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (cmd == AdapterHelper.UpdateOp.MOVE) {
1499f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (positionStart < itemCountOrToPosition) {
1500f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeEnd = itemCountOrToPosition + 1;
1501f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeStart = positionStart;
1502f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            } else {
1503f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeEnd = positionStart + 1;
1504f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                affectedRangeStart = itemCountOrToPosition;
1505f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1506f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        } else {
1507f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            affectedRangeStart = positionStart;
1508f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            affectedRangeEnd = positionStart + itemCountOrToPosition;
1509f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1510f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1511f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        mLazySpanLookup.invalidateAfter(affectedRangeStart);
1512d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        switch (cmd) {
1513d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.ADD:
1514d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition);
1515d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1516d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.REMOVE:
1517d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition);
1518d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1519d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            case AdapterHelper.UpdateOp.MOVE:
1520d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // TODO optimize
1521d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForRemoval(positionStart, 1);
1522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1);
1523d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                break;
1524d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1525d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1526f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (affectedRangeEnd <= minPosition) {
1527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return;
15282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1529f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
15302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition();
1531f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        if (affectedRangeStart <= maxPosition) {
15322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            requestLayout();
15332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
15342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
15352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
15362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
15372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
15382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mRemainingSpans.set(0, mSpanCount, true);
15392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // The target position we are trying to reach.
15402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int targetLine;
1541e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar
15422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Line of the furthest row.
15434143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mLayoutState.mInfinite) {
15444143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
15454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                targetLine = Integer.MAX_VALUE;
15464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else { // LAYOUT_START
15474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                targetLine = Integer.MIN_VALUE;
15484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
15494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        } else {
15504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
15514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                targetLine = layoutState.mEndLine + layoutState.mAvailable;
15524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else { // LAYOUT_START
15534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                targetLine = layoutState.mStartLine - layoutState.mAvailable;
15544143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
15552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1556e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar
1557d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine);
1558e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        if (DEBUG) {
15591e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            Log.d(TAG, "FILLING targetLine: " + targetLine + ","
15601e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + "remaining spans:" + mRemainingSpans + ", state: " + layoutState);
1561e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        }
15622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1563d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // the default coordinate to add new view.
1564d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int defaultNewViewLine = mShouldReverseLayout
1565d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                ? mPrimaryOrientation.getEndAfterPadding()
1566d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                : mPrimaryOrientation.getStartAfterPadding();
1567e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        boolean added = false;
15684143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        while (layoutState.hasMore(state)
15694143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                && (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) {
15702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View view = layoutState.next(recycler);
15712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = ((LayoutParams) view.getLayoutParams());
1572115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            final int position = lp.getViewLayoutPosition();
15732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanIndex = mLazySpanLookup.getSpan(position);
15742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Span currentSpan;
1575f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID;
1576d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (assignSpan) {
1577d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState);
15782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mLazySpanLookup.setSpan(position, currentSpan);
1579d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1580d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position);
1581d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
15822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1583d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (DEBUG) {
1584d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    Log.d(TAG, "using " + spanIndex + " for pos " + position);
1585d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
15862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                currentSpan = mSpans[spanIndex];
15872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1588ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            // assign span before measuring so that item decorators can get updated span index
1589ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            lp.mSpan = currentSpan;
1590ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
1591ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar                addView(view);
1592ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            } else {
1593ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar                addView(view, 0);
1594ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar            }
15954143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            measureChildWithDecorationsAndMargin(view, lp, false);
1596ca9ce7ccdccf6b6a2a81da73dd1e6425d90e4b23Yigit Boyar
15972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int start;
15982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int end;
15992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_END) {
1600d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine)
1601d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getEndLine(defaultNewViewLine);
16022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                end = start + mPrimaryOrientation.getDecoratedMeasurement(view);
1603d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1604d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1605d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromEnd(start);
1606d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_START;
1607d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1608d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
16092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
1611d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                end = lp.mFullSpan ? getMinStart(defaultNewViewLine)
1612d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        : currentSpan.getStartLine(defaultNewViewLine);
16132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                start = end - mPrimaryOrientation.getDecoratedMeasurement(view);
1614d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (assignSpan && lp.mFullSpan) {
1615d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem fullSpanItem;
1616d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem = createFullSpanItemFromStart(end);
1617d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mGapDir = LAYOUT_END;
1618d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fullSpanItem.mPosition = position;
1619d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mLazySpanLookup.addFullSpanItem(fullSpanItem);
16202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
16212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
16222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1623d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // check if this item may create gaps in the future
1624f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD) {
1625f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                if (assignSpan) {
1626f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    mLaidOutInvalidFullSpan = true;
1627f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                } else {
1628f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    final boolean hasInvalidGap;
1629f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    if (layoutState.mLayoutDirection == LAYOUT_END) {
1630f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        hasInvalidGap = !areAllEndsEqual();
1631f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    } else { // layoutState.mLayoutDirection == LAYOUT_START
1632f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        hasInvalidGap = !areAllStartsEqual();
1633f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    }
1634f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    if (hasInvalidGap) {
1635f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup
1636f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                                .getFullSpanItem(position);
1637f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        if (fullSpanItem != null) {
1638f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                            fullSpanItem.mHasUnwantedGapAfter = true;
1639f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        }
1640f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                        mLaidOutInvalidFullSpan = true;
1641f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                    }
1642f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                }
16432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1644d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            attachViewToSpans(view, lp, layoutState);
16454143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final int otherStart;
16464143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            final int otherEnd;
16474143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            if (isLayoutRTL() && mOrientation == VERTICAL) {
16484143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                otherEnd = lp.mFullSpan ? mSecondaryOrientation.getEndAfterPadding() :
16494143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                        mSecondaryOrientation.getEndAfterPadding()
16504143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                                - (mSpanCount - 1 - currentSpan.mIndex) * mSizePerSpan;
16514143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view);
16524143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            } else {
16534143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding()
16541e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        : currentSpan.mIndex * mSizePerSpan
16551e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                                + mSecondaryOrientation.getStartAfterPadding();
16564143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view);
16574143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            }
16584143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
16592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mOrientation == VERTICAL) {
16602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end);
16612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
16622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd);
16632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1664d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
16652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (lp.mFullSpan) {
1666d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine);
16672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
16682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine);
16692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
1670e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            recycle(recycler, mLayoutState);
1671b174744db6a70f384d44caeb43e10854652e81b9Keyvan Amiri            if (mLayoutState.mStopInFocusable && view.hasFocusable()) {
1672f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                if (lp.mFullSpan) {
1673f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    mRemainingSpans.clear();
1674f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                } else {
1675f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    mRemainingSpans.set(currentSpan.mIndex, false);
1676f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
1677f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            }
1678e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            added = true;
16792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1680e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        if (!added) {
1681e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            recycle(recycler, mLayoutState);
16822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1683e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        final int diff;
16842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mLayoutState.mLayoutDirection == LAYOUT_START) {
16852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding());
1686e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            diff = mPrimaryOrientation.getStartAfterPadding() - minStart;
16872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1688e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            final int maxEnd = getMaxEnd(mPrimaryOrientation.getEndAfterPadding());
1689e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            diff = maxEnd - mPrimaryOrientation.getEndAfterPadding();
16902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
1691e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        return diff > 0 ? Math.min(layoutState.mAvailable, diff) : 0;
16922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
16932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1694d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) {
1695d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1696d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1697d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1698d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop);
1699d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1700d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1701d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1702d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1703d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) {
1704d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem();
1705d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        fsi.mGapPerSpan = new int[mSpanCount];
1706d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1707d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom;
1708d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1709d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return fsi;
1710d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1711d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1712d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) {
1713d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) {
1714d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1715d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                appendViewToAllSpans(view);
1716d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1717d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.appendToSpan(view);
1718d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1719d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1720d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
1721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                prependViewToAllSpans(view);
1722d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
1723d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                lp.mSpan.prependToSpan(view);
1724d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1725d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1726d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1727d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1728e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar    private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState) {
17294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (!layoutState.mRecycle || layoutState.mInfinite) {
1730f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            return;
1731f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
1732e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        if (layoutState.mAvailable == 0) {
1733e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            // easy, recycle line is still valid
1734e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_START) {
1735e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                recycleFromEnd(recycler, layoutState.mEndLine);
1736e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            } else {
1737e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                recycleFromStart(recycler, layoutState.mStartLine);
1738e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            }
1739d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1740e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            // scrolling case, recycle line can be shifted by how much space we could cover
1741e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            // by adding new views
1742e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            if (layoutState.mLayoutDirection == LAYOUT_START) {
1743e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                // calculate recycle line
1744e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                int scrolled = layoutState.mStartLine - getMaxStart(layoutState.mStartLine);
1745e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                final int line;
1746e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                if (scrolled < 0) {
1747e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    line = layoutState.mEndLine;
1748e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                } else {
1749e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    line = layoutState.mEndLine - Math.min(scrolled, layoutState.mAvailable);
1750e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                }
1751e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                recycleFromEnd(recycler, line);
1752e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            } else {
1753e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                // calculate recycle line
1754e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                int scrolled = getMinEnd(layoutState.mEndLine) - layoutState.mEndLine;
1755e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                final int line;
1756e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                if (scrolled < 0) {
1757e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    line = layoutState.mStartLine;
1758e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                } else {
1759e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    line = layoutState.mStartLine + Math.min(scrolled, layoutState.mAvailable);
1760e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                }
1761e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                recycleFromStart(recycler, line);
1762e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            }
1763d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1764e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar
1765d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1766d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1767d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void appendViewToAllSpans(View view) {
1768d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1769d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1770d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].appendToSpan(view);
1771d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1772d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1773d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1774d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void prependViewToAllSpans(View view) {
1775d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        // traverse in reverse so that we end up assigning full span items to 0
1776d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = mSpanCount - 1; i >= 0; i--) {
1777d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mSpans[i].prependToSpan(view);
1778d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1779d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1780d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1781d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private void updateAllRemainingSpans(int layoutDir, int targetLine) {
1782d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        for (int i = 0; i < mSpanCount; i++) {
1783d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mSpans[i].mViews.isEmpty()) {
1784d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                continue;
1785d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
1786d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            updateRemainingSpans(mSpans[i], layoutDir, targetLine);
1787d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1788d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1789d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
17902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void updateRemainingSpans(Span span, int layoutDir, int targetLine) {
17912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int deletedSize = span.getDeletedSize();
17922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutDir == LAYOUT_START) {
17932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getStartLine();
1794e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            if (line + deletedSize <= targetLine) {
17952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
17962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
17972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
17982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int line = span.getEndLine();
1799e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            if (line - deletedSize >= targetLine) {
18002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mRemainingSpans.set(span.mIndex, false);
18012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxStart(int def) {
18062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxStart = mSpans[0].getStartLine(def);
18072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
18082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
18092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart > maxStart) {
18102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxStart = spanStart;
18112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxStart;
18142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinStart(int def) {
18172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minStart = mSpans[0].getStartLine(def);
18182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
18192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanStart = mSpans[i].getStartLine(def);
18202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanStart < minStart) {
18212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minStart = spanStart;
18222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minStart;
18252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
1827f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    boolean areAllEndsEqual() {
1828f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        int end = mSpans[0].getEndLine(Span.INVALID_LINE);
1829f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        for (int i = 1; i < mSpanCount; i++) {
1830f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (mSpans[i].getEndLine(Span.INVALID_LINE) != end) {
1831f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                return false;
1832f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1833f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1834f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        return true;
1835f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    }
1836f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
1837f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    boolean areAllStartsEqual() {
1838f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        int start = mSpans[0].getStartLine(Span.INVALID_LINE);
1839f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        for (int i = 1; i < mSpanCount; i++) {
1840f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            if (mSpans[i].getStartLine(Span.INVALID_LINE) != start) {
1841f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                return false;
1842f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            }
1843f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        }
1844f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        return true;
1845f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar    }
1846f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar
18472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMaxEnd(int def) {
18482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int maxEnd = mSpans[0].getEndLine(def);
18492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
18502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
18512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd > maxEnd) {
18522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                maxEnd = spanEnd;
18532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return maxEnd;
18562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int getMinEnd(int def) {
18592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int minEnd = mSpans[0].getEndLine(def);
18602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (int i = 1; i < mSpanCount; i++) {
18612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int spanEnd = mSpans[i].getEndLine(def);
18622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (spanEnd < minEnd) {
18632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                minEnd = spanEnd;
18642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return minEnd;
18672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromStart(RecyclerView.Recycler recycler, int line) {
18702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        while (getChildCount() > 0) {
18712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(0);
18721e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if (mPrimaryOrientation.getDecoratedEnd(child) <= line
18731e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    && mPrimaryOrientation.getTransformedEndWithDecoration(child) <= line) {
18742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
1875e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                // Don't recycle the last View in a span not to lose span's start/end lines
18762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
18772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
1878e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        if (mSpans[j].mViews.size() == 1) {
1879e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                            return;
1880e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        }
1881e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    }
1882e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
18832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popStart();
18842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
18852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
1886e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    if (lp.mSpan.mViews.size() == 1) {
1887e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        return;
1888e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    }
18892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popStart();
18902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
18912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
18922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
18931e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                return; // done
18942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
18952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
18962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
18972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
18982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private void recycleFromEnd(RecyclerView.Recycler recycler, int line) {
18992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
19002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int i;
19012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        for (i = childCount - 1; i >= 0; i--) {
19022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View child = getChildAt(i);
19031e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if (mPrimaryOrientation.getDecoratedStart(child) >= line
19041e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    && mPrimaryOrientation.getTransformedStartWithDecoration(child) >= line) {
19052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                LayoutParams lp = (LayoutParams) child.getLayoutParams();
1906e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                // Don't recycle the last View in a span not to lose span's start/end lines
19072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                if (lp.mFullSpan) {
19082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
1909e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        if (mSpans[j].mViews.size() == 1) {
1910e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                            return;
1911e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        }
1912e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    }
1913e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    for (int j = 0; j < mSpanCount; j++) {
19142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                        mSpans[j].popEnd();
19152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    }
19162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                } else {
1917e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    if (lp.mSpan.mViews.size() == 1) {
1918e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                        return;
1919e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar                    }
19202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    lp.mSpan.popEnd();
19212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
19222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                removeAndRecycleView(child, recycler);
19232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
19241e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                return; // done
19252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
1930d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * @return True if last span is the first one we want to fill
1931d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
1932d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    private boolean preferLastSpan(int layoutDir) {
1933d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (mOrientation == HORIZONTAL) {
1934d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return (layoutDir == LAYOUT_START) != mShouldReverseLayout;
1935d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
1936d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL();
1937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
1938d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
1939d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
19402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Finds the span for the next view.
19412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
19422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private Span getNextSpan(LayoutState layoutState) {
1943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection);
1944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        final int startIndex, endIndex, diff;
1945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (preferLastSpan) {
1946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = mSpanCount - 1;
1947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = -1;
1948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = -1;
1949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        } else {
1950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            startIndex = 0;
1951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            endIndex = mSpanCount;
1952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            diff = 1;
1953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
19542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (layoutState.mLayoutDirection == LAYOUT_END) {
1955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span min = null;
1956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int minLine = Integer.MAX_VALUE;
19572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getStartAfterPadding();
1958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
19592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getEndLine(defaultLine);
1961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine < minLine) {
19622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    min = other;
19632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    minLine = otherLine;
19642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
19652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return min;
19672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
1968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            Span max = null;
1969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int maxLine = Integer.MIN_VALUE;
19702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int defaultLine = mPrimaryOrientation.getEndAfterPadding();
1971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = startIndex; i != endIndex; i += diff) {
19722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                final Span other = mSpans[i];
1973d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int otherLine = other.getStartLine(defaultLine);
1974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (otherLine > maxLine) {
19752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    max = other;
19762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    maxLine = otherLine;
19772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                }
19782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
19792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return max;
19802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
19812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollVertically() {
19852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == VERTICAL;
19862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean canScrollHorizontally() {
19902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation == HORIZONTAL;
19912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
19942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
19952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
19962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dx, recycler, state);
19972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
19982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
19992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
20002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
20012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            RecyclerView.State state) {
20022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return scrollBy(dy, recycler, state);
20032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    private int calculateScrollDirectionForPosition(int position) {
20062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (getChildCount() == 0) {
20072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START;
20082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int firstChildPos = getFirstChildPosition();
20102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END;
20112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
2014c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    public PointF computeScrollVectorForPosition(int targetPosition) {
2015c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        final int direction = calculateScrollDirectionForPosition(targetPosition);
2016c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        PointF outVector = new PointF();
2017c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if (direction == 0) {
2018c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            return null;
2019c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
2020c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        if (mOrientation == HORIZONTAL) {
2021c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            outVector.x = direction;
2022c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            outVector.y = 0;
2023c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        } else {
2024c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            outVector.x = 0;
2025c587f7dba5a337169e854e235da59f595255d6ccAga Madurska            outVector.y = direction;
2026c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        }
2027c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        return outVector;
2028c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    }
2029c587f7dba5a337169e854e235da59f595255d6ccAga Madurska
2030c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Override
20312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
20322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int position) {
2033c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext());
20342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        scroller.setTargetPosition(position);
20352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        startSmoothScroll(scroller);
20362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
20392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPosition(int position) {
20402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) {
20412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
20422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
20442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
20452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
20462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
20482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
20492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Scroll to the specified adapter position with the given offset from layout start.
20502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
20512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * Note that scroll position change will not be reflected until the next layout call.
20522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * <p>
20532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
20542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *
20552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param position Index (starting at 0) of the reference item.
20562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @param offset   The distance (in pixels) between the start edge of the item view and
20572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     *                 start edge of the RecyclerView.
20582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #setReverseLayout(boolean)
20592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * @see #scrollToPosition(int)
20602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
20612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public void scrollToPositionWithOffset(int position, int offset) {
20622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (mPendingSavedState != null) {
20632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mPendingSavedState.invalidateAnchorPositionInfo();
20642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
20652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPosition = position;
20662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mPendingScrollPositionOffset = offset;
20672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        requestLayout();
20682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
20692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2070945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    /** @hide */
20711ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik    @Override
20721e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
20733104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik            LayoutPrefetchRegistry layoutPrefetchRegistry) {
2074945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        /* This method uses the simplifying assumption that the next N items (where N = span count)
2075945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * will be assigned, one-to-one, to spans, where ordering is based on which span  extends
2076945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * least beyond the viewport.
2077945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         *
2078945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * While this simplified model will be incorrect in some cases, it's difficult to know
2079945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * item heights, or whether individual items will be full span prior to construction.
2080945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         *
2081945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * While this greedy estimation approach may underestimate the distance to prefetch items,
2082945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * it's very unlikely to overestimate them, so distances can be conservatively used to know
2083945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         * the soonest (in terms of scroll distance) a prefetched view may come on screen.
2084945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik         */
20851ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        int delta = (mOrientation == HORIZONTAL) ? dx : dy;
20861ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        if (getChildCount() == 0 || delta == 0) {
20871ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik            // can't support this scroll, so don't bother prefetching
2088945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik            return;
20891ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        }
20901ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        prepareLayoutStateForDelta(delta, state);
2091945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik
2092945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        // build sorted list of distances to end of each span (though we don't care which is which)
2093945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        if (mPrefetchDistances == null || mPrefetchDistances.length < mSpanCount) {
2094945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik            mPrefetchDistances = new int[mSpanCount];
2095945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        }
2096695d9b8629fa048795298359d4845f0747364fafChris Craik
2097695d9b8629fa048795298359d4845f0747364fafChris Craik        int itemPrefetchCount = 0;
2098945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        for (int i = 0; i < mSpanCount; i++) {
2099695d9b8629fa048795298359d4845f0747364fafChris Craik            // compute number of pixels past the edge of the viewport that the current span extends
2100695d9b8629fa048795298359d4845f0747364fafChris Craik            int distance = mLayoutState.mItemDirection == LAYOUT_START
2101945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik                    ? mLayoutState.mStartLine - mSpans[i].getStartLine(mLayoutState.mStartLine)
2102945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik                    : mSpans[i].getEndLine(mLayoutState.mEndLine) - mLayoutState.mEndLine;
2103695d9b8629fa048795298359d4845f0747364fafChris Craik            if (distance >= 0) {
2104695d9b8629fa048795298359d4845f0747364fafChris Craik                // span extends to the edge, so prefetch next item
2105695d9b8629fa048795298359d4845f0747364fafChris Craik                mPrefetchDistances[itemPrefetchCount] = distance;
2106695d9b8629fa048795298359d4845f0747364fafChris Craik                itemPrefetchCount++;
2107695d9b8629fa048795298359d4845f0747364fafChris Craik            }
2108945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        }
2109695d9b8629fa048795298359d4845f0747364fafChris Craik        Arrays.sort(mPrefetchDistances, 0, itemPrefetchCount);
2110945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik
2111945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        // then assign them in order to the next N views (where N = span count)
2112695d9b8629fa048795298359d4845f0747364fafChris Craik        for (int i = 0; i < itemPrefetchCount && mLayoutState.hasMore(state); i++) {
21131e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            layoutPrefetchRegistry.addPosition(mLayoutState.mCurrentPosition,
21141e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    mPrefetchDistances[i]);
21151ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
21161ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        }
21171ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik    }
21181ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik
21191ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik    void prepareLayoutStateForDelta(int delta, RecyclerView.State state) {
21202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int referenceChildPosition;
2121e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        final int layoutDir;
21221ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        if (delta > 0) { // layout towards end
2123e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            layoutDir = LAYOUT_END;
21242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getLastChildPosition();
21252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
2126e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar            layoutDir = LAYOUT_START;
21272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            referenceChildPosition = getFirstChildPosition();
21282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLayoutState.mRecycle = true;
2130e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        updateLayoutState(referenceChildPosition, state);
2131e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar        setLayoutStateDirection(layoutDir);
21322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
2133945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik        mLayoutState.mAvailable = Math.abs(delta);
21341ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik    }
21351ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik
21361ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik    int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
21371ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        if (getChildCount() == 0 || dt == 0) {
21381ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik            return 0;
21391ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        }
21401ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik
21411ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        prepareLayoutStateForDelta(dt, state);
21422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int consumed = fill(recycler, mLayoutState, state);
21431ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        final int available = mLayoutState.mAvailable;
21442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int totalScroll;
21451ce43e3fefb07662431e9fffe62c40242a52cac6Chris Craik        if (available < consumed) {
21462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = dt;
21472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else if (dt < 0) {
21482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = -consumed;
21492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else { // dt > 0
21502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            totalScroll = consumed;
21512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (DEBUG) {
21532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Log.d(TAG, "asked " + dt + " scrolled" + totalScroll);
21542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
21552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2156d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        mPrimaryOrientation.offsetChildren(-totalScroll);
21572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // always reset this if we scroll for a proper save instance state
21582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        mLastLayoutFromEnd = mShouldReverseLayout;
215987b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        mLayoutState.mAvailable = 0;
216087b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        recycle(recycler, mLayoutState);
21612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return totalScroll;
21622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
21632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2164945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    int getLastChildPosition() {
21652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
21662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1));
21672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
21682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2169945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    int getFirstChildPosition() {
21702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int childCount = getChildCount();
21712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return childCount == 0 ? 0 : getPosition(getChildAt(0));
21722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
21732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2174719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
2175719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the first View that can be used as an anchor View.
2176719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
2177719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
2178719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
2179719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findFirstReferenceChildPosition(int itemCount) {
2180719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        final int limit = getChildCount();
2181719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = 0; i < limit; i++) {
2182719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
2183719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
2184719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
2185719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
2186719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
2187719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
2188719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
2189719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
2190719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
2191719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
2192719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Finds the last View that can be used as an anchor View.
2193719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
2194719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return Position of the View or 0 if it cannot find any such View.
2195719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
2196719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    private int findLastReferenceChildPosition(int itemCount) {
2197719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        for (int i = getChildCount() - 1; i >= 0; i--) {
2198719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
2199719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
2200719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
2201719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar                return position;
2202719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
2203719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
2204719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        return 0;
2205719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
2206719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
2207f1811618b8c1a58374da7eb6093038d80c0ede52Yigit Boyar    @SuppressWarnings("deprecation")
22082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
22092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
22104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (mOrientation == HORIZONTAL) {
22114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar            return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
2212e12dfa03641ad9cf0ddf272675bbe7d1198adbfdAurimas Liutikas                    ViewGroup.LayoutParams.MATCH_PARENT);
22134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        } else {
2214e12dfa03641ad9cf0ddf272675bbe7d1198adbfdAurimas Liutikas            return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
22154143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                    ViewGroup.LayoutParams.WRAP_CONTENT);
22164143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        }
22172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
22202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
22212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return new LayoutParams(c, attrs);
22222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
22252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
22262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        if (lp instanceof ViewGroup.MarginLayoutParams) {
22272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
22282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        } else {
22292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return new LayoutParams(lp);
22302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
22312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    @Override
22342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
22352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return lp instanceof LayoutParams;
22362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
22382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public int getOrientation() {
22392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        return mOrientation;
22402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
22412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2242f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    @Nullable
2243f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    @Override
2244f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
2245f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            RecyclerView.State state) {
2246f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (getChildCount() == 0) {
2247f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            return null;
2248f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
2249f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
2250bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar        final View directChild = findContainingItemView(focused);
2251f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (directChild == null) {
2252f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            return null;
2253f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
2254f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
2255f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        resolveShouldLayoutReverse();
2256f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        final int layoutDir = convertFocusDirectionToLayoutDirection(direction);
2257f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (layoutDir == LayoutState.INVALID_LAYOUT) {
2258f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            return null;
2259f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
2260bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar        LayoutParams prevFocusLayoutParams = (LayoutParams) directChild.getLayoutParams();
2261f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        boolean prevFocusFullSpan = prevFocusLayoutParams.mFullSpan;
2262f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        final Span prevFocusSpan = prevFocusLayoutParams.mSpan;
2263f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        final int referenceChildPosition;
2264f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (layoutDir == LAYOUT_END) { // layout towards end
2265f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            referenceChildPosition = getLastChildPosition();
2266f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        } else {
2267f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            referenceChildPosition = getFirstChildPosition();
2268f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
2269f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        updateLayoutState(referenceChildPosition, state);
2270f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        setLayoutStateDirection(layoutDir);
2271f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
2272f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection;
2273f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        mLayoutState.mAvailable = (int) (MAX_SCROLL_FACTOR * mPrimaryOrientation.getTotalSpace());
2274f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        mLayoutState.mStopInFocusable = true;
22754143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        mLayoutState.mRecycle = false;
2276f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        fill(recycler, mLayoutState, state);
2277f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        mLastLayoutFromEnd = mShouldReverseLayout;
2278f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (!prevFocusFullSpan) {
2279f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            View view = prevFocusSpan.getFocusableViewAfter(referenceChildPosition, layoutDir);
2280bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar            if (view != null && view != directChild) {
2281f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return view;
2282f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            }
2283f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
22849c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
2285f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        // either could not find from the desired span or prev view is full span.
2286f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        // traverse all spans
2287f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        if (preferLastSpan(layoutDir)) {
22881e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            for (int i = mSpanCount - 1; i >= 0; i--) {
2289f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
2290bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar                if (view != null && view != directChild) {
2291f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    return view;
2292f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
2293f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            }
2294f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        } else {
22951e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            for (int i = 0; i < mSpanCount; i++) {
2296f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir);
2297bc61003e6a10872c23f0de155456cb2fbeef31a7Yigit Boyar                if (view != null && view != directChild) {
2298f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    return view;
2299f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
2300f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            }
2301f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
23029c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
23039c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // Could not find any focusable views from any of the existing spans. Now start the search
23049c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // to find the best unfocusable candidate to become visible on the screen next. The search
23059c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // is done in the same fashion: first, check the views in the desired span and if no
23069c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // candidate is found, traverse the views in all the remaining spans.
23079c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        boolean shouldSearchFromStart = !mReverseLayout == (layoutDir == LayoutState.LAYOUT_START);
23089c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        View unfocusableCandidate = null;
23099c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (!prevFocusFullSpan) {
23109c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            unfocusableCandidate = findViewByPosition(shouldSearchFromStart
23119c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    ? prevFocusSpan.findFirstPartiallyVisibleItemPosition() :
23129c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    prevFocusSpan.findLastPartiallyVisibleItemPosition());
23139c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
23149c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                return unfocusableCandidate;
23159c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            }
23169c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
23179c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
23189c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (preferLastSpan(layoutDir)) {
23199c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            for (int i = mSpanCount - 1; i >= 0; i--) {
23209c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                if (i == prevFocusSpan.mIndex) {
23219c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    continue;
23229c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                }
23239c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                unfocusableCandidate = findViewByPosition(shouldSearchFromStart
23249c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        ? mSpans[i].findFirstPartiallyVisibleItemPosition() :
23259c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        mSpans[i].findLastPartiallyVisibleItemPosition());
23269c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
23279c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    return unfocusableCandidate;
23289c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                }
23299c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            }
23309c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        } else {
23319c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            for (int i = 0; i < mSpanCount; i++) {
23329c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                unfocusableCandidate = findViewByPosition(shouldSearchFromStart
23339c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        ? mSpans[i].findFirstPartiallyVisibleItemPosition() :
23349c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        mSpans[i].findLastPartiallyVisibleItemPosition());
23359c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
23369c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    return unfocusableCandidate;
23379c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                }
23389c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            }
23399c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
2340f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        return null;
2341f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    }
2342f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
2343f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    /**
2344f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * Converts a focusDirection to orientation.
2345f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     *
2346f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
2347f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     *                       {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
2348f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     *                       {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
2349f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     *                       or 0 for not applicable
2350f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
2351f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     * is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
2352f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar     */
2353f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    private int convertFocusDirectionToLayoutDirection(int focusDirection) {
2354f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        switch (focusDirection) {
2355f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_BACKWARD:
2356d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                if (mOrientation == VERTICAL) {
2357d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
2358d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else if (isLayoutRTL()) {
2359d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
2360d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else {
2361d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
2362d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                }
2363f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_FORWARD:
2364d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                if (mOrientation == VERTICAL) {
2365d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
2366d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else if (isLayoutRTL()) {
2367d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
2368d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else {
2369d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
2370d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                }
2371f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_UP:
2372f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return mOrientation == VERTICAL ? LayoutState.LAYOUT_START
2373f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        : LayoutState.INVALID_LAYOUT;
2374f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_DOWN:
2375f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return mOrientation == VERTICAL ? LayoutState.LAYOUT_END
2376f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        : LayoutState.INVALID_LAYOUT;
2377f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_LEFT:
2378f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START
2379f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        : LayoutState.INVALID_LAYOUT;
2380f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            case View.FOCUS_RIGHT:
2381f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END
2382f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        : LayoutState.INVALID_LAYOUT;
2383f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            default:
2384f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                if (DEBUG) {
2385f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    Log.d(TAG, "Unknown focus request:" + focusDirection);
2386f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
2387f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                return LayoutState.INVALID_LAYOUT;
2388f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
2389f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
2390f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    }
23912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
23922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
23932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * LayoutParams used by StaggeredGridLayoutManager.
239442e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * <p>
239542e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the
239642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is
239742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar     * expected to fill all of the space given to it.
23982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
23992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    public static class LayoutParams extends RecyclerView.LayoutParams {
24002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
24022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Span Id for Views that are not laid out yet.
24032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
24042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public static final int INVALID_SPAN_ID = -1;
24052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Package scope to be able to access from tests.
24072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        Span mSpan;
24082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mFullSpan;
24102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(Context c, AttributeSet attrs) {
24122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(c, attrs);
24132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(int width, int height) {
24162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(width, height);
24172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.MarginLayoutParams source) {
24202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
24212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(ViewGroup.LayoutParams source) {
24242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
24252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public LayoutParams(RecyclerView.LayoutParams source) {
24282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            super(source);
24292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
24322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * When set to true, the item will layout using all span area. That means, if orientation
24332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * is vertical, the view will have full width; if orientation is horizontal, the view will
24342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * have full height.
24352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
24362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @param fullSpan True if this item should traverse all spans.
24377499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #isFullSpan()
24382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
24392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void setFullSpan(boolean fullSpan) {
24402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mFullSpan = fullSpan;
24412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        /**
24447499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * Returns whether this View occupies all available spans or just one.
24457499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         *
24467499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @return True if the View occupies all spans or false otherwise.
24477499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         * @see #setFullSpan(boolean)
24487499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar         */
24497499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        public boolean isFullSpan() {
24507499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar            return mFullSpan;
24517499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        }
24527499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar
24537499c6e5b853057aa81bfc20c39e6fa188805c55Yigit Boyar        /**
24542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * Returns the Span index to which this View is assigned.
24552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         *
24562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * @return The Span index of the View. If View is not yet assigned to any span, returns
24572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         * {@link #INVALID_SPAN_ID}.
24582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar         */
24592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public final int getSpanIndex() {
24602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpan == null) {
24612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return INVALID_SPAN_ID;
24622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
24632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mSpan.mIndex;
24642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
24662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    // Package scoped to access from tests.
24682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    class Span {
24692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24706b4d950d0d1e26165a1e643a2fd1fe4e283786f1Yigit Boyar        static final int INVALID_LINE = Integer.MIN_VALUE;
24713a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas        ArrayList<View> mViews = new ArrayList<>();
24722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedStart = INVALID_LINE;
24732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mCachedEnd = INVALID_LINE;
24742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mDeletedSize = 0;
24752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        final int mIndex;
24762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24773a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas        Span(int index) {
24782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mIndex = index;
24792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
24812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine(int def) {
24822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
24832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
24842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
24852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
24862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
24872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2488d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
24892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
24902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
24912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2492d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedStart() {
2493d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View startView = mViews.get(0);
2494d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(startView);
2495d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedStart = mPrimaryOrientation.getDecoratedStart(startView);
2496d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
2497d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
2498115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        .getFullSpanItem(lp.getViewLayoutPosition());
2499d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_START) {
2500d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedStart -= fsi.getGapForSpan(mIndex);
2501d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2502d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2503d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2504d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
25052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
25062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getStartLine() {
25072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
25082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedStart;
25092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2510d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedStart();
25112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedStart;
25122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine(int def) {
25152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
25162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
25172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
25192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 0) {
25202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return def;
25212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2522d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
25232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
25242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2526d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void calculateCachedEnd() {
2527d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final View endView = mViews.get(mViews.size() - 1);
2528d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final LayoutParams lp = getLayoutParams(endView);
2529d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView);
2530d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (lp.mFullSpan) {
2531d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                LazySpanLookup.FullSpanItem fsi = mLazySpanLookup
2532115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar                        .getFullSpanItem(lp.getViewLayoutPosition());
2533d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi != null && fsi.mGapDir == LAYOUT_END) {
2534d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mCachedEnd += fsi.getGapForSpan(mIndex);
2535d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2536d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2537d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2538d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
25392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Use this one when default value does not make sense and not having a value means a bug.
25402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getEndLine() {
25412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
25422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mCachedEnd;
25432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2544d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            calculateCachedEnd();
25452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mCachedEnd;
25462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void prependToSpan(View view) {
25492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
25502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
25512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(0, view);
25522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
25532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
25542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
25552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25567c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
25572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
25582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void appendToSpan(View view) {
25622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            LayoutParams lp = getLayoutParams(view);
25632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = this;
25642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.add(view);
25652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
25662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 1) {
25672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
25682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25697c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
25702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view);
25712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        // Useful method to preserve positions on a re-layout.
25752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void cacheReferenceLineAndClear(boolean reverseLayout, int offset) {
25762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int reference;
25772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reverseLayout) {
25782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getEndLine(INVALID_LINE);
25792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
25802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference = getStartLine(INVALID_LINE);
25812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            clear();
25832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (reference == INVALID_LINE) {
25842d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return;
25852d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25861e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding())
25871e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    || (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) {
2588d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2589d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
25902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (offset != INVALID_OFFSET) {
25912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                reference += offset;
25922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
25932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = mCachedEnd = reference;
25942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
25952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
25962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
25972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mViews.clear();
25982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            invalidateCache();
25992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mDeletedSize = 0;
26002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateCache() {
26032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
26042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
26052d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26062d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26072d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setLine(int line) {
26082d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = mCachedStart = line;
26092d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popEnd() {
26122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final int size = mViews.size();
26132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View end = mViews.remove(size - 1);
26142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(end);
26152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
26167c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
26172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end);
26182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (size == 1) {
26202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart = INVALID_LINE;
26212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedEnd = INVALID_LINE;
26232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void popStart() {
26262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            View start = mViews.remove(0);
26272d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            final LayoutParams lp = getLayoutParams(start);
26282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            lp.mSpan = null;
26292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mViews.size() == 0) {
26302d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd = INVALID_LINE;
26312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26327c7fba8365684e1ccfc4f39f286df4d100c6c81fJustin Klaassen            if (lp.isItemRemoved() || lp.isItemChanged()) {
26332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start);
26342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mCachedStart = INVALID_LINE;
26362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int getDeletedSize() {
26392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return mDeletedSize;
26402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        LayoutParams getLayoutParams(View view) {
26432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return (LayoutParams) view.getLayoutParams();
26442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
26462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void onOffset(int dt) {
26472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedStart != INVALID_LINE) {
26482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedStart += dt;
26492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mCachedEnd != INVALID_LINE) {
26512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mCachedEnd += dt;
26522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
26532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
26542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2655333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstVisibleItemPosition() {
2656333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
265742e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    ? findOneVisibleChild(mViews.size() - 1, -1, false)
2658333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), false);
2659333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2660333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
26619c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        public int findFirstPartiallyVisibleItemPosition() {
26629c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return mReverseLayout
26639c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    ? findOnePartiallyVisibleChild(mViews.size() - 1, -1, true)
26649c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    : findOnePartiallyVisibleChild(0, mViews.size(), true);
26659c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
26669c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
2667333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findFirstCompletelyVisibleItemPosition() {
2668333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
266942e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    ? findOneVisibleChild(mViews.size() - 1, -1, true)
2670333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    : findOneVisibleChild(0, mViews.size(), true);
2671333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2672333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
2673333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastVisibleItemPosition() {
2674333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2675333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), false)
267642e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, false);
2677333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2678333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
26799c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        public int findLastPartiallyVisibleItemPosition() {
26809c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return mReverseLayout
26819c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    ? findOnePartiallyVisibleChild(0, mViews.size(), true)
26829c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    : findOnePartiallyVisibleChild(mViews.size() - 1, -1, true);
26839c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
26849c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
2685333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        public int findLastCompletelyVisibleItemPosition() {
2686333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            return mReverseLayout
2687333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    ? findOneVisibleChild(0, mViews.size(), true)
268842e9353bb9eb2747247e30e3612b227945acfd16Yigit Boyar                    : findOneVisibleChild(mViews.size() - 1, -1, true);
2689333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2690333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar
26919c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        /**
26929c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * Returns the first view within this span that is partially or fully visible. Partially
26939c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * visible refers to a view that overlaps but is not fully contained within RV's padded
26949c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * bounded area. This view returned can be defined to have an area of overlap strictly
26959c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * greater than zero if acceptEndPointInclusion is false. If true, the view's endpoint
26969c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * inclusion is enough to consider it partially visible. The latter case can then refer to
26979c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * an out-of-bounds view positioned right at the top (or bottom) boundaries of RV's padded
26989c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * area. This is used e.g. inside
26999c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * {@link #onFocusSearchFailed(View, int, RecyclerView.Recycler, RecyclerView.State)} for
27009c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * calculating the next unfocusable child to become visible on the screen.
27019c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @param fromIndex The child position index to start the search from.
27029c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @param toIndex The child position index to end the search at.
27039c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @param completelyVisible True if we have to only consider completely visible views,
27049c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         *                          false otherwise.
27059c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @param acceptCompletelyVisible True if we can consider both partially or fully visible
27069c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         *                                views, false, if only a partially visible child should be
27079c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         *                                returned.
27089c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @param acceptEndPointInclusion If the view's endpoint intersection with RV's padded
27099c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         *                                bounded area is enough to consider it partially visible,
27109c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         *                                false otherwise
27119c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * @return The adapter position of the first view that's either partially or fully visible.
27129c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         * {@link RecyclerView#NO_POSITION} if no such view is found.
27139c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri         */
27149c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        int findOnePartiallyOrCompletelyVisibleChild(int fromIndex, int toIndex,
27159c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean completelyVisible,
27169c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean acceptCompletelyVisible,
27179c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean acceptEndPointInclusion) {
2718333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int start = mPrimaryOrientation.getStartAfterPadding();
2719333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int end = mPrimaryOrientation.getEndAfterPadding();
2720333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            final int next = toIndex > fromIndex ? 1 : -1;
2721d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = fromIndex; i != toIndex; i += next) {
2722333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final View child = mViews.get(i);
2723333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
2724333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
27259c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean childStartInclusion = acceptEndPointInclusion ? (childStart <= end)
27269c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        : (childStart < end);
27279c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean childEndInclusion = acceptEndPointInclusion ? (childEnd >= start)
27289c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        : (childEnd > start);
27299c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                if (childStartInclusion && childEndInclusion) {
27309c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    if (completelyVisible && acceptCompletelyVisible) {
27319c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        // the child has to be completely visible to be returned.
2732333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        if (childStart >= start && childEnd <= end) {
2733333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                            return getPosition(child);
2734333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        }
27359c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    } else if (acceptCompletelyVisible) {
27369c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        // can return either a partially or completely visible child.
27379c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        return getPosition(child);
27389c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    } else if (childStart < start || childEnd > end) {
27399c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        // should return a partially visible child if exists and a completely
27409c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        // visible child is not acceptable in this case.
2741333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                        return getPosition(child);
2742333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                    }
2743333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar                }
2744333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            }
2745d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return NO_POSITION;
2746333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar        }
2747f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar
27489c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
27499c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return findOnePartiallyOrCompletelyVisibleChild(fromIndex, toIndex, completelyVisible,
27509c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    true, false);
27519c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
27529c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
27539c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        int findOnePartiallyVisibleChild(int fromIndex, int toIndex,
27549c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                boolean acceptEndPointInclusion) {
27559c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return findOnePartiallyOrCompletelyVisibleChild(fromIndex, toIndex, false, false,
27569c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    acceptEndPointInclusion);
27579c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
27589c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
2759f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        /**
2760f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar         * Depending on the layout direction, returns the View that is after the given position.
2761f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar         */
2762f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        public View getFocusableViewAfter(int referenceChildPosition, int layoutDir) {
2763f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            View candidate = null;
2764f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            if (layoutDir == LAYOUT_START) {
2765f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                final int limit = mViews.size();
2766f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                for (int i = 0; i < limit; i++) {
2767f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    final View view = mViews.get(i);
27689c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    if ((mReverseLayout && getPosition(view) <= referenceChildPosition)
27699c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                            || (!mReverseLayout && getPosition(view) >= referenceChildPosition)) {
27709c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        break;
27719c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    }
2772b174744db6a70f384d44caeb43e10854652e81b9Keyvan Amiri                    if (view.hasFocusable()) {
2773f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        candidate = view;
2774f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    } else {
2775f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        break;
2776f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    }
2777f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
2778f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            } else {
2779f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                for (int i = mViews.size() - 1; i >= 0; i--) {
2780f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    final View view = mViews.get(i);
27819c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    if ((mReverseLayout && getPosition(view) >= referenceChildPosition)
27829c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                            || (!mReverseLayout && getPosition(view) <= referenceChildPosition)) {
27839c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        break;
27849c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    }
2785b174744db6a70f384d44caeb43e10854652e81b9Keyvan Amiri                    if (view.hasFocusable()) {
2786f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        candidate = view;
2787f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    } else {
2788f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                        break;
2789f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                    }
2790f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                }
2791f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            }
2792f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            return candidate;
2793f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar        }
27942d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
27952d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
27962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    /**
27972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * An array of mappings from adapter position to span.
27982d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     * This only grows when a write happens and it grows up to the size of the adapter.
27992d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar     */
28002d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    static class LazySpanLookup {
28012d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        private static final int MIN_SIZE = 10;
28032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mData;
2804d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<FullSpanItem> mFullSpanItems;
2805d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2806d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2807d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2808d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Invalidates everything after this position, including full span information
2809d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2810d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int forceInvalidateAfter(int position) {
2811d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems != null) {
2812d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2813d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    FullSpanItem fsi = mFullSpanItems.get(i);
2814d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (fsi.mPosition >= position) {
2815d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2816d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2817d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2818d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2819d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return invalidateAfter(position);
2820d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
28212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
2822d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2823d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * returns end position for invalidation.
2824d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2825d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int invalidateAfter(int position) {
28262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
2827d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
28282d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
28292d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (position >= mData.length) {
2830d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2831d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2832d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int endPosition = invalidateFullSpansAfter(position);
2833d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (endPosition == RecyclerView.NO_POSITION) {
2834d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID);
2835d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mData.length;
2836d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
2837d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                // just invalidate items in between
2838d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID);
2839d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return endPosition + 1;
28402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
28412d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28422d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28432d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int getSpan(int position) {
28442d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null || position >= mData.length) {
28452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return LayoutParams.INVALID_SPAN_ID;
28462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else {
28472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                return mData[position];
28482d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
28492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28502d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void setSpan(int position, Span span) {
28522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(position);
28532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mData[position] = span.mIndex;
28542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28562d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int sizeForPosition(int position) {
28572d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            int len = mData.length;
28582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            while (len <= position) {
28592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                len *= 2;
28602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
28612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return len;
28622d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void ensureSize(int position) {
28652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData == null) {
28662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[Math.max(position, MIN_SIZE) + 1];
28672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
28682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            } else if (position >= mData.length) {
28692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                int[] old = mData;
28702d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mData = new int[sizeForPosition(position)];
28712d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                System.arraycopy(old, 0, mData, 0, old.length);
28722d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID);
28732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
28742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void clear() {
28772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mData != null) {
28782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID);
28792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
2880d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
28812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
28822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
28832d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForRemoval(int positionStart, int itemCount) {
2884d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2885d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2886d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
28872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
28882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart + itemCount, mData, positionStart,
28892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
28902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, mData.length - itemCount, mData.length,
28912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2892d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForRemoval(positionStart, itemCount);
2893d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2894d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2895d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForRemoval(int positionStart, int itemCount) {
2896d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2897d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2898d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2899d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int end = positionStart + itemCount;
2900d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2901d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2902d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2903d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2904d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2905d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < end) {
2906d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.remove(i);
2907d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
2908d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    fsi.mPosition -= itemCount;
2909d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2910d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
29112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
29122d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
29132d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void offsetForAddition(int positionStart, int itemCount) {
2914d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mData == null || positionStart >= mData.length) {
2915d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2916d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
29172d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            ensureSize(positionStart + itemCount);
29182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            System.arraycopy(mData, positionStart, mData, positionStart + itemCount,
29192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    mData.length - positionStart - itemCount);
29202d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            Arrays.fill(mData, positionStart, positionStart + itemCount,
29212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                    LayoutParams.INVALID_SPAN_ID);
2922d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            offsetFullSpansForAddition(positionStart, itemCount);
2923d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2924d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2925d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private void offsetFullSpansForAddition(int positionStart, int itemCount) {
2926d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2927d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return;
2928d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2929d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2930d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2931d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition < positionStart) {
2932d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    continue;
2933d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2934d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                fsi.mPosition += itemCount;
2935d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2936d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2937d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2938d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
2939d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returns when invalidation should end. e.g. hitting a full span position.
2940d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * Returned position SHOULD BE invalidated.
2941d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
2942d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        private int invalidateFullSpansAfter(int position) {
2943d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2944d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return RecyclerView.NO_POSITION;
2945d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2946d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final FullSpanItem item = getFullSpanItem(position);
2947d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if there is an fsi at this position, get rid of it.
2948d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (item != null) {
2949d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(item);
2950d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2951d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int nextFsiIndex = -1;
2952d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int count = mFullSpanItems.size();
2953d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < count; i++) {
2954d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
2955d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= position) {
2956d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    nextFsiIndex = i;
2957d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    break;
2958d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2959d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2960d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (nextFsiIndex != -1) {
2961d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex);
2962d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mFullSpanItems.remove(nextFsiIndex);
2963d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return fsi.mPosition;
2964d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2965d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return RecyclerView.NO_POSITION;
2966d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2967d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2968d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public void addFullSpanItem(FullSpanItem fullSpanItem) {
2969d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2970f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar                mFullSpanItems = new ArrayList<>();
2971d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2972d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            final int size = mFullSpanItems.size();
2973d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = 0; i < size; i++) {
2974d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem other = mFullSpanItems.get(i);
2975d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition == fullSpanItem.mPosition) {
2976d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    if (DEBUG) {
2977d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        throw new IllegalStateException("two fsis for same position");
2978d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    } else {
2979d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                        mFullSpanItems.remove(i);
2980d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    }
2981d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2982d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (other.mPosition >= fullSpanItem.mPosition) {
2983d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mFullSpanItems.add(i, fullSpanItem);
2984d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return;
2985d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
2986d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2987d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            // if it is not added to a position.
2988d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems.add(fullSpanItem);
2989d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
2990d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
2991d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        public FullSpanItem getFullSpanItem(int position) {
2992d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
2993d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
2994d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
2995d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            for (int i = mFullSpanItems.size() - 1; i >= 0; i--) {
2996d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                final FullSpanItem fsi = mFullSpanItems.get(i);
2997d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition == position) {
2998d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
2999d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3000d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3001d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
3002d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
3003d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3004d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
3005d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param minPos inclusive
3006d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param maxPos exclusive
3007d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * @param gapDir if not 0, returns FSIs on in that direction
3008f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar         * @param hasUnwantedGapAfter If true, when full span item has unwanted gaps, it will be
3009f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar         *                        returned even if its gap direction does not match.
3010d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
3011f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar        public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir,
3012f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                boolean hasUnwantedGapAfter) {
3013d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mFullSpanItems == null) {
3014d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return null;
3015d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3016f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            final int limit = mFullSpanItems.size();
3017f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            for (int i = 0; i < limit; i++) {
3018d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                FullSpanItem fsi = mFullSpanItems.get(i);
3019d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (fsi.mPosition >= maxPos) {
3020d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return null;
3021d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3022f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                if (fsi.mPosition >= minPos
30231e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        && (gapDir == 0 || fsi.mGapDir == gapDir
30241e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        || (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) {
3025d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    return fsi;
3026d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3027d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3028d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return null;
3029d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
3030d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3031d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        /**
3032d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         * We keep information about full span items because they may create gaps in the UI.
3033d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar         */
3034d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        static class FullSpanItem implements Parcelable {
3035d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3036d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mPosition;
3037d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int mGapDir;
3038d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int[] mGapPerSpan;
3039f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // A full span may be laid out in primary direction but may have gaps due to
3040f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // invalidation of views after it. This is recorded during a reverse scroll and if
3041f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            // view is still on the screen after scroll stops, we have to recalculate layout
3042f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar            boolean mHasUnwantedGapAfter;
3043d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
30441e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            FullSpanItem(Parcel in) {
3045d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mPosition = in.readInt();
3046d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mGapDir = in.readInt();
3047f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                mHasUnwantedGapAfter = in.readInt() == 1;
3048d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                int spanCount = in.readInt();
3049d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (spanCount > 0) {
3050d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    mGapPerSpan = new int[spanCount];
3051d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    in.readIntArray(mGapPerSpan);
3052d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3053d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3054d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
30551e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            FullSpanItem() {
3056d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3057d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3058d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            int getGapForSpan(int spanIndex) {
3059d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex];
3060d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3061d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3062d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
3063d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public int describeContents() {
3064d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                return 0;
3065d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3066d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3067d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
3068d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public void writeToParcel(Parcel dest, int flags) {
3069d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mPosition);
3070d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                dest.writeInt(mGapDir);
3071f009f639980abd669fd533e5bc6ed42f3d4ed9ffYigit Boyar                dest.writeInt(mHasUnwantedGapAfter ? 1 : 0);
3072d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                if (mGapPerSpan != null && mGapPerSpan.length > 0) {
3073d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(mGapPerSpan.length);
3074d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeIntArray(mGapPerSpan);
3075d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                } else {
3076d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    dest.writeInt(0);
3077d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                }
3078d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3079d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3080d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            @Override
3081d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            public String toString() {
30821e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                return "FullSpanItem{"
30831e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + "mPosition=" + mPosition
30841e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + ", mGapDir=" + mGapDir
30851e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter
30861e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + ", mGapPerSpan=" + Arrays.toString(mGapPerSpan)
30871e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + '}';
30881e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            }
30891e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas
30901e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            public static final Parcelable.Creator<FullSpanItem> CREATOR =
30911e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    new Parcelable.Creator<FullSpanItem>() {
30921e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        @Override
30931e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        public FullSpanItem createFromParcel(Parcel in) {
30941e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            return new FullSpanItem(in);
30951e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        }
3096d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
30971e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        @Override
30981e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        public FullSpanItem[] newArray(int size) {
30991e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            return new FullSpanItem[size];
31001e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        }
31011e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    };
31022d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31032d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
31042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
3105ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar    /**
3106ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar     * @hide
3107ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar     */
31088e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
3109ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar    public static class SavedState implements Parcelable {
31102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31112d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mAnchorPosition;
3112d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated
3113b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar        int mSpanOffsetsSize;
31142d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanOffsets;
31152d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int mSpanLookupSize;
31162d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        int[] mSpanLookup;
3117d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        List<LazySpanLookup.FullSpanItem> mFullSpanItems;
31182d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mReverseLayout;
31192d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        boolean mAnchorLayoutFromEnd;
3120d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLastLayoutRTL;
31212d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31222d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState() {
31232d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31242d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31252d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        SavedState(Parcel in) {
31262d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = in.readInt();
3127333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = in.readInt();
3128b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = in.readInt();
3129b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
3130b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar                mSpanOffsets = new int[mSpanOffsetsSize];
31312d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanOffsets);
31322d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
31332d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31342d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = in.readInt();
31352d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
31362d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                mSpanLookup = new int[mSpanLookupSize];
31372d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                in.readIntArray(mSpanLookup);
31382d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
31392d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = in.readInt() == 1;
31402d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = in.readInt() == 1;
3141d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = in.readInt() == 1;
3142f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar            //noinspection unchecked
3143d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = in.readArrayList(
3144d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    LazySpanLookup.FullSpanItem.class.getClassLoader());
31452d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31462d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31472d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public SavedState(SavedState other) {
3148b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = other.mSpanOffsetsSize;
31492d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorPosition = other.mAnchorPosition;
3150333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            mVisibleAnchorPosition = other.mVisibleAnchorPosition;
31512d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = other.mSpanOffsets;
31522d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = other.mSpanLookupSize;
31532d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = other.mSpanLookup;
31542d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mReverseLayout = other.mReverseLayout;
31552d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
3156d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLastLayoutRTL = other.mLastLayoutRTL;
3157d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = other.mFullSpanItems;
31582d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31592d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31602d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateSpanInfo() {
31612d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
3162b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
31632d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookupSize = 0;
31642d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanLookup = null;
3165d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mFullSpanItems = null;
31662d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31672d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31682d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        void invalidateAnchorPositionInfo() {
31692d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            mSpanOffsets = null;
3170b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mSpanOffsetsSize = 0;
3171d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mAnchorPosition = NO_POSITION;
3172d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mVisibleAnchorPosition = NO_POSITION;
31732d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31742d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31752d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
31762d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public int describeContents() {
31772d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            return 0;
31782d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31792d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31802d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        @Override
31812d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        public void writeToParcel(Parcel dest, int flags) {
31822d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorPosition);
3183333382aecf6822cb1ec484e8d3e4e822c9bd0c8dYigit Boyar            dest.writeInt(mVisibleAnchorPosition);
3184b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            dest.writeInt(mSpanOffsetsSize);
3185b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            if (mSpanOffsetsSize > 0) {
31862d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanOffsets);
31872d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
31882d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mSpanLookupSize);
31892d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            if (mSpanLookupSize > 0) {
31902d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar                dest.writeIntArray(mSpanLookup);
31912d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            }
31922d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mReverseLayout ? 1 : 0);
31932d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
3194d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeInt(mLastLayoutRTL ? 1 : 0);
3195d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            dest.writeList(mFullSpanItems);
31962d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar        }
31972d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
31981e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        public static final Parcelable.Creator<SavedState> CREATOR =
31991e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                new Parcelable.Creator<SavedState>() {
32001e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    @Override
32011e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    public SavedState createFromParcel(Parcel in) {
32021e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return new SavedState(in);
32031e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    }
32042d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar
32051e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    @Override
32061e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    public SavedState[] newArray(int size) {
32071e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return new SavedState[size];
32081e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    }
32091e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                };
32102d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar    }
3211d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3212d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    /**
3213d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     * Data class to hold the information about an anchor position which is used in onLayout call.
3214d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar     */
32159aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar    class AnchorInfo {
3216d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3217d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mPosition;
3218d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        int mOffset;
3219d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mLayoutFromEnd;
3220d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        boolean mInvalidateOffsets;
32219aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        boolean mValid;
322287b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        // this is where we save span reference lines in case we need to re-use them for multi-pass
322387b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        // measure steps
322487b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        int[] mSpanReferenceLines;
32259aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar
32261e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        AnchorInfo() {
32279aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            reset();
32289aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        }
3229d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3230d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void reset() {
3231d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mPosition = NO_POSITION;
3232d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = INVALID_OFFSET;
3233d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mLayoutFromEnd = false;
3234d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mInvalidateOffsets = false;
32359aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mValid = false;
323687b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            if (mSpanReferenceLines != null) {
323787b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                Arrays.fill(mSpanReferenceLines, -1);
323887b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            }
323987b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        }
324087b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar
324187b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar        void saveSpanReferenceLines(Span[] spans) {
324287b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            int spanCount = spans.length;
324387b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            if (mSpanReferenceLines == null || mSpanReferenceLines.length < spanCount) {
324487b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                mSpanReferenceLines = new int[mSpans.length];
324587b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            }
324687b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            for (int i = 0; i < spanCount; i++) {
324787b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                // does not matter start or end since this is only recorded when span is reset
324887b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar                mSpanReferenceLines[i] = spans[i].getStartLine(Span.INVALID_LINE);
324987b20c0e2004e884422b37fae6202c83cc24a8d9Yigit Boyar            }
3250d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
3251d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3252d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding() {
3253d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding()
3254d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                    : mPrimaryOrientation.getStartAfterPadding();
3255d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
3256d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar
3257d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        void assignCoordinateFromPadding(int addedDistance) {
3258d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            if (mLayoutFromEnd) {
3259d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance;
3260d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            } else {
3261d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar                mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance;
3262d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            }
3263d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        }
3264d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar    }
32652d2e8d88103866b631eb0f3805da137ebcfb0275Yigit Boyar}
3266