17dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
37dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar *
47dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
57dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * you may not use this file except in compliance with the License.
67dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * You may obtain a copy of the License at
77dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar *
87dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
97dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar *
107dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * Unless required by applicable law or agreed to in writing, software
117dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
127dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas * See the License for the specific language governing permissions and
147dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * limitations under the License.
157dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar */
167dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.recyclerview.widget;
187dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
206b6a29eea7f6a212447b3cc7b45a081b609ca4b1Yigit Boyar
217dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyarimport android.content.Context;
22baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Pealimport android.graphics.PointF;
2308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyarimport android.os.Parcel;
2408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyarimport android.os.Parcelable;
254143554adb9b31b700b6876a251a64419e6111e2Yigit Boyarimport android.util.AttributeSet;
267dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyarimport android.util.Log;
277dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyarimport android.view.View;
287dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyarimport android.view.ViewGroup;
29a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyarimport android.view.accessibility.AccessibilityEvent;
30a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
31c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.NonNull;
32c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.annotation.RestrictTo;
33c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.core.os.TraceCompat;
34c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikasimport androidx.core.view.ViewCompat;
35c95a6f1f125ad3a7e1f9f79bccf4b2603bc40ebaAurimas Liutikas
36b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyarimport java.util.List;
37b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
387dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar/**
39ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * A {@link RecyclerView.LayoutManager} implementation which provides
407dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar * similar functionality to {@link android.widget.ListView}.
417dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar */
42e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarpublic class LinearLayoutManager extends RecyclerView.LayoutManager implements
43c587f7dba5a337169e854e235da59f595255d6ccAga Madurska        ItemTouchHelper.ViewDropHandler, RecyclerView.SmoothScroller.ScrollVectorProvider {
447dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
457dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private static final String TAG = "LinearLayoutManager";
467dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
473a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas    static final boolean DEBUG = false;
487dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
49a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard    public static final int HORIZONTAL = RecyclerView.HORIZONTAL;
507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
51a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard    public static final int VERTICAL = RecyclerView.VERTICAL;
527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
53d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    public static final int INVALID_OFFSET = Integer.MIN_VALUE;
54d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
550447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar
567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
575f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * While trying to find next view to focus, LayoutManager will not try to scroll more
585f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * than this factor times the total space of the list. If layout is vertical, total space is the
592aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * height minus padding, if layout is horizontal, total space is the width minus padding.
602aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     */
61f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    private static final float MAX_SCROLL_FACTOR = 1 / 3f;
622aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
632aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    /**
647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}
657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
66a8e9d2739e676eb27f2570b3db278e183ec327f2Aurimas Liutikas    @RecyclerView.Orientation
67a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard    int mOrientation = RecyclerView.DEFAULT_ORIENTATION;
687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
7094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * Helper class that keeps temporary layout state.
7194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * It does not keep state after layout is complete but we still keep a reference to re-use
727dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * the same object.
737dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
7494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    private LayoutState mLayoutState;
757dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
767dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Many calculations are made depending on orientation. To keep it clean, this interface
787dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * helps {@link LinearLayoutManager} make those decisions.
797dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
80d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    OrientationHelper mOrientationHelper;
817dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
837dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * We need to track this so that we can ignore current position when it changes.
847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
8508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    private boolean mLastStackFromEnd;
867dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
877dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
897dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Defines if layout should be calculated from end to start.
907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @see #mShouldReverseLayout
927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
937dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private boolean mReverseLayout = false;
947dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
957dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
968c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * This keeps the final value for how LayoutManager should start laying out views.
977dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * It is calculated by checking {@link #getReverseLayout()} and View's layout direction.
98d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * {@link #onLayoutChildren(RecyclerView.Recycler, RecyclerView.State)} is run.
997dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
100b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    boolean mShouldReverseLayout = false;
1017dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1027dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
1037dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Works the same way as {@link android.widget.AbsListView#setStackFromBottom(boolean)} and
1047dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * it supports both orientations.
1057dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * see {@link android.widget.AbsListView#setStackFromBottom(boolean)}
1067dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
1077dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private boolean mStackFromEnd = false;
1087dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1097dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
1108c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}.
1118c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}
1128c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     */
1138c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    private boolean mSmoothScrollbarEnabled = true;
1148c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
1158c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    /**
116d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
11725a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     * layout which will check this variable and re-layout accordingly.
11825a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     */
119ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas    int mPendingScrollPosition = RecyclerView.NO_POSITION;
12025a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
12125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    /**
122d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
123d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * called.
124d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     */
1256e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    int mPendingScrollPositionOffset = INVALID_OFFSET;
126d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
12749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    private boolean mRecycleChildrenOnDetach;
12849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
1296e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar    SavedState mPendingSavedState = null;
13008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
131d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    /**
1321e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas     *  Re-used variable to keep anchor information on re-layout.
1331e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas     *  Anchor position and coordinate defines the reference point for LLM while doing a layout.
1341e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas     * */
1350194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    final AnchorInfo mAnchorInfo = new AnchorInfo();
136310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
137310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    /**
138e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik     * Stashed to avoid allocation, currently only used in #fill()
139e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik     */
140e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik    private final LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();
141e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik
142e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik    /**
1431e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik     * Number of items to prefetch when first coming on screen with new data.
1441e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik     */
145d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik    private int mInitialPrefetchItemCount = 2;
1461e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik
1471e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    /**
1487dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Creates a vertical LinearLayoutManager
1497dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
1507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param context Current context, will be used to access resources.
1517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
1527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public LinearLayoutManager(Context context) {
153a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard        this(context, RecyclerView.DEFAULT_ORIENTATION, false);
1547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
1557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
1577dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param context       Current context, will be used to access resources.
1587dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param orientation   Layout orientation. Should be {@link #HORIZONTAL} or {@link
1597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *                      #VERTICAL}.
16094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * @param reverseLayout When set to true, layouts from end to start.
1617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
162a8e9d2739e676eb27f2570b3db278e183ec327f2Aurimas Liutikas    public LinearLayoutManager(Context context, @RecyclerView.Orientation int orientation,
163a8e9d2739e676eb27f2570b3db278e183ec327f2Aurimas Liutikas            boolean reverseLayout) {
1647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        setOrientation(orientation);
1657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        setReverseLayout(reverseLayout);
1667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
1677dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
1690194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     * Constructor used when layout manager is set in XML by RecyclerView attribute
1700194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     * "layoutManager". Defaults to vertical orientation.
1710194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     *
172ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @attr ref androidx.recyclerview.R.styleable#RecyclerView_android_orientation
173ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @attr ref androidx.recyclerview.R.styleable#RecyclerView_reverseLayout
174ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @attr ref androidx.recyclerview.R.styleable#RecyclerView_stackFromEnd
1750194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta     */
1760194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
1771e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            int defStyleRes) {
1780194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
1790194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setOrientation(properties.orientation);
1800194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setReverseLayout(properties.reverseLayout);
1810194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta        setStackFromEnd(properties.stackFromEnd);
18231df934a5cd4bcaac517f313a9fc1a2639beaf9fshepshapard    }
18331df934a5cd4bcaac517f313a9fc1a2639beaf9fshepshapard
18431df934a5cd4bcaac517f313a9fc1a2639beaf9fshepshapard    @Override
18531df934a5cd4bcaac517f313a9fc1a2639beaf9fshepshapard    public boolean isAutoMeasureEnabled() {
18631df934a5cd4bcaac517f313a9fc1a2639beaf9fshepshapard        return true;
1870194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    }
1880194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta
1890194ed84ad6f1d3d489db52b9431fa93a7697b50Deepanshu Gupta    /**
1907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@inheritDoc}
1917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
1927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
193ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
194ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
1957dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                ViewGroup.LayoutParams.WRAP_CONTENT);
1967dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
1977dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
19849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    /**
1995f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * Returns whether LayoutManager will recycle its children when it is detached from
20049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * RecyclerView.
20149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     *
2025f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * @return true if LayoutManager will recycle its children when it is detached from
20349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * RecyclerView.
20449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     */
20549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    public boolean getRecycleChildrenOnDetach() {
20649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        return mRecycleChildrenOnDetach;
20749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    }
20849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
20949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    /**
2105f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * Set whether LayoutManager will recycle its children when it is detached from
21149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * RecyclerView.
21249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * <p>
21349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * If you are using a {@link RecyclerView.RecycledViewPool}, it might be a good idea to set
214c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas     * this flag to <code>true</code> so that views will be available to other RecyclerViews
21549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * immediately.
21649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * <p>
21749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * Note that, setting this flag will result in a performance drop if RecyclerView
21849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * is restored.
21949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     *
22049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     * @param recycleChildrenOnDetach Whether children should be recycled in detach or not.
22149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar     */
22249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    public void setRecycleChildrenOnDetach(boolean recycleChildrenOnDetach) {
22349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        mRecycleChildrenOnDetach = recycleChildrenOnDetach;
22449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    }
22549c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
22649c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    @Override
22749c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
22849c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        super.onDetachedFromWindow(view, recycler);
22949c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        if (mRecycleChildrenOnDetach) {
23049c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            removeAndRecycleAllViews(recycler);
23149c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar            recycler.clear();
23249c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar        }
23349c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar    }
23449c83b12201dde5b93d4eca3d44478e0c967a2e6Yigit Boyar
23508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    @Override
236a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
237a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        super.onInitializeAccessibilityEvent(event);
238a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        if (getChildCount() > 0) {
23914d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas            event.setFromIndex(findFirstVisibleItemPosition());
24014d02ef06479168249fdfeea47bc105d05e88749Aurimas Liutikas            event.setToIndex(findLastVisibleItemPosition());
241a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar        }
242a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    }
243a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar
244a910619e83d0052e1d81aa5fe532821a2f99d76cYigit Boyar    @Override
24508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    public Parcelable onSaveInstanceState() {
24608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        if (mPendingSavedState != null) {
24708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            return new SavedState(mPendingSavedState);
24808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
24908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        SavedState state = new SavedState();
25008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        if (getChildCount() > 0) {
251ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar            ensureLayoutState();
25208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            boolean didLayoutFromEnd = mLastStackFromEnd ^ mShouldReverseLayout;
25308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            state.mAnchorLayoutFromEnd = didLayoutFromEnd;
25408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            if (didLayoutFromEnd) {
255668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                final View refChild = getChildClosestToEnd();
2561e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                state.mAnchorOffset = mOrientationHelper.getEndAfterPadding()
2571e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        - mOrientationHelper.getDecoratedEnd(refChild);
25808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar                state.mAnchorPosition = getPosition(refChild);
25908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            } else {
260668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar                final View refChild = getChildClosestToStart();
26108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar                state.mAnchorPosition = getPosition(refChild);
2621e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                state.mAnchorOffset = mOrientationHelper.getDecoratedStart(refChild)
2631e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        - mOrientationHelper.getStartAfterPadding();
26408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            }
26508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        } else {
26675b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar            state.invalidateAnchor();
26708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
26808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        return state;
26908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    }
27008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
27108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    @Override
27208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    public void onRestoreInstanceState(Parcelable state) {
27308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        if (state instanceof SavedState) {
27408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mPendingSavedState = (SavedState) state;
27508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            requestLayout();
27608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            if (DEBUG) {
27708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar                Log.d(TAG, "loaded saved state");
27808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            }
27908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        } else if (DEBUG) {
28008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            Log.d(TAG, "invalid saved state class");
28108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
28208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    }
28308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
2847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
2857dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @return true if {@link #getOrientation()} is {@link #HORIZONTAL}
2867dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
2877dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
2887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public boolean canScrollHorizontally() {
2897dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return mOrientation == HORIZONTAL;
2907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
2917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
2927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
2937dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @return true if {@link #getOrientation()} is {@link #VERTICAL}
2947dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
2957dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
2967dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public boolean canScrollVertically() {
2977dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return mOrientation == VERTICAL;
2987dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
2997dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3007dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
3017dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Compatibility support for {@link android.widget.AbsListView#setStackFromBottom(boolean)}
3027dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
3037dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public void setStackFromEnd(boolean stackFromEnd) {
3040bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3058edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar        if (mStackFromEnd == stackFromEnd) {
3068edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar            return;
3078edcb0bdeaba6931f9d8154f0c81f57da7ddab2aYigit Boyar        }
3087dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        mStackFromEnd = stackFromEnd;
3097dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        requestLayout();
3107dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3117dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3127dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public boolean getStackFromEnd() {
3137dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return mStackFromEnd;
3147dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3157dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3167dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
317c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas     * Returns the current orientation of the layout.
3187dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
319c47c04733b86048a31a2419af32a5f8df01d4602Andrew Solovay     * @return Current orientation,  either {@link #HORIZONTAL} or {@link #VERTICAL}
3207dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @see #setOrientation(int)
3217dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
322a8e9d2739e676eb27f2570b3db278e183ec327f2Aurimas Liutikas    @RecyclerView.Orientation
3237dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public int getOrientation() {
3247dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return mOrientation;
3257dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3267dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3277dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
328ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * Sets the orientation of the layout. {@link LinearLayoutManager}
3297dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * will do its best to keep scroll position.
3307dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
3317dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
3327dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
333a8e9d2739e676eb27f2570b3db278e183ec327f2Aurimas Liutikas    public void setOrientation(@RecyclerView.Orientation int orientation) {
3347dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (orientation != HORIZONTAL && orientation != VERTICAL) {
33594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            throw new IllegalArgumentException("invalid orientation:" + orientation);
3367dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
337a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard
3380bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
339a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard
340a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard        if (orientation != mOrientation || mOrientationHelper == null) {
341a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mOrientationHelper =
342a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard                    OrientationHelper.createOrientationHelper(this, orientation);
343a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mAnchorInfo.mOrientationHelper = mOrientationHelper;
344a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mOrientation = orientation;
345a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            requestLayout();
3467dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
3477dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3487dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3497dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
3507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Calculates the view layout order. (e.g. from end to start or start to end)
3517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * RTL layout support is applied automatically. So if layout is RTL and
3527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
3537dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
3547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private void resolveShouldLayoutReverse() {
3557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        // A == B is the same result, but we rather keep it readable
356d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (mOrientation == VERTICAL || !isLayoutRTL()) {
3577dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            mShouldReverseLayout = mReverseLayout;
3587dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
3597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            mShouldReverseLayout = !mReverseLayout;
3607dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
3617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3627dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3637dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
3647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Returns if views are laid out from the opposite direction of the layout.
3657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
3667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @return If layout is reversed or not.
367c47c04733b86048a31a2419af32a5f8df01d4602Andrew Solovay     * @see #setReverseLayout(boolean)
3687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
3697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public boolean getReverseLayout() {
3707dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return mReverseLayout;
3717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3727dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3737dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
3747dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Used to reverse item traversal and layout order.
3757dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * This behaves similar to the layout change for RTL views. When set to true, first item is
37694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * laid out at the end of the UI, second item is laid out before it etc.
3777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
3787dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * For horizontal layouts, it depends on the layout direction.
379ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * When set to true, If {@link RecyclerView} is LTR, than it will
380ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * layout from RTL, if {@link RecyclerView}} is RTL, it will layout
3817dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * from LTR.
3827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
3837dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * If you are looking for the exact same behavior of
3847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@link android.widget.AbsListView#setStackFromBottom(boolean)}, use
3857dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@link #setStackFromEnd(boolean)}
3867dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
3877dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    public void setReverseLayout(boolean reverseLayout) {
3880bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        assertNotInLayoutOrScroll(null);
3897dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (reverseLayout == mReverseLayout) {
3907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return;
3917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
3927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        mReverseLayout = reverseLayout;
3937dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        requestLayout();
3947dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
3957dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
3960447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    /**
3970447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     * {@inheritDoc}
3980447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     */
3990447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    @Override
4000447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    public View findViewByPosition(int position) {
401d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        final int childCount = getChildCount();
402d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (childCount == 0) {
403d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            return null;
404d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
405d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        final int firstChild = getPosition(getChildAt(0));
406d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        final int viewPosition = position - firstChild;
407d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (viewPosition >= 0 && viewPosition < childCount) {
408e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            final View child = getChildAt(viewPosition);
409e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (getPosition(child) == position) {
410e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return child; // in pre-layout, this may not match
411e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
412d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
413e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // fallback to traversal. This might be necessary in pre-layout.
414e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        return super.findViewByPosition(position);
415d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
4167dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
4177dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
418565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * <p>Returns the amount of extra space that should be laid out by LayoutManager.</p>
419565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     *
420ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * <p>By default, {@link LinearLayoutManager} lays out 1 extra page
421565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * of items while smooth scrolling and 0 otherwise. You can override this method to implement
422565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * your custom layout pre-cache logic.</p>
423565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     *
424565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * <p><strong>Note:</strong>Laying out invisible elements generally comes with significant
425565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * performance cost. It's typically only desirable in places like smooth scrolling to an unknown
426565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * location, where 1) the extra content helps LinearLayoutManager know in advance when its
427565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * target is approaching, so it can decelerate early and smoothly and 2) while motion is
428565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * continuous.</p>
429565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     *
430565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * <p>Extending the extra layout space is especially expensive if done while the user may change
431565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * scrolling direction. Changing direction will cause the extra layout space to swap to the
432565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * opposite side of the viewport, incurring many rebinds/recycles, unless the cache is large
433565b7cf4798c21d54a3a5af12933400c72fb3885Chris Craik     * enough to handle it.</p>
4340447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     *
4350447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     * @return The extra space that should be laid out (in pixels).
4360447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     */
4370447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    protected int getExtraLayoutSpace(RecyclerView.State state) {
4380447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        if (state.hasTargetScrollPosition()) {
4390447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            return mOrientationHelper.getTotalSpace();
4400447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        } else {
4410447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            return 0;
4420447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        }
4430447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    }
4440447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar
4450447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    @Override
446d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
4470447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            int position) {
4480447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        LinearSmoothScroller linearSmoothScroller =
449c587f7dba5a337169e854e235da59f595255d6ccAga Madurska                new LinearSmoothScroller(recyclerView.getContext());
4500447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        linearSmoothScroller.setTargetPosition(position);
4510447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        startSmoothScroll(linearSmoothScroller);
4520447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    }
4530447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar
454c587f7dba5a337169e854e235da59f595255d6ccAga Madurska    @Override
4550447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    public PointF computeScrollVectorForPosition(int targetPosition) {
4560447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        if (getChildCount() == 0) {
4570447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            return null;
4580447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        }
4590447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        final int firstChildPos = getPosition(getChildAt(0));
4600447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        final int direction = targetPosition < firstChildPos != mShouldReverseLayout ? -1 : 1;
4610447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        if (mOrientation == HORIZONTAL) {
4620447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            return new PointF(direction, 0);
4630447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        } else {
4640447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            return new PointF(0, direction);
4650447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        }
4660447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    }
4670447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar
4680447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar    /**
4697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@inheritDoc}
4707dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
4717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
472d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
473d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // layout algorithm:
474d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // 1) by checking children and other variables, find an anchor coordinate and an anchor
475d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        //  item position.
476d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // 2) fill towards start, stacking from bottom
477d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // 3) fill towards end, stacking from top
478d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // 4) scroll to fulfill requirements like stack from bottom.
47994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        // create layout state
480b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        if (DEBUG) {
481b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            Log.d(TAG, "is pre layout:" + state.isPreLayout());
482b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
483ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        if (mPendingSavedState != null || mPendingScrollPosition != RecyclerView.NO_POSITION) {
4843d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev            if (state.getItemCount() == 0) {
4853d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev                removeAndRecycleAllViews(recycler);
4863d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev                return;
4873d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev            }
4883d8453880afb3e32c4c59c52b8b580f91d78b29fVladislav Kaznacheev        }
489b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
490b8403301bbec29129730f6cce3fe2fa3ee8e1e0bYigit Boyar            mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
49108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
492b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
49394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        ensureLayoutState();
494c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        mLayoutState.mRecycle = false;
495d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // resolve layout direction
4967dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        resolveShouldLayoutReverse();
4977dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
498151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri        final View focused = getFocusedChild();
499ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        if (!mAnchorInfo.mValid || mPendingScrollPosition != RecyclerView.NO_POSITION
5001e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                || mPendingSavedState != null) {
5019aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.reset();
5029aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.mLayoutFromEnd = mShouldReverseLayout ^ mStackFromEnd;
5039aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            // calculate anchor position and coordinate
5049aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            updateAnchorInfoForLayout(recycler, state, mAnchorInfo);
5059aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.mValid = true;
506151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri        } else if (focused != null && (mOrientationHelper.getDecoratedStart(focused)
507151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri                        >= mOrientationHelper.getEndAfterPadding()
508151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri                || mOrientationHelper.getDecoratedEnd(focused)
509151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri                <= mOrientationHelper.getStartAfterPadding())) {
510151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // This case relates to when the anchor child is the focused view and due to layout
511151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // shrinking the focused view fell outside the viewport, e.g. when soft keyboard shows
512151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // up after tapping an EditText which shrinks RV causing the focused view (The tapped
513151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // EditText which is the anchor child) to get kicked out of the screen. Will update the
514151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // anchor coordinate in order to make sure that the focused view is laid out. Otherwise,
515151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // the available space in layoutState will be calculated as negative preventing the
516151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // focused view from being laid out in fill.
517151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // Note that we won't update the anchor position between layout passes (refer to
518151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // TestResizingRelayoutWithAutoMeasure), which happens if we were to call
519151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // updateAnchorInfoForLayout for an anchor that's not the focused view (e.g. a reference
520151e43e7057619d714bc0f91ac7e2139ee334058Keyvan Amiri            // child which can change between layout passes).
521a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mAnchorInfo.assignFromViewAndKeepVisibleRect(focused, getPosition(focused));
5229aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        }
523310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (DEBUG) {
524310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            Log.d(TAG, "Anchor info:" + mAnchorInfo);
5257dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
526d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
527310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // LLM may decide to layout items for "extra" pixels to account for scrolling target,
528310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // caching or predictive animations.
529e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar        int extraForStart;
530e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar        int extraForEnd;
5310447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        final int extra = getExtraLayoutSpace(state);
532baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        // If the previous scroll delta was less than zero, the extra space should be laid out
533baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        // at the start. Otherwise, it should be at the end.
534baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        if (mLayoutState.mLastScrollDelta >= 0) {
5350447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            extraForEnd = extra;
5360447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            extraForStart = 0;
5370447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        } else {
5380447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            extraForStart = extra;
5390447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            extraForEnd = 0;
5400447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        }
541c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar        extraForStart += mOrientationHelper.getStartAfterPadding();
542c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar        extraForEnd += mOrientationHelper.getEndPadding();
543ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        if (state.isPreLayout() && mPendingScrollPosition != RecyclerView.NO_POSITION
5441e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                && mPendingScrollPositionOffset != INVALID_OFFSET) {
545c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            // if the child is visible and we are going to move it around, we should layout
546c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            // extra items in the opposite direction to make sure new items animate nicely
547c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            // instead of just fading in
548c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            final View existing = findViewByPosition(mPendingScrollPosition);
549c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            if (existing != null) {
550c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                final int current;
551c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                final int upcomingOffset;
552c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                if (mShouldReverseLayout) {
5531e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    current = mOrientationHelper.getEndAfterPadding()
5541e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            - mOrientationHelper.getDecoratedEnd(existing);
555c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                    upcomingOffset = current - mPendingScrollPositionOffset;
556c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                } else {
557c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                    current = mOrientationHelper.getDecoratedStart(existing)
558c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                            - mOrientationHelper.getStartAfterPadding();
559c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                    upcomingOffset = mPendingScrollPositionOffset - current;
560c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                }
561c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                if (upcomingOffset > 0) {
562c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                    extraForStart += upcomingOffset;
563c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                } else {
564c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                    extraForEnd -= upcomingOffset;
565c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar                }
566c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            }
567c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        }
568e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar        int startOffset;
569e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar        int endOffset;
570f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar        final int firstLayoutDirection;
571f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar        if (mAnchorInfo.mLayoutFromEnd) {
5721e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
5731e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    : LayoutState.ITEM_DIRECTION_HEAD;
574f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar        } else {
5751e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
5761e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    : LayoutState.ITEM_DIRECTION_TAIL;
577f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar        }
578f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar
579f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar        onAnchorReady(recycler, state, mAnchorInfo, firstLayoutDirection);
580c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        detachAndScrapAttachedViews(recycler);
581f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        mLayoutState.mInfinite = resolveIsInfinite();
58218ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar        mLayoutState.mIsPreLayout = state.isPreLayout();
583310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (mAnchorInfo.mLayoutFromEnd) {
584e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar            // fill towards start
585310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillStart(mAnchorInfo);
58694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mExtra = extraForStart;
58794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            fill(recycler, mLayoutState, state, false);
58894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            startOffset = mLayoutState.mOffset;
5891f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            final int firstElement = mLayoutState.mCurrentPosition;
590c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            if (mLayoutState.mAvailable > 0) {
591c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar                extraForEnd += mLayoutState.mAvailable;
592c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            }
593e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar            // fill towards end
594310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillEnd(mAnchorInfo);
59594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mExtra = extraForEnd;
59694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
59794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            fill(recycler, mLayoutState, state, false);
59894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            endOffset = mLayoutState.mOffset;
5991f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar
6001f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            if (mLayoutState.mAvailable > 0) {
6011f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                // end could not consume all. add more items towards start
6021f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                extraForStart = mLayoutState.mAvailable;
6031f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                updateLayoutStateToFillStart(firstElement, startOffset);
6041f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                mLayoutState.mExtra = extraForStart;
6051f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                fill(recycler, mLayoutState, state, false);
6061f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                startOffset = mLayoutState.mOffset;
6071f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            }
608e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar        } else {
609e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar            // fill towards end
610310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillEnd(mAnchorInfo);
61194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mExtra = extraForEnd;
61294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            fill(recycler, mLayoutState, state, false);
61394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            endOffset = mLayoutState.mOffset;
6141f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            final int lastElement = mLayoutState.mCurrentPosition;
615c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            if (mLayoutState.mAvailable > 0) {
616c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar                extraForStart += mLayoutState.mAvailable;
617c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            }
618e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar            // fill towards start
619310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillStart(mAnchorInfo);
62094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mExtra = extraForStart;
62194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
62294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            fill(recycler, mLayoutState, state, false);
62394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            startOffset = mLayoutState.mOffset;
6241f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar
6251f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            if (mLayoutState.mAvailable > 0) {
6261f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                extraForEnd = mLayoutState.mAvailable;
6271f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                // start could not consume all it should. add more items towards end
6281f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                updateLayoutStateToFillEnd(lastElement, endOffset);
6291f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                mLayoutState.mExtra = extraForEnd;
6301f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                fill(recycler, mLayoutState, state, false);
6311f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar                endOffset = mLayoutState.mOffset;
6321f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar            }
633d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
634e679158cd5f7469d49918c80e6cfaf4ba35d6ea6Yigit Boyar
635d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        // changes may cause gaps on the UI, try to fix them.
636310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // TODO we can probably avoid this if neither stackFromEnd/reverseLayout/RTL values have
637310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // changed
63825a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar        if (getChildCount() > 0) {
639d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // because layout from end may be changed by scroll to position
640d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // we re-calculate it.
641d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // find which side we should check for gaps.
642d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            if (mShouldReverseLayout ^ mStackFromEnd) {
643b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                int fixOffset = fixLayoutEndGap(endOffset, recycler, state, true);
644b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                startOffset += fixOffset;
645b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                endOffset += fixOffset;
646b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                fixOffset = fixLayoutStartGap(startOffset, recycler, state, false);
647b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                startOffset += fixOffset;
648b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                endOffset += fixOffset;
64925a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar            } else {
650b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                int fixOffset = fixLayoutStartGap(startOffset, recycler, state, true);
651b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                startOffset += fixOffset;
652b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                endOffset += fixOffset;
653b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                fixOffset = fixLayoutEndGap(endOffset, recycler, state, false);
654b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                startOffset += fixOffset;
655b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                endOffset += fixOffset;
65625a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar            }
65725a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar        }
658310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        layoutForPredictiveAnimations(recycler, state, startOffset, endOffset);
659310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (!state.isPreLayout()) {
660310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mOrientationHelper.onLayoutComplete();
6619aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        } else {
6629aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mAnchorInfo.reset();
663310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
664310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        mLastStackFromEnd = mStackFromEnd;
665310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (DEBUG) {
666310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            validateChildOrder();
667310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
668310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
66925a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
6708cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    @Override
6718cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    public void onLayoutCompleted(RecyclerView.State state) {
6728cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        super.onLayoutCompleted(state);
6738cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        mPendingSavedState = null; // we don't need this anymore
674ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        mPendingScrollPosition = RecyclerView.NO_POSITION;
6758cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
6769aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        mAnchorInfo.reset();
6778cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar    }
6788cf399b2e813234a1a603df3575c2dcdfa38dc9eYigit Boyar
679310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    /**
680b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar     * Method called when Anchor position is decided. Extending class can setup accordingly or
681b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar     * even update anchor info if necessary.
682f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar     * @param recycler The recycler for the layout
683f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar     * @param state The layout state
684f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar     * @param anchorInfo The mutable POJO that keeps the position and offset.
685f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar     * @param firstLayoutItemDirection The direction of the first layout filling in terms of adapter
686f7f1c1ef2a0e0696fbfa8065ac88cd1f8dd39623Yigit Boyar     *                                 indices.
687b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar     */
688cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
6891e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            AnchorInfo anchorInfo, int firstLayoutItemDirection) {
690b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    }
691b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar
692b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    /**
693310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * If necessary, layouts new items for predictive animations
694310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     */
695310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    private void layoutForPredictiveAnimations(RecyclerView.Recycler recycler,
6969c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            RecyclerView.State state, int startOffset,
6979c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            int endOffset) {
698b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        // If there are scrap children that we did not layout, we need to find where they did go
699b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        // and layout them accordingly so that animations can work as expected.
700b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        // This case may happen if new views are added or an existing view expands and pushes
701b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        // another view out of bounds.
702b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (!state.willRunPredictiveAnimations() ||  getChildCount() == 0 || state.isPreLayout()
703b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                || !supportsPredictiveItemAnimations()) {
704310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return;
705310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
706310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // to make the logic simpler, we calculate the size of children and call fill.
707310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        int scrapExtraStart = 0, scrapExtraEnd = 0;
708310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        final List<RecyclerView.ViewHolder> scrapList = recycler.getScrapList();
709310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        final int scrapSize = scrapList.size();
710310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        final int firstChildPos = getPosition(getChildAt(0));
711310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        for (int i = 0; i < scrapSize; i++) {
712310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            RecyclerView.ViewHolder scrap = scrapList.get(i);
713888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            if (scrap.isRemoved()) {
714888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                continue;
715888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            }
716115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar            final int position = scrap.getLayoutPosition();
717310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            final int direction = position < firstChildPos != mShouldReverseLayout
718310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    ? LayoutState.LAYOUT_START : LayoutState.LAYOUT_END;
719310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (direction == LayoutState.LAYOUT_START) {
720310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                scrapExtraStart += mOrientationHelper.getDecoratedMeasurement(scrap.itemView);
721310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            } else {
722310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                scrapExtraEnd += mOrientationHelper.getDecoratedMeasurement(scrap.itemView);
723b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
724310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
725b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
726310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (DEBUG) {
727310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            Log.d(TAG, "for unused scrap, decided to add " + scrapExtraStart
728310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    + " towards start and " + scrapExtraEnd + " towards end");
729310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
730310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        mLayoutState.mScrapList = scrapList;
731310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (scrapExtraStart > 0) {
732310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            View anchor = getChildClosestToStart();
733310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillStart(getPosition(anchor), startOffset);
734310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mLayoutState.mExtra = scrapExtraStart;
735310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mLayoutState.mAvailable = 0;
736888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            mLayoutState.assignPositionFromScrapList();
737310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            fill(recycler, mLayoutState, state, false);
738310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
739310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
740310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (scrapExtraEnd > 0) {
741310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            View anchor = getChildClosestToEnd();
742310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            updateLayoutStateToFillEnd(getPosition(anchor), endOffset);
743310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mLayoutState.mExtra = scrapExtraEnd;
744310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mLayoutState.mAvailable = 0;
745888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            mLayoutState.assignPositionFromScrapList();
746310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            fill(recycler, mLayoutState, state, false);
747310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
748310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        mLayoutState.mScrapList = null;
749310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
750310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
751cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private void updateAnchorInfoForLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
7521e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            AnchorInfo anchorInfo) {
753310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (updateAnchorFromPendingData(state, anchorInfo)) {
754b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            if (DEBUG) {
755310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                Log.d(TAG, "updated anchor info from pending information");
756b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
757310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return;
758310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
759310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
760cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        if (updateAnchorFromChildren(recycler, state, anchorInfo)) {
761310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (DEBUG) {
762310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                Log.d(TAG, "updated anchor info from existing children");
763b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
764310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return;
765310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
766310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (DEBUG) {
767310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            Log.d(TAG, "deciding anchor info for fresh state");
768310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
769310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        anchorInfo.assignCoordinateFromPadding();
770310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0;
771310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
772b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
773310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    /**
774310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * Finds an anchor child from existing Views. Most of the time, this is the view closest to
775310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * start or end that has a valid position (e.g. not removed).
776310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * <p>
777310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * If a child has focus, it is given priority.
778310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     */
779cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private boolean updateAnchorFromChildren(RecyclerView.Recycler recycler,
7801e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            RecyclerView.State state, AnchorInfo anchorInfo) {
781310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (getChildCount() == 0) {
782310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return false;
783310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
784542f1260934df280985294eaef1ec8469863281fYigit Boyar        final View focused = getFocusedChild();
785542f1260934df280985294eaef1ec8469863281fYigit Boyar        if (focused != null && anchorInfo.isViewValidAsAnchor(focused, state)) {
786a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            anchorInfo.assignFromViewAndKeepVisibleRect(focused, getPosition(focused));
787310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return true;
788b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
789310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (mLastStackFromEnd != mStackFromEnd) {
790310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return false;
791310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
792cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        View referenceChild = anchorInfo.mLayoutFromEnd
793cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar                ? findReferenceChildClosestToEnd(recycler, state)
794cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar                : findReferenceChildClosestToStart(recycler, state);
795310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (referenceChild != null) {
796a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            anchorInfo.assignFromView(referenceChild, getPosition(referenceChild));
797ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar            // If all visible views are removed in 1 pass, reference child might be out of bounds.
798ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar            // If that is the case, offset it back to 0 so that we use these pre-layout children.
799ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar            if (!state.isPreLayout() && supportsPredictiveItemAnimations()) {
800ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                // validate this child is at least partially visible. if not, offset it to start
801ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                final boolean notVisible =
802ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                        mOrientationHelper.getDecoratedStart(referenceChild) >= mOrientationHelper
803ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                                .getEndAfterPadding()
804be9090704b5671c49f1e89cb7003f4744cd69918Yigit Boyar                                || mOrientationHelper.getDecoratedEnd(referenceChild)
805ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                                < mOrientationHelper.getStartAfterPadding();
806ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                if (notVisible) {
807245b9720dad47a694d16a1d0f48ad462bc27989fYigit Boyar                    anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd
808ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                            ? mOrientationHelper.getEndAfterPadding()
809ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                            : mOrientationHelper.getStartAfterPadding();
810ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar                }
811ff6a18ccc12673e67ae2b143de1bb27048824365Yigit Boyar            }
812310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return true;
813310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
814310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        return false;
815310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
816310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
817310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    /**
818310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * If there is a pending scroll position or saved states, updates the anchor info from that
819310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * data and returns true
820310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     */
821310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    private boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) {
822ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        if (state.isPreLayout() || mPendingScrollPosition == RecyclerView.NO_POSITION) {
823310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return false;
824310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
825310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // validate scroll position
826310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
827ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            mPendingScrollPosition = RecyclerView.NO_POSITION;
8286e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar            mPendingScrollPositionOffset = INVALID_OFFSET;
829310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (DEBUG) {
830310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                Log.e(TAG, "ignoring invalid scroll position " + mPendingScrollPosition);
831310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            }
832310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return false;
833310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
834310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
835310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // if child is visible, try to make it a reference child and ensure it is fully visible.
836310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // if child is not visible, align it depending on its virtual position.
837310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        anchorInfo.mPosition = mPendingScrollPosition;
838310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
839310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            // Anchor offset depends on how that child was laid out. Here, we update it
840310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            // according to our current view bounds
841310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
842310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (anchorInfo.mLayoutFromEnd) {
8431e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
8441e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        - mPendingSavedState.mAnchorOffset;
845310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            } else {
8461e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
8471e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + mPendingSavedState.mAnchorOffset;
848310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            }
849310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return true;
8506e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        }
851310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
852310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        if (mPendingScrollPositionOffset == INVALID_OFFSET) {
853310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            View child = findViewByPosition(mPendingScrollPosition);
854310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (child != null) {
855310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                final int childSize = mOrientationHelper.getDecoratedMeasurement(child);
856310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                if (childSize > mOrientationHelper.getTotalSpace()) {
857310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    // item does not fit. fix depending on layout direction
858310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.assignCoordinateFromPadding();
859310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    return true;
860310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                }
861310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                final int startGap = mOrientationHelper.getDecoratedStart(child)
862310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                        - mOrientationHelper.getStartAfterPadding();
863310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                if (startGap < 0) {
864310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding();
865310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.mLayoutFromEnd = false;
866310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    return true;
867310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                }
8681e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                final int endGap = mOrientationHelper.getEndAfterPadding()
8691e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        - mOrientationHelper.getDecoratedEnd(child);
870310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                if (endGap < 0) {
871310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding();
872310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.mLayoutFromEnd = true;
873310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    return true;
874310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                }
875310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd
876310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                        ? (mOrientationHelper.getDecoratedEnd(child) + mOrientationHelper
8779c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        .getTotalSpaceChange())
878310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                        : mOrientationHelper.getDecoratedStart(child);
879310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            } else { // item is not visible.
880310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                if (getChildCount() > 0) {
881310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    // get position of any child, does not matter
882310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    int pos = getPosition(getChildAt(0));
883310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    anchorInfo.mLayoutFromEnd = mPendingScrollPosition < pos
884310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                            == mShouldReverseLayout;
885310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                }
886310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                anchorInfo.assignCoordinateFromPadding();
887310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            }
888310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            return true;
889d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
890310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        // override layout from end values for consistency
891310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
892e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // if this changes, we should update prepareForDrop as well
893c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        if (mShouldReverseLayout) {
8941e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
8951e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    - mPendingScrollPositionOffset;
896c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        } else {
8971e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
8981e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + mPendingScrollPositionOffset;
899c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        }
900310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        return true;
901d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
902d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
903b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    /**
904b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar     * @return The final offset amount for children
905b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar     */
906b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler recycler,
907b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            RecyclerView.State state, boolean canOffsetChildren) {
908b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int gap = mOrientationHelper.getEndAfterPadding() - endOffset;
909b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int fixOffset = 0;
910d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (gap > 0) {
911b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            fixOffset = -scrollBy(-gap, recycler, state);
912d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        } else {
913b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            return 0; // nothing to fix
914d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
915b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        // move offset according to scroll amount
916b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        endOffset += fixOffset;
917d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (canOffsetChildren) {
918d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // re-calculate gap, see if we could fix it
919b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            gap = mOrientationHelper.getEndAfterPadding() - endOffset;
920d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            if (gap > 0) {
921d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar                mOrientationHelper.offsetChildren(gap);
922b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                return gap + fixOffset;
923d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            }
924d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
925b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        return fixOffset;
9267dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
9277dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
928b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    /**
929b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar     * @return The final offset amount for children
930b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar     */
931b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar    private int fixLayoutStartGap(int startOffset, RecyclerView.Recycler recycler,
932b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            RecyclerView.State state, boolean canOffsetChildren) {
933b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int gap = startOffset - mOrientationHelper.getStartAfterPadding();
934b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        int fixOffset = 0;
935d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (gap > 0) {
936d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // check if we should fix this gap.
937b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            fixOffset = -scrollBy(gap, recycler, state);
938d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        } else {
939b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            return 0; // nothing to fix
940d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
941b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        startOffset += fixOffset;
942d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        if (canOffsetChildren) {
943d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            // re-calculate gap, see if we could fix it
944b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            gap = startOffset - mOrientationHelper.getStartAfterPadding();
945d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            if (gap > 0) {
946d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar                mOrientationHelper.offsetChildren(-gap);
947b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                return fixOffset - gap;
948d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar            }
949d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        }
950b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        return fixOffset;
951d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
952d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
953310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    private void updateLayoutStateToFillEnd(AnchorInfo anchorInfo) {
954310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        updateLayoutStateToFillEnd(anchorInfo.mPosition, anchorInfo.mCoordinate);
955310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
956310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
95794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    private void updateLayoutStateToFillEnd(int itemPosition, int offset) {
95894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mAvailable = mOrientationHelper.getEndAfterPadding() - offset;
95994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD :
96094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                LayoutState.ITEM_DIRECTION_TAIL;
96194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mCurrentPosition = itemPosition;
96294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mLayoutDirection = LayoutState.LAYOUT_END;
96394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mOffset = offset;
964c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
965d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
966d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
967310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    private void updateLayoutStateToFillStart(AnchorInfo anchorInfo) {
968310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        updateLayoutStateToFillStart(anchorInfo.mPosition, anchorInfo.mCoordinate);
969310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
970310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
97194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    private void updateLayoutStateToFillStart(int itemPosition, int offset) {
97294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mAvailable = offset - mOrientationHelper.getStartAfterPadding();
97394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mCurrentPosition = itemPosition;
97494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL :
97594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                LayoutState.ITEM_DIRECTION_HEAD;
97694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mLayoutDirection = LayoutState.LAYOUT_START;
97794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mOffset = offset;
978c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
979d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
980d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
981d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
982b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    protected boolean isLayoutRTL() {
9837dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
9847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
9857dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
98694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    void ensureLayoutState() {
98794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        if (mLayoutState == null) {
988888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            mLayoutState = createLayoutState();
9897dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
9907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
9917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
9927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
993888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar     * Test overrides this to plug some tracking and verification.
994888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar     *
995888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar     * @return A new LayoutState
996888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar     */
997888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar    LayoutState createLayoutState() {
998888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        return new LayoutState();
999888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar    }
1000888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar
1001888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar    /**
1002d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * <p>Scroll the RecyclerView to make the position visible.</p>
1003d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     *
1004d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * <p>RecyclerView will scroll the minimum amount that is necessary to make the
1005d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * target position visible. If you are looking for a similar behavior to
1006d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * {@link android.widget.ListView#setSelection(int)} or
1007d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * {@link android.widget.ListView#setSelectionFromTop(int, int)}, use
1008d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * {@link #scrollToPositionWithOffset(int, int)}.</p>
100925a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     *
101025a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     * <p>Note that scroll position change will not be reflected until the next layout call.</p>
101125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     *
101225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     * @param position Scroll to this adapter position
1013d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * @see #scrollToPositionWithOffset(int, int)
101425a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar     */
101525a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
101625a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    public void scrollToPosition(int position) {
101725a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar        mPendingScrollPosition = position;
1018d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        mPendingScrollPositionOffset = INVALID_OFFSET;
101975b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        if (mPendingSavedState != null) {
102075b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar            mPendingSavedState.invalidateAnchor();
102175b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        }
102225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar        requestLayout();
102325a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
102425a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
102525a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    /**
1026c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * Scroll to the specified adapter position with the given offset from resolved layout
1027c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * start. Resolved layout start depends on {@link #getReverseLayout()},
1028c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * {@link ViewCompat#getLayoutDirection(android.view.View)} and {@link #getStackFromEnd()}.
1029c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * <p>
1030c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * For example, if layout is {@link #VERTICAL} and {@link #getStackFromEnd()} is true, calling
1031c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * <code>scrollToPositionWithOffset(10, 20)</code> will layout such that
1032c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * <code>item[10]</code>'s bottom is 20 pixels above the RecyclerView's bottom.
1033c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * <p>
1034c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * Note that scroll position change will not be reflected until the next layout call.
1035c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * <p>
1036c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
1037d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     *
1038d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * @param position Index (starting at 0) of the reference item.
1039d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * @param offset   The distance (in pixels) between the start edge of the item view and
1040d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     *                 start edge of the RecyclerView.
1041d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * @see #setReverseLayout(boolean)
1042d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     * @see #scrollToPosition(int)
1043d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar     */
1044d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    public void scrollToPositionWithOffset(int position, int offset) {
1045d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        mPendingScrollPosition = position;
1046d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        mPendingScrollPositionOffset = offset;
104775b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        if (mPendingSavedState != null) {
104875b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar            mPendingSavedState.invalidateAnchor();
104975b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        }
1050d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar        requestLayout();
1051d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    }
1052d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
1053d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar
1054d9746b39ccf730ebb2780fa0d6a5d4970c06076dYigit Boyar    /**
10557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@inheritDoc}
10567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
10577dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
1058d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
1059d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            RecyclerView.State state) {
10602aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (mOrientation == VERTICAL) {
10612aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return 0;
10622aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
1063d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return scrollBy(dx, recycler, state);
10647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
10657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
10667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
10677dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * {@inheritDoc}
10687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
10697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    @Override
1070d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
1071d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            RecyclerView.State state) {
10722aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (mOrientation == HORIZONTAL) {
10732aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return 0;
10742aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
1075d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return scrollBy(dy, recycler, state);
10767dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
10777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
107825a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1079d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeHorizontalScrollOffset(RecyclerView.State state) {
10808c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollOffset(state);
108125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
108225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
108325a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1084d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeVerticalScrollOffset(RecyclerView.State state) {
10858c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollOffset(state);
108625a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
108725a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
108825a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1089d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeHorizontalScrollExtent(RecyclerView.State state) {
10908c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollExtent(state);
109125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
109225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
109325a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1094d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeVerticalScrollExtent(RecyclerView.State state) {
10958c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollExtent(state);
109625a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
109725a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
109825a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1099d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeHorizontalScrollRange(RecyclerView.State state) {
11008c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollRange(state);
110125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
110225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
110325a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    @Override
1104d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public int computeVerticalScrollRange(RecyclerView.State state) {
11058c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return computeScrollRange(state);
11068c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    }
11078c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
11088c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    private int computeScrollOffset(RecyclerView.State state) {
1109d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
11108c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar            return 0;
11118c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        }
1112ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
1113d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollOffset(state, mOrientationHelper,
11146490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
11156490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
11166490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                this, mSmoothScrollbarEnabled, mShouldReverseLayout);
11178c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    }
11188c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
11198c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    private int computeScrollExtent(RecyclerView.State state) {
1120d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
1121d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar            return 0;
11228c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        }
1123ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
1124d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollExtent(state, mOrientationHelper,
11256490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
11266490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
11276490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                this,  mSmoothScrollbarEnabled);
11288c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    }
11298c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
11308c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    private int computeScrollRange(RecyclerView.State state) {
1131d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        if (getChildCount() == 0) {
11328c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar            return 0;
11338c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        }
1134ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
1135d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar        return ScrollbarHelper.computeScrollRange(state, mOrientationHelper,
11366490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
11376490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
11386490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                this, mSmoothScrollbarEnabled);
11398c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    }
11408c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
11418c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    /**
11428c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * When smooth scrollbar is enabled, the position and size of the scrollbar thumb is computed
11438c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * based on the number of visible pixels in the visible items. This however assumes that all
11448c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * list items have similar or equal widths or heights (depending on list orientation).
11458c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * If you use a list in which items have different dimensions, the scrollbar will change
11468c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * appearance as the user scrolls through the list. To avoid this issue,  you need to disable
11478c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * this property.
11488c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     *
11498c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * When smooth scrollbar is disabled, the position and size of the scrollbar thumb is based
11508c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * solely on the number of items in the adapter and the position of the visible items inside
11518c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * the adapter. This provides a stable scrollbar as the user navigates through a list of items
11528c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * with varying widths / heights.
11538c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     *
11548c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * @param enabled Whether or not to enable smooth scrollbar.
11558c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     *
11568c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * @see #setSmoothScrollbarEnabled(boolean)
11578c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     */
11588c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    public void setSmoothScrollbarEnabled(boolean enabled) {
11598c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        mSmoothScrollbarEnabled = enabled;
11608c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    }
11618c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar
11628c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    /**
11638c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * Returns the current state of the smooth scrollbar feature. It is enabled by default.
11648c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     *
11658c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * @return True if smooth scrollbar is enabled, false otherwise.
11668c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     *
11678c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     * @see #setSmoothScrollbarEnabled(boolean)
11688c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar     */
11698c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar    public boolean isSmoothScrollbarEnabled() {
11708c23e5d30a95b7807109db376d43a07a52e00802Yigit Boyar        return mSmoothScrollbarEnabled;
117125a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar    }
117225a1df3b5e7fcd875440ccf6b877cb280d63f418Yigit Boyar
117394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    private void updateLayoutState(int layoutDirection, int requiredSpace,
11740447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar            boolean canUseExistingSpace, RecyclerView.State state) {
1175f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        // If parent provides a hint, don't measure unlimited.
1176f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        mLayoutState.mInfinite = resolveIsInfinite();
117794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mExtra = getExtraLayoutSpace(state);
117894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mLayoutDirection = layoutDirection;
11793ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas        int scrollingOffset;
118094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        if (layoutDirection == LayoutState.LAYOUT_END) {
1181c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            mLayoutState.mExtra += mOrientationHelper.getEndPadding();
11827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            // get the first child in the direction we are going
1183668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            final View child = getChildClosestToEnd();
11847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            // the direction in which we are traversing children
118594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
118694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                    : LayoutState.ITEM_DIRECTION_TAIL;
118794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
118894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mOffset = mOrientationHelper.getDecoratedEnd(child);
11892aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            // calculate how much we can scroll without adding new children (independent of layout)
11903ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas            scrollingOffset = mOrientationHelper.getDecoratedEnd(child)
11912aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                    - mOrientationHelper.getEndAfterPadding();
11922aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
11937dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
1194668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            final View child = getChildClosestToStart();
1195c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar            mLayoutState.mExtra += mOrientationHelper.getStartAfterPadding();
119694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
119794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                    : LayoutState.ITEM_DIRECTION_HEAD;
119894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
119994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child);
12003ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas            scrollingOffset = -mOrientationHelper.getDecoratedStart(child)
12012aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                    + mOrientationHelper.getStartAfterPadding();
12022aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
120394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        mLayoutState.mAvailable = requiredSpace;
12042aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (canUseExistingSpace) {
12053ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas            mLayoutState.mAvailable -= scrollingOffset;
12062aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
12073ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas        mLayoutState.mScrollingOffset = scrollingOffset;
12082aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    }
12092aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
1210f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar    boolean resolveIsInfinite() {
1211f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar        return mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED
1212f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar                && mOrientationHelper.getEnd() == 0;
1213f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar    }
1214f3844451301cb14ca885e125cb27f108a834c386Yigit Boyar
1215945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik    void collectPrefetchPositionsForLayoutState(RecyclerView.State state, LayoutState layoutState,
12163104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik            LayoutPrefetchRegistry layoutPrefetchRegistry) {
1217ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        final int pos = layoutState.mCurrentPosition;
1218ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        if (pos >= 0 && pos < state.getItemCount()) {
12196425bbc0816bc5c2dbd14010d8dee4245d14fd1dChris Craik            layoutPrefetchRegistry.addPosition(pos, Math.max(0, layoutState.mScrollingOffset));
1220ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        }
1221ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
1222ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
12231e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    @Override
12241e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    public void collectInitialPrefetchPositions(int adapterItemCount,
12253104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik            LayoutPrefetchRegistry layoutPrefetchRegistry) {
12261e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        final boolean fromEnd;
12271e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        final int anchorPos;
12281e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
12291e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            // use restored state, since it hasn't been resolved yet
12301e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            fromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
12311e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            anchorPos = mPendingSavedState.mAnchorPosition;
12321e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        } else {
12331e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            resolveShouldLayoutReverse();
12341e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            fromEnd = mShouldReverseLayout;
1235ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            if (mPendingScrollPosition == RecyclerView.NO_POSITION) {
12361e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik                anchorPos = fromEnd ? adapterItemCount - 1 : 0;
12371e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            } else {
12381e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik                anchorPos = mPendingScrollPosition;
12391e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            }
12401e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        }
12411e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik
12421e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        final int direction = fromEnd
12431e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik                ? LayoutState.ITEM_DIRECTION_HEAD
12441e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik                : LayoutState.ITEM_DIRECTION_TAIL;
12451e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        int targetPos = anchorPos;
1246d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik        for (int i = 0; i < mInitialPrefetchItemCount; i++) {
12471e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            if (targetPos >= 0 && targetPos < adapterItemCount) {
12483104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik                layoutPrefetchRegistry.addPosition(targetPos, 0);
12491e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            } else {
12501e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik                break; // no more to prefetch
12511e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            }
12521e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik            targetPos += direction;
12531e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik        }
12541e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    }
12551e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik
12563104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik    /**
12573104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * Sets the number of items to prefetch in
12583104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)}, which defines
12593104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * how many inner items should be prefetched when this LayoutManager's RecyclerView
12603104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * is nested inside another RecyclerView.
12613104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12623104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * <p>Set this value to the number of items this inner LayoutManager will display when it is
12633104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * first scrolled into the viewport. RecyclerView will attempt to prefetch that number of items
12643104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * so they are ready, avoiding jank as the inner RecyclerView is scrolled into the viewport.</p>
12653104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12663104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * <p>For example, take a vertically scrolling RecyclerView with horizontally scrolling inner
12673104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * RecyclerViews. The rows always have 4 items visible in them (or 5 if not aligned). Passing
12683104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * <code>4</code> to this method for each inner RecyclerView's LinearLayoutManager will enable
12693104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * RecyclerView's prefetching feature to do create/bind work for 4 views within a row early,
12703104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * before it is scrolled on screen, instead of just the default 2.</p>
12713104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12723104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * <p>Calling this method does nothing unless the LayoutManager is in a RecyclerView
12733104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * nested in another RecyclerView.</p>
12743104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12753104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * <p class="note"><strong>Note:</strong> Setting this value to be larger than the number of
12763104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * views that will be visible in this view can incur unnecessary bind work, and an increase to
12773104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * the number of Views created and in active use.</p>
12783104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12793104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @param itemCount Number of items to prefetch
12803104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12813104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @see #isItemPrefetchEnabled()
1282d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik     * @see #getInitialPrefetchItemCount()
12833104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @see #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
12843104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     */
12851e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    public void setInitialPrefetchItemCount(int itemCount) {
1286d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik        mInitialPrefetchItemCount = itemCount;
12871e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    }
12881e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik
12893104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik    /**
12903104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * Gets the number of items to prefetch in
12913104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)}, which defines
12923104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * how many inner items should be prefetched when this LayoutManager's RecyclerView
12933104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * is nested inside another RecyclerView.
12943104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12953104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @see #isItemPrefetchEnabled()
12963104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @see #setInitialPrefetchItemCount(int)
12973104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @see #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
12983104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     *
12993104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     * @return number of items to prefetch.
13003104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik     */
1301d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik    public int getInitialPrefetchItemCount() {
1302d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik        return mInitialPrefetchItemCount;
1303d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik    }
1304d6696c2abea2771acd000c2269cf9113acc6c0a9Chris Craik
1305ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    @Override
13061e0a453dff8d7bb7a966d006541454c770d1ed05Chris Craik    public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
13073104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik            LayoutPrefetchRegistry layoutPrefetchRegistry) {
1308ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        int delta = (mOrientation == HORIZONTAL) ? dx : dy;
1309466d1f5850356125fd12c4f6f0032eb2d72f4ff1Chris Craik        if (getChildCount() == 0 || delta == 0) {
1310466d1f5850356125fd12c4f6f0032eb2d72f4ff1Chris Craik            // can't support this scroll, so don't bother prefetching
1311945dc1e8a9ee0b71e6b2454ccb3e61145d2132f5Chris Craik            return;
1312ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        }
1313ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
1314213c0aa34bc54fb1b540a040609f097a4e4f65faChris Craik        ensureLayoutState();
1315ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        final int layoutDirection = delta > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
1316ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        final int absDy = Math.abs(delta);
1317ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik        updateLayoutState(layoutDirection, absDy, true, state);
13183104d446bcf3da9ffb7a761fd30f0506c30f0cc9Chris Craik        collectPrefetchPositionsForLayoutState(state, mLayoutState, layoutPrefetchRegistry);
1319ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik    }
1320ec4b5429886bfe93707a85823cf40de107bd9dc6Chris Craik
1321061c3284cf284424ae084799dd7ba5c8d6d59faaYigit Boyar    int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
13222aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (getChildCount() == 0 || dy == 0) {
13232aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return 0;
13242aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
1325c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        mLayoutState.mRecycle = true;
132694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        ensureLayoutState();
132794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
13282aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        final int absDy = Math.abs(dy);
132994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        updateLayoutState(layoutDirection, absDy, true, state);
13303ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas        final int consumed = mLayoutState.mScrollingOffset
13313ebdce1f656e8f92d28c81a6951052e38d6abe07Aurimas Liutikas                + fill(recycler, mLayoutState, state, false);
13322aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (consumed < 0) {
13337dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            if (DEBUG) {
13342aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                Log.d(TAG, "Don't have any more elements to scroll");
13357dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
13362aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return 0;
13372aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
13382aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
13392aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        mOrientationHelper.offsetChildren(-scrolled);
13402aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (DEBUG) {
13412aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
13427dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
1343baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        mLayoutState.mLastScrollDelta = scrolled;
13442aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        return scrolled;
13457dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
13467dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
13470bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    @Override
13480bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    public void assertNotInLayoutOrScroll(String message) {
13490bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        if (mPendingSavedState == null) {
13500bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar            super.assertNotInLayoutOrScroll(message);
13510bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar        }
13520bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar    }
13530bdfd8728199045676f3ad6c6571e7080099716fYigit Boyar
13547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
13557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Recycles children between given indices.
13567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
13577dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param startIndex inclusive
13587dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param endIndex   exclusive
13597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
13607dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private void recycleChildren(RecyclerView.Recycler recycler, int startIndex, int endIndex) {
13617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (startIndex == endIndex) {
13627dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return;
13637dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
13647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (DEBUG) {
13657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            Log.d(TAG, "Recycling " + Math.abs(startIndex - endIndex) + " items");
13667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
13677dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (endIndex > startIndex) {
13687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = endIndex - 1; i >= startIndex; i--) {
13697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                removeAndRecycleViewAt(i, recycler);
13707dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
13717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
13727dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = startIndex; i > endIndex; i--) {
13737dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                removeAndRecycleViewAt(i, recycler);
13747dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
13757dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
13767dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
13777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
13787dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
13797dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Recycles views that went out of bounds after scrolling towards the end of the layout.
13804510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar     * <p>
13814510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar     * Checks both layout position and visible position to guarantee that the view is not visible.
13827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
1383ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @param recycler Recycler instance of {@link RecyclerView}
13847dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param dt       This can be used to add additional padding to the visible area. This is used
1385e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar     *                 to detect children that will go out of bounds after scrolling, without
1386e05fbd9cfe05496e82a3abe19e07e8745985e9a5Yigit Boyar     *                 actually moving them.
13877dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
13887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private void recycleViewsFromStart(RecyclerView.Recycler recycler, int dt) {
13897dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (dt < 0) {
13907dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            if (DEBUG) {
13917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                Log.d(TAG, "Called recycle from start with a negative value. This might happen"
13927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                        + " during layout changes but may be sign of a bug");
13937dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
13947dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return;
13957dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
13963ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar        // ignore padding, ViewGroup may not clip children.
13973ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar        final int limit = dt;
13987dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        final int childCount = getChildCount();
13997dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (mShouldReverseLayout) {
14007dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = childCount - 1; i >= 0; i--) {
14017dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
14024510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                if (mOrientationHelper.getDecoratedEnd(child) > limit
14034510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
14044510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                    // stop here
14057dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    recycleChildren(recycler, childCount - 1, i);
14067dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    return;
14077dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
14087dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
14097dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
14107dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = 0; i < childCount; i++) {
14117dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
14124510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                if (mOrientationHelper.getDecoratedEnd(child) > limit
14134510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
14144510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                    // stop here
14157dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    recycleChildren(recycler, 0, i);
14167dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    return;
14177dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
14187dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
14197dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
14207dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
14217dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
14227dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
14237dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
14247dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Recycles views that went out of bounds after scrolling towards the start of the layout.
14254510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar     * <p>
14264510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar     * Checks both layout position and visible position to guarantee that the view is not visible.
14277dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
1428ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @param recycler Recycler instance of {@link RecyclerView}
14297dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param dt       This can be used to add additional padding to the visible area. This is used
14307dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *                 to detect children that will go out of bounds after scrolling, without
14317dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *                 actually moving them.
14327dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
14337dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private void recycleViewsFromEnd(RecyclerView.Recycler recycler, int dt) {
14347dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        final int childCount = getChildCount();
14357dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (dt < 0) {
14367dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            if (DEBUG) {
14377dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                Log.d(TAG, "Called recycle from end with a negative value. This might happen"
14387dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                        + " during layout changes but may be sign of a bug");
14397dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
14407dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return;
14417dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
14423ed05355fded55e438477b23a1864c3b6d129342Yigit Boyar        final int limit = mOrientationHelper.getEnd() - dt;
14437dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (mShouldReverseLayout) {
14447dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = 0; i < childCount; i++) {
14457dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
14464510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                if (mOrientationHelper.getDecoratedStart(child) < limit
14474510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) {
14484510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                    // stop here
14497dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    recycleChildren(recycler, 0, i);
14507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    return;
14517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
14527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
14537dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
14547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = childCount - 1; i >= 0; i--) {
14557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
14564510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                if (mOrientationHelper.getDecoratedStart(child) < limit
14574510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                        || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) {
14584510b5c24adad2b94df9b84c6b73f5534ffe9b57Yigit Boyar                    // stop here
14597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    recycleChildren(recycler, childCount - 1, i);
14607dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    return;
14617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
14627dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
14637dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
14647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
14657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
14667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
146794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * Helper method to call appropriate recycle method depending on current layout direction
14687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
14697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * @param recycler    Current recycler that is attached to RecyclerView
147094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * @param layoutState Current layout state. Right now, this object does not change but
14717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *                    we may consider moving it out of this view so passing around as a
147294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     *                    parameter for now, rather than accessing {@link #mLayoutState}
1473ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @see #recycleViewsFromStart(RecyclerView.Recycler, int)
1474ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @see #recycleViewsFromEnd(RecyclerView.Recycler, int)
1475ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * @see LinearLayoutManager.LayoutState#mLayoutDirection
14767dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
147794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar    private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {
14784143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        if (!layoutState.mRecycle || layoutState.mInfinite) {
1479c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar            return;
1480c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        }
148194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
148294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);
14837dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
148494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            recycleViewsFromStart(recycler, layoutState.mScrollingOffset);
14857dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
14867dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
14877dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
14887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
148994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * The magic functions :). Fills the given layout, defined by the layoutState. This is fairly
1490ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * independent from the rest of the {@link LinearLayoutManager}
14917dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * and with little change, can be made publicly available as a helper class.
14927dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
14930447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     * @param recycler        Current recycler that is attached to RecyclerView
149494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * @param layoutState     Configuration on how we should fill out the available space.
14950447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     * @param state           Context passed by the RecyclerView to control scroll steps.
14960447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar     * @param stopOnFocusable If true, filling stops in the first focusable new child
1497c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas     * @return Number of pixels that it added. Useful for scroll functions.
14987dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
1499b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
15006d35693091a469a1048e418171176a6792f5d015Yigit Boyar            RecyclerView.State state, boolean stopOnFocusable) {
15017dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        // max offset we should set is mFastScroll + available
150294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        final int start = layoutState.mAvailable;
1503c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
15047dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            // TODO ugly bug fix. should not happen
150594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            if (layoutState.mAvailable < 0) {
150694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                layoutState.mScrollingOffset += layoutState.mAvailable;
15077dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
150894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar            recycleByLayoutState(recycler, layoutState);
15097dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
151094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
1511e835a0f12bb6c6a7aa323cb9f58c29e2a9f232adChris Craik        LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
15124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
1513b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            layoutChunkResult.resetInternal();
1514ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            if (RecyclerView.VERBOSE_TRACING) {
15157c29d5250936de17de62ef295794ff98aa5d0dc4Chris Craik                TraceCompat.beginSection("LLM LayoutChunk");
15167c29d5250936de17de62ef295794ff98aa5d0dc4Chris Craik            }
1517b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            layoutChunk(recycler, state, layoutState, layoutChunkResult);
1518ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            if (RecyclerView.VERBOSE_TRACING) {
15197c29d5250936de17de62ef295794ff98aa5d0dc4Chris Craik                TraceCompat.endSection();
15207c29d5250936de17de62ef295794ff98aa5d0dc4Chris Craik            }
1521b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (layoutChunkResult.mFinished) {
1522b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                break;
1523b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
1524b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection;
15256d35693091a469a1048e418171176a6792f5d015Yigit Boyar            /**
15266d35693091a469a1048e418171176a6792f5d015Yigit Boyar             * Consume the available space if:
1527b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar             * * layoutChunk did not request to be ignored
15286d35693091a469a1048e418171176a6792f5d015Yigit Boyar             * * OR we are laying out scrap children
15296d35693091a469a1048e418171176a6792f5d015Yigit Boyar             * * OR we are not doing pre-layout
15306d35693091a469a1048e418171176a6792f5d015Yigit Boyar             */
1531b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (!layoutChunkResult.mIgnoreConsumed || mLayoutState.mScrapList != null
1532b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                    || !state.isPreLayout()) {
1533b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                layoutState.mAvailable -= layoutChunkResult.mConsumed;
1534b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                // we keep a separate remaining space because mAvailable is important for recycling
1535b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                remainingSpace -= layoutChunkResult.mConsumed;
1536b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
15377dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1538c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas            if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
1539b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                layoutState.mScrollingOffset += layoutChunkResult.mConsumed;
154094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                if (layoutState.mAvailable < 0) {
154194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                    layoutState.mScrollingOffset += layoutState.mAvailable;
15427dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
154394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                recycleByLayoutState(recycler, layoutState);
15447dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
1545b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (stopOnFocusable && layoutChunkResult.mFocusable) {
15462aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                break;
15472aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            }
15487dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
15497dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (DEBUG) {
15507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            validateChildOrder();
15517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
155294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        return start - layoutState.mAvailable;
15537dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
15547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
1555b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
1556b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            LayoutState layoutState, LayoutChunkResult result) {
1557b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        View view = layoutState.next(recycler);
1558b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (view == null) {
1559b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (DEBUG && layoutState.mScrapList == null) {
1560b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                throw new RuntimeException("received null view when unexpected");
1561b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1562b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            // if we are laying out views in scrap, this may return null which means there is
1563b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            // no more items to layout.
1564b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            result.mFinished = true;
1565b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            return;
1566b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
1567ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
1568b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (layoutState.mScrapList == null) {
1569b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (mShouldReverseLayout == (layoutState.mLayoutDirection
1570b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                    == LayoutState.LAYOUT_START)) {
1571b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                addView(view);
1572b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            } else {
1573b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                addView(view, 0);
1574b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1575b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        } else {
1576b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (mShouldReverseLayout == (layoutState.mLayoutDirection
1577b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                    == LayoutState.LAYOUT_START)) {
1578b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                addDisappearingView(view);
1579b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            } else {
1580b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                addDisappearingView(view, 0);
1581b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1582b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
1583b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        measureChildWithMargins(view, 0, 0);
1584b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view);
1585b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        int left, top, right, bottom;
1586b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (mOrientation == VERTICAL) {
1587b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (isLayoutRTL()) {
1588b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                right = getWidth() - getPaddingRight();
1589b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
1590b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            } else {
1591b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                left = getPaddingLeft();
1592b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
1593b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1594b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
1595b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                bottom = layoutState.mOffset;
1596b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                top = layoutState.mOffset - result.mConsumed;
1597b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            } else {
1598b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                top = layoutState.mOffset;
1599b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                bottom = layoutState.mOffset + result.mConsumed;
1600b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1601b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        } else {
1602b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            top = getPaddingTop();
1603b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
1604b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar
1605b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
1606b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                right = layoutState.mOffset;
1607b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                left = layoutState.mOffset - result.mConsumed;
1608b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            } else {
1609b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                left = layoutState.mOffset;
1610b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                right = layoutState.mOffset + result.mConsumed;
1611b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            }
1612b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
1613b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        // We calculate everything with View's bounding box (which includes decor and margins)
1614b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        // To calculate correct layout position, we subtract margins.
16155f538711872b050b93f49a5dcaff1753e0299449Dake Gu        layoutDecoratedWithMargins(view, left, top, right, bottom);
1616b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (DEBUG) {
1617b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:"
1618b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                    + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:"
1619b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar                    + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin));
1620b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
1621b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        // Consume the available space if the view is not removed OR changed
1622b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        if (params.isItemRemoved() || params.isItemChanged()) {
1623b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            result.mIgnoreConsumed = true;
1624b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
1625b174744db6a70f384d44caeb43e10854652e81b9Keyvan Amiri        result.mFocusable = view.hasFocusable();
1626b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    }
1627b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar
16284143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    @Override
16294143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    boolean shouldMeasureTwice() {
16304143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        return getHeightMode() != View.MeasureSpec.EXACTLY
16314143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                && getWidthMode() != View.MeasureSpec.EXACTLY
16324143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar                && hasFlexibleChildInBothOrientations();
16334143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar    }
16344143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
16352aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    /**
16362aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * Converts a focusDirection to orientation.
16372aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     *
16382aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
16392aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     *                       {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
16402aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     *                       {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
16412aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     *                       or 0 for not applicable
164294c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
164394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar     * is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
16442aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     */
1645f89e1b82c74b7b85df3a349340a643f62fc5bfa1Yigit Boyar    int convertFocusDirectionToLayoutDirection(int focusDirection) {
16462aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        switch (focusDirection) {
16472aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_BACKWARD:
1648d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                if (mOrientation == VERTICAL) {
1649d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
1650d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else if (isLayoutRTL()) {
1651d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
1652d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else {
1653d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
1654d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                }
16552aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_FORWARD:
1656d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                if (mOrientation == VERTICAL) {
1657d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
1658d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else if (isLayoutRTL()) {
1659d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_START;
1660d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                } else {
1661d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                    return LayoutState.LAYOUT_END;
1662d8d42d52f8ae53107ffa849b86496650182e24b8Yigit Boyar                }
16632aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_UP:
166494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                return mOrientation == VERTICAL ? LayoutState.LAYOUT_START
166594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                        : LayoutState.INVALID_LAYOUT;
16662aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_DOWN:
166794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                return mOrientation == VERTICAL ? LayoutState.LAYOUT_END
166894c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                        : LayoutState.INVALID_LAYOUT;
16692aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_LEFT:
167094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START
167194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                        : LayoutState.INVALID_LAYOUT;
16722aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            case View.FOCUS_RIGHT:
167394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END
167494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                        : LayoutState.INVALID_LAYOUT;
16752aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            default:
16762aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                if (DEBUG) {
16772aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                    Log.d(TAG, "Unknown focus request:" + focusDirection);
16782aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar                }
167994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar                return LayoutState.INVALID_LAYOUT;
16802aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
16812aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
16822aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    }
16832aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
16842aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    /**
16852aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * Convenience method to find the child closes to start. Caller should check it has enough
16862aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * children.
1687719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
16882aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * @return The child closes to start of the layout from user's perspective.
16892aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     */
1690668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar    private View getChildClosestToStart() {
1691668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        return getChildAt(mShouldReverseLayout ? getChildCount() - 1 : 0);
16922aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    }
16932aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
16942aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    /**
16952aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * Convenience method to find the child closes to end. Caller should check it has enough
16962aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * children.
1697719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
16982aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     * @return The child closes to end of the layout from user's perspective.
16992aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar     */
1700668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar    private View getChildClosestToEnd() {
1701668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar        return getChildAt(mShouldReverseLayout ? 0 : getChildCount() - 1);
17022aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    }
17032aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
17046490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    /**
17056490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * Convenience method to find the visible child closes to start. Caller should check if it has
17066490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * enough children.
17076490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     *
17086490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * @param completelyVisible Whether child should be completely visible or not
17096490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * @return The first visible child closest to start of the layout from user's perspective.
17106490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     */
17116490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    private View findFirstVisibleChildClosestToStart(boolean completelyVisible,
17126490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            boolean acceptPartiallyVisible) {
17136490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        if (mShouldReverseLayout) {
17146490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible,
17156490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    acceptPartiallyVisible);
17166490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        } else {
17176490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            return findOneVisibleChild(0, getChildCount(), completelyVisible,
17186490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    acceptPartiallyVisible);
17196490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        }
17206490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    }
17216490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar
17226490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    /**
17236490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * Convenience method to find the visible child closes to end. Caller should check if it has
17246490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * enough children.
17256490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     *
17266490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * @param completelyVisible Whether child should be completely visible or not
17276490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     * @return The first visible child closest to end of the layout from user's perspective.
17286490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar     */
17296490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    private View findFirstVisibleChildClosestToEnd(boolean completelyVisible,
17306490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            boolean acceptPartiallyVisible) {
17316490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        if (mShouldReverseLayout) {
17326490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            return findOneVisibleChild(0, getChildCount(), completelyVisible,
17336490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    acceptPartiallyVisible);
17346490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        } else {
17356490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible,
17366490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar                    acceptPartiallyVisible);
17376490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        }
17386490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    }
17396490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar
1740719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1741719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1742719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Among the children that are suitable to be considered as an anchor child, returns the one
1743719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * closest to the end of the layout.
1744719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * <p>
1745719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Due to ambiguous adapter updates or children being removed, some children's positions may be
1746719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * invalid. This method is a best effort to find a position within adapter bounds if possible.
17478a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar     * <p>
17488a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar     * It also prioritizes children that are within the visible bounds.
1749719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return A View that can be used an an anchor View.
1750719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1751cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private View findReferenceChildClosestToEnd(RecyclerView.Recycler recycler,
17521e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            RecyclerView.State state) {
1753cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        return mShouldReverseLayout ? findFirstReferenceChild(recycler, state) :
1754cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar                findLastReferenceChild(recycler, state);
1755719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1756719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1757719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    /**
1758719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Among the children that are suitable to be considered as an anchor child, returns the one
1759719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * closest to the start of the layout.
1760719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * <p>
1761719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * Due to ambiguous adapter updates or children being removed, some children's positions may be
1762719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * invalid. This method is a best effort to find a position within adapter bounds if possible.
17638a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar     * <p>
17648a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar     * It also prioritizes children that are within the visible bounds.
1765719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     *
1766719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     * @return A View that can be used an an anchor View.
1767719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar     */
1768cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private View findReferenceChildClosestToStart(RecyclerView.Recycler recycler,
17691e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            RecyclerView.State state) {
1770cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        return mShouldReverseLayout ? findLastReferenceChild(recycler, state) :
1771cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar                findFirstReferenceChild(recycler, state);
1772719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1773719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1774cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private View findFirstReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) {
1775cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        return findReferenceChild(recycler, state, 0, getChildCount(), state.getItemCount());
1776719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1777719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
1778cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    private View findLastReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) {
1779cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar        return findReferenceChild(recycler, state, getChildCount() - 1, -1, state.getItemCount());
17808a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar    }
17818a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar
17821f5c7b76bfc3da85513e6d2c6aa1058339f0c625Yigit Boyar    // overridden by GridLayoutManager
1783cf87e0b2827dba309646d6a73945b2e1d1fac248Yigit Boyar    View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state,
17841e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            int start, int end, int itemCount) {
1785ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
17868a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        View invalidMatch = null;
17878a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        View outOfBoundsMatch = null;
17888a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        final int boundsStart = mOrientationHelper.getStartAfterPadding();
17898a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        final int boundsEnd = mOrientationHelper.getEndAfterPadding();
17908a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        final int diff = end > start ? 1 : -1;
17918a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        for (int i = start; i != end; i += diff) {
1792719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final View view = getChildAt(i);
1793719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            final int position = getPosition(view);
1794719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            if (position >= 0 && position < itemCount) {
1795ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas                if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) {
17968a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                    if (invalidMatch == null) {
17978a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                        invalidMatch = view; // removed item, least preferred
17988a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                    }
17991e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd
18001e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        || mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
18018a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                    if (outOfBoundsMatch == null) {
18028a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                        outOfBoundsMatch = view; // item is not visible, less preferred
18038a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                    }
18048a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                } else {
18058a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                    return view;
18068a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar                }
1807719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar            }
1808719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar        }
18098a1f650a5d51c95b0d4e34c11b4c6d453ce6696cYigit Boyar        return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch;
1810719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar    }
1811719a0dfbcf2ca2b63cc3ce1e7ab18eadb3694f2cYigit Boyar
18129c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // returns the out-of-bound child view closest to RV's end bounds. An out-of-bound child is
18139c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // defined as a child that's either partially or fully invisible (outside RV's padding area).
18149c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    private View findPartiallyOrCompletelyInvisibleChildClosestToEnd(RecyclerView.Recycler recycler,
18159c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            RecyclerView.State state) {
18169c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return mShouldReverseLayout ? findFirstPartiallyOrCompletelyInvisibleChild(recycler, state)
18179c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                : findLastPartiallyOrCompletelyInvisibleChild(recycler, state);
18189c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    }
18199c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
18209c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // returns the out-of-bound child view closest to RV's starting bounds. An out-of-bound child is
18219c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // defined as a child that's either partially or fully invisible (outside RV's padding area).
18229c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    private View findPartiallyOrCompletelyInvisibleChildClosestToStart(
18239c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            RecyclerView.Recycler recycler, RecyclerView.State state) {
18249c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return mShouldReverseLayout ? findLastPartiallyOrCompletelyInvisibleChild(recycler, state) :
18259c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                findFirstPartiallyOrCompletelyInvisibleChild(recycler, state);
18269c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    }
18279c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
18289c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    private View findFirstPartiallyOrCompletelyInvisibleChild(RecyclerView.Recycler recycler,
18299c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            RecyclerView.State state) {
18309c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return findOnePartiallyOrCompletelyInvisibleChild(0, getChildCount());
18319c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    }
18329c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
18339c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    private View findLastPartiallyOrCompletelyInvisibleChild(RecyclerView.Recycler recycler,
18349c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            RecyclerView.State state) {
18359c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return findOnePartiallyOrCompletelyInvisibleChild(getChildCount() - 1, -1);
18369c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    }
18379c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
1838d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    /**
1839115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * Returns the adapter position of the first visible view. This position does not include
1840115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * adapter changes that were dispatched after the last layout pass.
1841d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1842d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
1843d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
1844d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * not in the layout.
1845d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1846d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
1847d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
18485f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * LayoutManager may pre-cache some views that are not necessarily visible. Those views
1849d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * are ignored in this method.
1850d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     *
1851d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @return The adapter position of the first visible item or {@link RecyclerView#NO_POSITION} if
1852d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * there aren't any visible items.
1853d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findFirstCompletelyVisibleItemPosition()
1854d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findLastVisibleItemPosition()
1855d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     */
1856d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public int findFirstVisibleItemPosition() {
18576490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        final View child = findOneVisibleChild(0, getChildCount(), false, true);
1858ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        return child == null ? RecyclerView.NO_POSITION : getPosition(child);
1859d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
1860d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
1861d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    /**
1862115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * Returns the adapter position of the first fully visible view. This position does not include
1863115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * adapter changes that were dispatched after the last layout pass.
1864d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1865d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * Note that bounds check is only performed in the current orientation. That means, if
18665f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * LayoutManager is horizontal, it will only check the view's left and right edges.
1867d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     *
1868d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @return The adapter position of the first fully visible item or
1869d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * {@link RecyclerView#NO_POSITION} if there aren't any visible items.
1870d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findFirstVisibleItemPosition()
1871d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findLastCompletelyVisibleItemPosition()
1872d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     */
1873d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public int findFirstCompletelyVisibleItemPosition() {
18746490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        final View child = findOneVisibleChild(0, getChildCount(), true, false);
1875ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        return child == null ? RecyclerView.NO_POSITION : getPosition(child);
1876d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
1877d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
1878d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    /**
1879115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * Returns the adapter position of the last visible view. This position does not include
1880115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * adapter changes that were dispatched after the last layout pass.
1881d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1882d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * Note that, this value is not affected by layout orientation or item order traversal.
1883d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
1884d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * not in the layout.
1885d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1886d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * If RecyclerView has item decorators, they will be considered in calculations as well.
1887d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
18885f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * LayoutManager may pre-cache some views that are not necessarily visible. Those views
1889d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * are ignored in this method.
1890d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     *
1891d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @return The adapter position of the last visible view or {@link RecyclerView#NO_POSITION} if
1892d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * there aren't any visible items.
1893d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findLastCompletelyVisibleItemPosition()
1894d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findFirstVisibleItemPosition()
1895d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     */
1896d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public int findLastVisibleItemPosition() {
18976490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        final View child = findOneVisibleChild(getChildCount() - 1, -1, false, true);
1898ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        return child == null ? RecyclerView.NO_POSITION : getPosition(child);
1899d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
1900d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
1901d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    /**
1902115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * Returns the adapter position of the last fully visible view. This position does not include
1903115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar     * adapter changes that were dispatched after the last layout pass.
1904d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * <p>
1905d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * Note that bounds check is only performed in the current orientation. That means, if
19065f1c90f3afcf680f6467d80eb369f81f35222ed3Yigit Boyar     * LayoutManager is horizontal, it will only check the view's left and right edges.
1907d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     *
1908d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @return The adapter position of the last fully visible view or
1909d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * {@link RecyclerView#NO_POSITION} if there aren't any visible items.
1910d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findLastVisibleItemPosition()
1911d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     * @see #findFirstCompletelyVisibleItemPosition()
1912d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar     */
1913d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public int findLastCompletelyVisibleItemPosition() {
19146490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar        final View child = findOneVisibleChild(getChildCount() - 1, -1, true, false);
1915ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas        return child == null ? RecyclerView.NO_POSITION : getPosition(child);
1916d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
1917d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
19189c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // Returns the first child that is visible in the provided index range, i.e. either partially or
19199c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // fully visible depending on the arguments provided. Completely invisible children are not
19209c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // acceptable by this method, but could be returned
19219c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    // using #findOnePartiallyOrCompletelyInvisibleChild
19226490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar    View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible,
19236490f4b25e7725acd06248f0247fb0c7634afcb1Yigit Boyar            boolean acceptPartiallyVisible) {
1924ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
19259c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
19269c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
19279c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (completelyVisible) {
19289c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_GT_PVS | ViewBoundsCheck.FLAG_CVS_EQ_PVS
19299c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVE_LT_PVE | ViewBoundsCheck.FLAG_CVE_EQ_PVE);
19309c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        } else {
19319c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVE
19329c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVE_GT_PVS);
19338f25dd858240e8b86dffc4c1af54307bb462052aKeyvan Amiri        }
19349c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (acceptPartiallyVisible) {
19359c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVE
19369c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVE_GT_PVS);
19379c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
19389c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return (mOrientation == HORIZONTAL) ? mHorizontalBoundCheck
19399c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
19409c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        acceptableBoundsFlag) : mVerticalBoundCheck
19419c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
19429c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        acceptableBoundsFlag);
19439c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    }
19449c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
19459c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri    View findOnePartiallyOrCompletelyInvisibleChild(int fromIndex, int toIndex) {
19469c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        ensureLayoutState();
19479c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        final int next = toIndex > fromIndex ? 1 : (toIndex < fromIndex ? -1 : 0);
19489c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (next == 0) {
19499c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return getChildAt(fromIndex);
19509c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
19519c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
19529c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
19539c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (mOrientationHelper.getDecoratedStart(getChildAt(fromIndex))
19549c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                < mOrientationHelper.getStartAfterPadding()) {
19559c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS | ViewBoundsCheck.FLAG_CVE_LT_PVE
19569c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVE_GT_PVS);
19579c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
19589c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVE_LT_PVE);
19599c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        } else {
19609c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE | ViewBoundsCheck.FLAG_CVS_GT_PVS
19619c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVS_LT_PVE);
19629c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE
19639c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                    | ViewBoundsCheck.FLAG_CVS_GT_PVS);
19649c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
19659c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return (mOrientation == HORIZONTAL) ? mHorizontalBoundCheck
19669c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
19679c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        acceptableBoundsFlag) : mVerticalBoundCheck
19689c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
19699c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        acceptableBoundsFlag);
1970d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
1971d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
19722aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    @Override
1973d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public View onFocusSearchFailed(View focused, int focusDirection,
19748c1ebc6e59cc5a28de408f4138d3fa8870e8faceYigit Boyar            RecyclerView.Recycler recycler, RecyclerView.State state) {
19752aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        resolveShouldLayoutReverse();
19762aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        if (getChildCount() == 0) {
19772aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return null;
19782aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
19792aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
19802aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
198194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        if (layoutDir == LayoutState.INVALID_LAYOUT) {
19822aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar            return null;
19832aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
1984ffff7c903fa7dbf176fd251f77a959e6b9531456Yigit Boyar        ensureLayoutState();
198594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        ensureLayoutState();
1986c032ec5462f6c7c07031310090e23af65841deeeYigit Boyar        final int maxScroll = (int) (MAX_SCROLL_FACTOR * mOrientationHelper.getTotalSpace());
198794c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        updateLayoutState(layoutDir, maxScroll, false, state);
1988c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
1989c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        mLayoutState.mRecycle = false;
199094c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        fill(recycler, mLayoutState, state, true);
19919c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri
19929c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // nextCandidate is the first child view in the layout direction that's partially
19939c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // within RV's bounds, i.e. part of it is visible or it's completely invisible but still
19949c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // touching RV's bounds. This will be the unfocusable candidate view to become visible onto
19959c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // the screen if no focusable views are found in the given layout direction.
19969c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        final View nextCandidate;
19979c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        if (layoutDir == LayoutState.LAYOUT_START) {
19989c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            nextCandidate = findPartiallyOrCompletelyInvisibleChildClosestToStart(recycler, state);
19999c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        } else {
20009c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            nextCandidate = findPartiallyOrCompletelyInvisibleChildClosestToEnd(recycler, state);
20019c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        }
20029c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // nextFocus is meaningful only if it refers to a focusable child, in which case it
20039c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        // indicates the next view to gain focus.
20042aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        final View nextFocus;
200594c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar        if (layoutDir == LayoutState.LAYOUT_START) {
2006668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            nextFocus = getChildClosestToStart();
20072aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        } else {
2008668e774379c036a5d53d07ec69ed9ebee13a1fd9Yigit Boyar            nextFocus = getChildClosestToEnd();
20092aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
2010b174744db6a70f384d44caeb43e10854652e81b9Keyvan Amiri        if (nextFocus.hasFocusable()) {
20119c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            if (nextCandidate == null) {
20129c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                return null;
20139c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            }
20149c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri            return nextFocus;
20152aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar        }
20169c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri        return nextCandidate;
20172aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar    }
20187dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
20197dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
20207dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Used for debugging.
20217dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Logs the internal representation of children to default logger.
20227dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
20237dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    private void logChildren() {
20247dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        Log.d(TAG, "internal representation of views on the screen");
20257dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        for (int i = 0; i < getChildCount(); i++) {
20267dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            View child = getChildAt(i);
20277dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            Log.d(TAG, "item " + getPosition(child) + ", coord:"
20287dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    + mOrientationHelper.getDecoratedStart(child));
20297dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
20307dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        Log.d(TAG, "==============");
20317dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
20327dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
20337dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
20347dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Used for debugging.
20357dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Validates that child views are laid out in correct order. This is important because rest of
20367dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * the algorithm relies on this constraint.
20377dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     *
20387dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * In default layout, child 0 should be closest to screen position 0 and last child should be
20397dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * closest to position WIDTH or HEIGHT.
20407dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * In reverse layout, last child should be closes to screen position 0 and first child should
20417dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * be closest to position WIDTH  or HEIGHT
20427dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
2043b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    void validateChildOrder() {
20440447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        Log.d(TAG, "validating child count " + getChildCount());
20457dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (getChildCount() < 1) {
20467dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return;
20477dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
20487dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int lastPos = getPosition(getChildAt(0));
20497dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int lastScreenLoc = mOrientationHelper.getDecoratedStart(getChildAt(0));
20507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        if (mShouldReverseLayout) {
20517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = 1; i < getChildCount(); i++) {
20527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
20537dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                int pos = getPosition(child);
20547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                int screenLoc = mOrientationHelper.getDecoratedStart(child);
20557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                if (pos < lastPos) {
20567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    logChildren();
20571e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    throw new RuntimeException("detected invalid position. loc invalid? "
20581e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            + (screenLoc < lastScreenLoc));
20597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
20607dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                if (screenLoc > lastScreenLoc) {
20617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    logChildren();
20627dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    throw new RuntimeException("detected invalid location");
20637dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
20647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
20657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        } else {
20667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            for (int i = 1; i < getChildCount(); i++) {
20677dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                View child = getChildAt(i);
20687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                int pos = getPosition(child);
20697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                int screenLoc = mOrientationHelper.getDecoratedStart(child);
20707dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                if (pos < lastPos) {
20717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    logChildren();
20721e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    throw new RuntimeException("detected invalid position. loc invalid? "
20731e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            + (screenLoc < lastScreenLoc));
20747dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
20757dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                if (screenLoc < lastScreenLoc) {
20767dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    logChildren();
20777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                    throw new RuntimeException("detected invalid location");
20787dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar                }
20797dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            }
20807dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
20817dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
20827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
2083d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
2084c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase    public boolean supportsPredictiveItemAnimations() {
20856e83751247c5be0211d7bffaf057431c03dfef38Yigit Boyar        return mPendingSavedState == null && mLastStackFromEnd == mStackFromEnd;
2086d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
2087d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
20887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    /**
2089e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     * @hide This method should be called by ItemTouchHelper only.
2090e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar     */
20918e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
2092e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    @Override
20938a11e6829c522aa1efcc903afa4c01d337082eabChris Craik    public void prepareForDrop(@NonNull View view, @NonNull View target, int x, int y) {
2094e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertNotInLayoutOrScroll("Cannot drop a view during a scroll or layout calculation");
2095e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        ensureLayoutState();
2096e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        resolveShouldLayoutReverse();
2097e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int myPos = getPosition(view);
2098e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int targetPos = getPosition(target);
20991e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        final int dropDirection = myPos < targetPos ? LayoutState.ITEM_DIRECTION_TAIL
21001e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                : LayoutState.ITEM_DIRECTION_HEAD;
2101e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        if (mShouldReverseLayout) {
2102e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dropDirection == LayoutState.ITEM_DIRECTION_TAIL) {
2103e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollToPositionWithOffset(targetPos,
21049c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                        mOrientationHelper.getEndAfterPadding()
21059c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                                - (mOrientationHelper.getDecoratedStart(target)
21069c0ad7d5adfbe51d85adcbc056b6183095d8aaedKeyvan Amiri                                + mOrientationHelper.getDecoratedMeasurement(view)));
2107e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2108e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollToPositionWithOffset(targetPos,
21091e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        mOrientationHelper.getEndAfterPadding()
21101e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                                - mOrientationHelper.getDecoratedEnd(target));
2111e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2112e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        } else {
2113e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            if (dropDirection == LayoutState.ITEM_DIRECTION_HEAD) {
2114e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollToPositionWithOffset(targetPos, mOrientationHelper.getDecoratedStart(target));
2115e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            } else {
2116e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                scrollToPositionWithOffset(targetPos,
21171e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        mOrientationHelper.getDecoratedEnd(target)
21181e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                                - mOrientationHelper.getDecoratedMeasurement(view));
2119e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
2120e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
2121e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
2122e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
2123e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    /**
21247dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * Helper class that keeps temporary state while {LayoutManager} is filling out the empty
21257dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     * space.
21267dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar     */
2127b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    static class LayoutState {
21287dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21291e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final String TAG = "LLM#LayoutState";
21307dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21311e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int LAYOUT_START = -1;
21327dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21331e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int LAYOUT_END = 1;
21347dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21351e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int INVALID_LAYOUT = Integer.MIN_VALUE;
21362aad60a0bcc40c5985f8e5e7c6b5c139cde6ceeeYigit Boyar
21371e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int ITEM_DIRECTION_HEAD = -1;
21387dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21391e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int ITEM_DIRECTION_TAIL = 1;
21407dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21411e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        static final int SCROLLING_OFFSET_NaN = Integer.MIN_VALUE;
21427dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21437dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
2144c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar         * We may not want to recycle children in some cases (e.g. layout)
2145c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar         */
2146c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        boolean mRecycle = true;
2147c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar
2148c50c4cad31d73e574b27bb3d7581542975e37263Yigit Boyar        /**
214994c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * Pixel offset where layout should start
21507dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21517dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mOffset;
21527dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21537dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
21547dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Number of pixels that we should fill, in the layout direction.
21557dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21567dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mAvailable;
21577dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21587dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
21597dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Current position on the adapter to get the next item.
21607dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21617dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mCurrentPosition;
21627dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21637dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
21647dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Defines the direction in which the data adapter is traversed.
21657dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL}
21667dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21677dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mItemDirection;
21687dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21697dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
21707dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Defines the direction in which the layout is filled.
21717dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Should be {@link #LAYOUT_START} or {@link #LAYOUT_END}
21727dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21737dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mLayoutDirection;
21747dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21757dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
217694c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * Used when LayoutState is constructed in a scrolling state.
21777dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * It should be set the amount of scrolling we can make without creating a new view.
21787dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Settings this is required for efficient view recycling.
21797dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
21807dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        int mScrollingOffset;
21817dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
21827dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
21830447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar         * Used if you want to pre-layout items that are not yet visible.
218494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * The difference with {@link #mAvailable} is that, when recycling, distance laid out for
21850447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar         * {@link #mExtra} is not considered to avoid recycling visible children.
21860447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar         */
21870447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        int mExtra = 0;
21880447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar
21890447ba889146f60d6965e6ea66fa4e2cac4d0891Yigit Boyar        /**
219018ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar         * Equal to {@link RecyclerView.State#isPreLayout()}. When consuming scrap, if this value
219118ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar         * is set to true, we skip removed views since they should not be laid out in post layout
219218ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar         * step.
219318ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar         */
219418ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar        boolean mIsPreLayout = false;
219518ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar
219618ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar        /**
21974143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar         * The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)}
21984143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar         * amount.
2199baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal         */
2200baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        int mLastScrollDelta;
2201baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal
2202baa826219e2ae7c054011cabf992cd7a37fe2a8fGabriel Peal        /**
220394c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * When LLM needs to layout particular views, it sets this list in which case, LayoutState
2204b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         * will only return views from this list and return null if it cannot find an item.
2205b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         */
2206b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        List<RecyclerView.ViewHolder> mScrapList = null;
2207b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
2208b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        /**
22094143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar         * Used when there is no limit in how many views can be laid out.
22104143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar         */
22114143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        boolean mInfinite;
22124143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar
22134143554adb9b31b700b6876a251a64419e6111e2Yigit Boyar        /**
22147dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * @return true if there are more items in the data adapter
22157dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
2216d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean hasMore(RecyclerView.State state) {
2217d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount();
22187dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
22197dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
22207dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        /**
222194c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * Gets the view for the next element that we should layout.
22227dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         * Also updates current item index to the next item, based on {@link #mItemDirection}
22237dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         *
222494c0b086c12e634976fecd47d442bc7a1a6341bbYigit Boyar         * @return The next element that we should layout.
22257dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar         */
2226d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        View next(RecyclerView.Recycler recycler) {
2227b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            if (mScrapList != null) {
2228888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                return nextViewFromScrapList();
2229b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
2230d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            final View view = recycler.getViewForPosition(mCurrentPosition);
22317dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            mCurrentPosition += mItemDirection;
22327dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar            return view;
22337dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
22347dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar
2235b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        /**
2236888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar         * Returns the next item from the scrap list.
2237b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         * <p>
2238b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         * Upon finding a valid VH, sets current item position to VH.itemPosition + mItemDirection
2239b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         *
2240b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         * @return View if an item in the current position or direction exists if not null.
2241b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar         */
2242888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        private View nextViewFromScrapList() {
2243888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            final int size = mScrapList.size();
2244888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            for (int i = 0; i < size; i++) {
2245364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                final View view = mScrapList.get(i).itemView;
2246ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas                final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
2247364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                if (lp.isItemRemoved()) {
2248888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                    continue;
2249888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                }
2250364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                if (mCurrentPosition == lp.getViewLayoutPosition()) {
2251364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                    assignPositionFromScrapList(view);
2252364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                    return view;
2253888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                }
2254888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            }
2255888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            return null;
2256888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        }
2257888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar
2258888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        public void assignPositionFromScrapList() {
2259888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            assignPositionFromScrapList(null);
2260888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        }
2261888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar
2262364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar        public void assignPositionFromScrapList(View ignore) {
2263364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar            final View closest = nextViewInLimitedList(ignore);
2264364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar            if (closest == null) {
2265ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas                mCurrentPosition = RecyclerView.NO_POSITION;
2266364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar            } else {
2267ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas                mCurrentPosition = ((RecyclerView.LayoutParams) closest.getLayoutParams())
2268364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                        .getViewLayoutPosition();
2269364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar            }
2270888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar        }
2271888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar
2272364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar        public View nextViewInLimitedList(View ignore) {
2273b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            int size = mScrapList.size();
2274364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar            View closest = null;
2275b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            int closestDistance = Integer.MAX_VALUE;
2276888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            if (DEBUG && mIsPreLayout) {
2277888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar                throw new IllegalStateException("Scrap list cannot be used in pre layout");
2278888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            }
2279b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            for (int i = 0; i < size; i++) {
2280364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                View view = mScrapList.get(i).itemView;
2281ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas                final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
2282364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                if (view == ignore || lp.isItemRemoved()) {
228318ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar                    continue;
228418ae336dbaae3db982f38cde08936c9f0243757bYigit Boyar                }
22851e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                final int distance = (lp.getViewLayoutPosition() - mCurrentPosition)
22861e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        * mItemDirection;
2287b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (distance < 0) {
2288b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    continue; // item is not in current direction
2289b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
2290b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                if (distance < closestDistance) {
2291364ca611da0789aefae36126a8e302abaefa0d48Yigit Boyar                    closest = view;
2292b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    closestDistance = distance;
2293b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    if (distance == 0) {
2294b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                        break;
2295b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                    }
2296b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar                }
2297b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar            }
2298888093b0a071a99d65c01116cf703d46b21f9918Yigit Boyar            return closest;
2299b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar        }
2300b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar
23017dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        void log() {
23021e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:"
23031e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection);
23047dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar        }
23057dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar    }
230608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
2307ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar    /**
2308ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar     * @hide
2309ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar     */
23108e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
2311ceb1d0ab9e22f5a48b72e9850f713be60311c516Yigit Boyar    public static class SavedState implements Parcelable {
231208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
231308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        int mAnchorPosition;
231408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
231508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        int mAnchorOffset;
231608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
231708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        boolean mAnchorLayoutFromEnd;
231808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
231908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        public SavedState() {
232008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
232108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
232208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
232308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        SavedState(Parcel in) {
232408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorPosition = in.readInt();
232508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorOffset = in.readInt();
232608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorLayoutFromEnd = in.readInt() == 1;
232708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
232808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
232908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        public SavedState(SavedState other) {
233008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorPosition = other.mAnchorPosition;
233108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorOffset = other.mAnchorOffset;
233208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
233308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
233408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
233575b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        boolean hasValidAnchor() {
233675b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar            return mAnchorPosition >= 0;
233775b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        }
233875b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar
233975b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        void invalidateAnchor() {
2340ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            mAnchorPosition = RecyclerView.NO_POSITION;
234175b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar        }
234275b7ff9ccca9311854e9c74282b1af1ce87df470Yigit Boyar
234308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        @Override
234408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        public int describeContents() {
234508cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            return 0;
234608cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
234708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
234808cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        @Override
234908cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        public void writeToParcel(Parcel dest, int flags) {
235008cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            dest.writeInt(mAnchorPosition);
235108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            dest.writeInt(mAnchorOffset);
235208cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
235308cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar        }
235408cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
23551e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas        public static final Parcelable.Creator<SavedState> CREATOR =
23561e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                new Parcelable.Creator<SavedState>() {
23571e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    @Override
23581e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    public SavedState createFromParcel(Parcel in) {
23591e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return new SavedState(in);
23601e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    }
236108cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar
23621e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    @Override
23631e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    public SavedState[] newArray(int size) {
23641e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        return new SavedState[size];
23651e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    }
23661e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                };
236708cbcdeb4283048c097397d042d5ae0d2b8683d3Yigit Boyar    }
2368310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
2369310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    /**
2370310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     * Simple data class to keep Anchor information
2371310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar     */
2372a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard    static class AnchorInfo {
2373a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard        OrientationHelper mOrientationHelper;
2374310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        int mPosition;
2375310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        int mCoordinate;
2376310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        boolean mLayoutFromEnd;
23779aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        boolean mValid;
23789aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar
23799aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        AnchorInfo() {
23809aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            reset();
23819aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar        }
23829aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar
2383310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        void reset() {
2384ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            mPosition = RecyclerView.NO_POSITION;
2385310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mCoordinate = INVALID_OFFSET;
2386310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mLayoutFromEnd = false;
23879aae13b01e2a00d892ab82677f613bcc6e380baeYigit Boyar            mValid = false;
2388310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
2389310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
2390310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        /**
2391310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar         * assigns anchor coordinate from the RecyclerView's padding depending on current
2392310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar         * layoutFromEnd value
2393310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar         */
2394310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        void assignCoordinateFromPadding() {
2395310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            mCoordinate = mLayoutFromEnd
2396310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    ? mOrientationHelper.getEndAfterPadding()
2397310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                    : mOrientationHelper.getStartAfterPadding();
2398310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
2399310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
2400310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        @Override
2401310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        public String toString() {
24021e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas            return "AnchorInfo{"
24031e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + "mPosition=" + mPosition
24041e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", mCoordinate=" + mCoordinate
24051e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", mLayoutFromEnd=" + mLayoutFromEnd
24061e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + ", mValid=" + mValid
24071e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    + '}';
2408310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
2409310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
24103a500f61a8bdf48904f380f2d4925fe420d18ce7Aurimas Liutikas        boolean isViewValidAsAnchor(View child, RecyclerView.State state) {
2411ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
2412542f1260934df280985294eaef1ec8469863281fYigit Boyar            return !lp.isItemRemoved() && lp.getViewLayoutPosition() >= 0
2413542f1260934df280985294eaef1ec8469863281fYigit Boyar                    && lp.getViewLayoutPosition() < state.getItemCount();
2414542f1260934df280985294eaef1ec8469863281fYigit Boyar        }
2415542f1260934df280985294eaef1ec8469863281fYigit Boyar
2416a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard        public void assignFromViewAndKeepVisibleRect(View child, int position) {
2417542f1260934df280985294eaef1ec8469863281fYigit Boyar            final int spaceChange = mOrientationHelper.getTotalSpaceChange();
2418542f1260934df280985294eaef1ec8469863281fYigit Boyar            if (spaceChange >= 0) {
2419a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard                assignFromView(child, position);
2420542f1260934df280985294eaef1ec8469863281fYigit Boyar                return;
2421542f1260934df280985294eaef1ec8469863281fYigit Boyar            }
2422a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mPosition = position;
2423542f1260934df280985294eaef1ec8469863281fYigit Boyar            if (mLayoutFromEnd) {
2424542f1260934df280985294eaef1ec8469863281fYigit Boyar                final int prevLayoutEnd = mOrientationHelper.getEndAfterPadding() - spaceChange;
2425542f1260934df280985294eaef1ec8469863281fYigit Boyar                final int childEnd = mOrientationHelper.getDecoratedEnd(child);
2426542f1260934df280985294eaef1ec8469863281fYigit Boyar                final int previousEndMargin = prevLayoutEnd - childEnd;
2427542f1260934df280985294eaef1ec8469863281fYigit Boyar                mCoordinate = mOrientationHelper.getEndAfterPadding() - previousEndMargin;
2428542f1260934df280985294eaef1ec8469863281fYigit Boyar                // ensure we did not push child's top out of bounds because of this
24291e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                if (previousEndMargin > 0) { // we have room to shift bottom if necessary
2430542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int childSize = mOrientationHelper.getDecoratedMeasurement(child);
2431542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int estimatedChildStart = mCoordinate - childSize;
2432542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int layoutStart = mOrientationHelper.getStartAfterPadding();
24331e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    final int previousStartMargin = mOrientationHelper.getDecoratedStart(child)
24341e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            - layoutStart;
2435542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int startReference = layoutStart + Math.min(previousStartMargin, 0);
2436542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int startMargin = estimatedChildStart - startReference;
2437542f1260934df280985294eaef1ec8469863281fYigit Boyar                    if (startMargin < 0) {
2438542f1260934df280985294eaef1ec8469863281fYigit Boyar                        // offset to make top visible but not too much
2439542f1260934df280985294eaef1ec8469863281fYigit Boyar                        mCoordinate += Math.min(previousEndMargin, -startMargin);
2440542f1260934df280985294eaef1ec8469863281fYigit Boyar                    }
2441542f1260934df280985294eaef1ec8469863281fYigit Boyar                }
2442542f1260934df280985294eaef1ec8469863281fYigit Boyar            } else {
2443542f1260934df280985294eaef1ec8469863281fYigit Boyar                final int childStart = mOrientationHelper.getDecoratedStart(child);
2444542f1260934df280985294eaef1ec8469863281fYigit Boyar                final int startMargin = childStart - mOrientationHelper.getStartAfterPadding();
2445542f1260934df280985294eaef1ec8469863281fYigit Boyar                mCoordinate = childStart;
2446542f1260934df280985294eaef1ec8469863281fYigit Boyar                if (startMargin > 0) { // we have room to fix end as well
24471e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    final int estimatedEnd = childStart
24481e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            + mOrientationHelper.getDecoratedMeasurement(child);
24491e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    final int previousLayoutEnd = mOrientationHelper.getEndAfterPadding()
24501e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            - spaceChange;
24511e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    final int previousEndMargin = previousLayoutEnd
24521e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            - mOrientationHelper.getDecoratedEnd(child);
24531e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                    final int endReference = mOrientationHelper.getEndAfterPadding()
24541e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                            - Math.min(0, previousEndMargin);
2455542f1260934df280985294eaef1ec8469863281fYigit Boyar                    final int endMargin = endReference - estimatedEnd;
2456542f1260934df280985294eaef1ec8469863281fYigit Boyar                    if (endMargin < 0) {
2457542f1260934df280985294eaef1ec8469863281fYigit Boyar                        mCoordinate -= Math.min(startMargin, -endMargin);
2458542f1260934df280985294eaef1ec8469863281fYigit Boyar                    }
2459542f1260934df280985294eaef1ec8469863281fYigit Boyar                }
2460542f1260934df280985294eaef1ec8469863281fYigit Boyar            }
2461542f1260934df280985294eaef1ec8469863281fYigit Boyar        }
2462542f1260934df280985294eaef1ec8469863281fYigit Boyar
2463a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard        public void assignFromView(View child, int position) {
2464310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            if (mLayoutFromEnd) {
24651e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                mCoordinate = mOrientationHelper.getDecoratedEnd(child)
24661e827caa16440590647019b9c1338f6309c5be7aAurimas Liutikas                        + mOrientationHelper.getTotalSpaceChange();
2467310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            } else {
2468310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar                mCoordinate = mOrientationHelper.getDecoratedStart(child);
2469310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar            }
2470310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar
2471a0e32c54b808887323ba05392fe4e340c9ad6c0bshepshapard            mPosition = position;
2472310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar        }
2473310e95e1c6dfe4f26ef594233e65e1ff83e0f1ffYigit Boyar    }
2474b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar
2475b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    protected static class LayoutChunkResult {
2476b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        public int mConsumed;
2477b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        public boolean mFinished;
2478b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        public boolean mIgnoreConsumed;
2479b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        public boolean mFocusable;
2480b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar
2481b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        void resetInternal() {
2482b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            mConsumed = 0;
2483b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            mFinished = false;
2484b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            mIgnoreConsumed = false;
2485b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar            mFocusable = false;
2486b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar        }
2487b97e8219784e623526bc3c6077a698d608f04fd9Yigit Boyar    }
24887dad56243ebcde65d75d592dc802269a4d86c875Yigit Boyar}
2489