LinearLayoutManagerTest.java revision d7848507d6c561ca8e17d1954653f4fd26b58f84
1d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar/*
2d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Copyright (C) 2014 The Android Open Source Project
3d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar *
4d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * you may not use this file except in compliance with the License.
6d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * You may obtain a copy of the License at
7d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar *
8d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar *
10d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * See the License for the specific language governing permissions and
14d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar * limitations under the License.
15d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar */
16d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
17d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarpackage android.support.v7.widget;
18d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
19d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.content.Context;
20d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport android.view.View;
21d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
22d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.ArrayList;
23d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.List;
24d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.CountDownLatch;
25d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarimport java.util.concurrent.TimeUnit;
26d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
27d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyarpublic class LinearLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
28d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
29d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    WrappedLinearLayoutManager mLayoutManager;
30d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
31d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    TestAdapter mTestAdapter;
32d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
33d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    final List<Config> mBaseVariations = new ArrayList<Config>();
34d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
35d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    @Override
36d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    protected void setUp() throws Exception {
37d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        super.setUp();
38d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        for (int orientation : new int[]{LinearLayoutManager.VERTICAL,
39d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                LinearLayoutManager.HORIZONTAL}) {
40d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            for (boolean reverseLayout : new boolean[]{false, true}) {
41d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                for (boolean stackFromBottom : new boolean[]{false, true}) {
42d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    mBaseVariations.add(new Config(orientation, reverseLayout, stackFromBottom));
43d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
44d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
45d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
46d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
47d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
48d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    RecyclerView setupByConfig(Config config) throws Throwable {
49d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        final RecyclerView recyclerView = new RecyclerView(getActivity());
50d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        recyclerView.setHasFixedSize(true);
51d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mTestAdapter = new TestAdapter(config.mItemCount);
52d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        recyclerView.setAdapter(mTestAdapter);
53d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager = new WrappedLinearLayoutManager(getActivity(), config.mOrientation,
54d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                config.mReverseLayout);
55d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.setStackFromEnd(config.mStackFromEnd);
56d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        recyclerView.setLayoutManager(mLayoutManager);
57d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.expectLayouts(1);
58d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        setRecyclerView(recyclerView);
59d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.waitForLayout(2);
60d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        return recyclerView;
61d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
62d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
63d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
64d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public void testGetFirstLastChildrenTest() throws Throwable {
65d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        for (Config config : mBaseVariations) {
66d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            getFirstLastChildrenTest(config);
67d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
68d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
69d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
70d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    public void getFirstLastChildrenTest(final Config config) throws Throwable {
71d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        setupByConfig(config);
72d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        Runnable viewInBoundsTest = new Runnable() {
73d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            @Override
74d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            public void run() {
75d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren();
76d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final String boundsLog = mLayoutManager.getBoundsLog();
77d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                assertEquals(config + ":\nfirst visible child should match traversal result\n"
78d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                                + boundsLog, visibleChildren.firstVisiblePosition,
79d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        mLayoutManager.findFirstVisibleItemPosition()
80d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                );
81d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                assertEquals(
82d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        config + ":\nfirst fully visible child should match traversal result\n"
83d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                                + boundsLog, visibleChildren.firstFullyVisiblePosition,
84d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        mLayoutManager.findFirstCompletelyVisibleItemPosition()
85d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                );
86d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
87d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                assertEquals(config + ":\nlast visible child should match traversal result\n"
88d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                                + boundsLog, visibleChildren.lastVisiblePosition,
89d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        mLayoutManager.findLastVisibleItemPosition()
90d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                );
91d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                assertEquals(
92d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        config + ":\nlast fully visible child should match traversal result\n"
93d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                                + boundsLog, visibleChildren.lastFullyVisiblePosition,
94d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        mLayoutManager.findLastCompletelyVisibleItemPosition()
95d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                );
96d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
97d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        };
98d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        runTestOnUiThread(viewInBoundsTest);
99d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
100d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        // case
101d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        final int scrollPosition = config.mStackFromEnd ? 0 : mTestAdapter.getItemCount();
102d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        runTestOnUiThread(new Runnable() {
103d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            @Override
104d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            public void run() {
105d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                mRecyclerView.smoothScrollToPosition(scrollPosition);
106d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
107d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        });
108d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        while (mLayoutManager.isSmoothScrolling() ||
109d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
110d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            runTestOnUiThread(viewInBoundsTest);
111d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            Thread.sleep(200);
112d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
113d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        // delete all items
114d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.expectLayouts(2);
115d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mTestAdapter.deleteAndNotify(0, mTestAdapter.getItemCount());
116d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.waitForLayout(2);
117d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        // test empty case
118d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        runTestOnUiThread(viewInBoundsTest);
119d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        // set a new adapter with huge items to test full bounds check
120d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.expectLayouts(1);
121d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        final int totalSpace = mLayoutManager.mOrientationHelper.getTotalSpace();
122d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        final TestAdapter newAdapter = new TestAdapter(100) {
123d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            @Override
124d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            public void onBindViewHolder(TestViewHolder holder,
125d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    int position) {
126d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                super.onBindViewHolder(holder, position);
127d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                if (config.mOrientation == LinearLayoutManager.HORIZONTAL) {
128d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    holder.itemView.setMinimumWidth(totalSpace + 5);
129d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                } else {
130d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    holder.itemView.setMinimumHeight(totalSpace + 5);
131d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
132d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
133d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        };
134d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        runTestOnUiThread(new Runnable() {
135d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            @Override
136d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            public void run() {
137d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                mRecyclerView.setAdapter(newAdapter);
138d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
139d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        });
140d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        mLayoutManager.waitForLayout(2);
141d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        runTestOnUiThread(viewInBoundsTest);
142d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
143d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
144d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    static class VisibleChildren {
145d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
146d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int firstVisiblePosition = RecyclerView.NO_POSITION;
147d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
148d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int firstFullyVisiblePosition = RecyclerView.NO_POSITION;
149d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
150d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int lastVisiblePosition = RecyclerView.NO_POSITION;
151d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
152d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int lastFullyVisiblePosition = RecyclerView.NO_POSITION;
153d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
154d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        @Override
155d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public String toString() {
156d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return "VisibleChildren{" +
157d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    "firstVisiblePosition=" + firstVisiblePosition +
158d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", firstFullyVisiblePosition=" + firstFullyVisiblePosition +
159d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", lastVisiblePosition=" + lastVisiblePosition +
160d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", lastFullyVisiblePosition=" + lastFullyVisiblePosition +
161d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    '}';
162d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
163d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
164d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
165d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    static class WrappedLinearLayoutManager extends LinearLayoutManager {
166d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
167d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        CountDownLatch layoutLatch;
168d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
169d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public WrappedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
170d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            super(context, orientation, reverseLayout);
171d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
172d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
173d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public void expectLayouts(int count) {
174d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            layoutLatch = new CountDownLatch(count);
175d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
176d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
177d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public void waitForLayout(long timeout) throws InterruptedException {
178d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            waitForLayout(timeout, TimeUnit.SECONDS);
179d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
180d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
181d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        private void waitForLayout(long timeout, TimeUnit timeUnit) throws InterruptedException {
182d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            layoutLatch.await(timeout, timeUnit);
183d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            assertEquals("all expected layouts should be executed at the expected time",
184d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    0, layoutLatch.getCount());
185d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
186d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
187d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public String getBoundsLog() {
188d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            StringBuilder sb = new StringBuilder();
189d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            sb.append("view bounds:[start:").append(mOrientationHelper.getStartAfterPadding())
190d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    .append(",").append(" end").append(mOrientationHelper.getEndAfterPadding());
191d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            sb.append("\nchildren bounds\n");
192d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            final int childCount = getChildCount();
193d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            for (int i = 0; i < childCount; i++) {
194d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                View child = getChildAt(i);
195d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                sb.append("child (ind:").append(i).append(", pos:").append(getPosition(child))
196d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        .append("[").append("start:").append(
197d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        mOrientationHelper.getDecoratedStart(child)).append(", end:")
198d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        .append(mOrientationHelper.getDecoratedEnd(child)).append("]\n");
199d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
200d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return sb.toString();
201d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
202d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
203d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public VisibleChildren traverseAndFindVisibleChildren() {
204d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            int childCount = getChildCount();
205d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            final VisibleChildren visibleChildren = new VisibleChildren();
206d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            final int start = mOrientationHelper.getStartAfterPadding();
207d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            final int end = mOrientationHelper.getEndAfterPadding();
208d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            for (int i = 0; i < childCount; i++) {
209d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                View child = getChildAt(i);
210d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final int childStart = mOrientationHelper.getDecoratedStart(child);
211d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final int childEnd = mOrientationHelper.getDecoratedEnd(child);
212d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final boolean fullyVisible = childStart >= start && childEnd <= end;
213d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final boolean hidden = childEnd <= start || childStart >= end;
214d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                if (hidden) {
215d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    continue;
216d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
217d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                final int position = getPosition(child);
218d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                if (fullyVisible) {
219d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    if (position < visibleChildren.firstFullyVisiblePosition ||
220d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                            visibleChildren.firstFullyVisiblePosition == RecyclerView.NO_POSITION) {
221d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        visibleChildren.firstFullyVisiblePosition = position;
222d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    }
223d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
224d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    if (position > visibleChildren.lastFullyVisiblePosition) {
225d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        visibleChildren.lastFullyVisiblePosition = position;
226d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    }
227d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
228d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
229d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                if (position < visibleChildren.firstVisiblePosition ||
230d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                        visibleChildren.firstVisiblePosition == RecyclerView.NO_POSITION) {
231d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    visibleChildren.firstVisiblePosition = position;
232d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
233d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
234d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                if (position > visibleChildren.lastVisiblePosition) {
235d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    visibleChildren.lastVisiblePosition = position;
236d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                }
237d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
238d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            }
239d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return visibleChildren;
240d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
241d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
242d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        @Override
243d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
244d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            super.onLayoutChildren(recycler, state);
245d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            layoutLatch.countDown();
246d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
247d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
248d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
249d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    static class Config {
250d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
251d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        private static final int DEFAULT_ITEM_COUNT = 300;
252d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
253d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        private boolean mStackFromEnd;
254d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
255d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int mOrientation = LinearLayoutManager.VERTICAL;
256d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
257d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        boolean mReverseLayout = false;
258d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
259d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        int mItemCount = DEFAULT_ITEM_COUNT;
260d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
261d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        Config(int orientation, boolean reverseLayout, boolean stackFromEnd) {
262d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mOrientation = orientation;
263d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mReverseLayout = reverseLayout;
264d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mStackFromEnd = stackFromEnd;
265d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
266d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
267d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public Config() {
268d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
269d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
270d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
271d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        Config orientation(int orientation) {
272d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mOrientation = orientation;
273d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return this;
274d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
275d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
276d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        Config stackFromBottom(boolean stackFromBottom) {
277d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mStackFromEnd = stackFromBottom;
278d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return this;
279d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
280d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
281d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        Config reverseLayout(boolean reverseLayout) {
282d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mReverseLayout = reverseLayout;
283d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return this;
284d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
285d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
286d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public Config itemCount(int itemCount) {
287d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            mItemCount = itemCount;
288d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return this;
289d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
290d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar
291d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        @Override
292d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        public String toString() {
293d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar            return "Config{" +
294d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    "mStackFromEnd=" + mStackFromEnd +
295d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", mOrientation=" + mOrientation +
296d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", mReverseLayout=" + mReverseLayout +
297d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    ", mItemCount=" + mItemCount +
298d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar                    '}';
299d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar        }
300d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar    }
301d7848507d6c561ca8e17d1954653f4fd26b58f84Yigit Boyar}
302