1edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar/*
2edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * Copyright (C) 2014 The Android Open Source Project
3edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar *
4edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * you may not use this file except in compliance with the License.
6edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * You may obtain a copy of the License at
7edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar *
8edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar *
10edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * See the License for the specific language governing permissions and
14edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar * limitations under the License.
15edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar */
16edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
17edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarpackage android.support.v7.widget;
18edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
19c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport android.os.Parcel;
20c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport android.os.Parcelable;
21edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.test.AndroidTestCase;
22abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyarimport android.util.Log;
23edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.view.View;
24edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.view.ViewGroup;
25edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyarimport android.widget.TextView;
26edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
27c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyarimport java.util.UUID;
28c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
29d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class RecyclerViewBasicTest extends AndroidTestCase {
30edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
31edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    RecyclerView mRecyclerView;
32edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
33edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    @Override
34edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    protected void setUp() throws Exception {
35edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        super.setUp();
36edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView = new RecyclerView(mContext);
37edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
38edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
39edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    public void testMeasureWithoutLayoutManager() {
40abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
41edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
42edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
43edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    private void measure() {
44edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
45edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
46edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
47edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    private void layout() {
48edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.layout(0, 0, 320, 320);
49edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
50edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
51abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    private void focusSearch() {
52abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.focusSearch(1);
53edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
54edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
55abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testLayoutWithoutAdapter() throws InterruptedException {
56edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockLayoutManager layoutManager = new MockLayoutManager();
57edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setLayoutManager(layoutManager);
58abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
59edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertEquals("layout manager should not be called if there is no adapter attached",
60edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                0, layoutManager.mLayoutCount);
61edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
62edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
63abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testLayoutWithoutLayoutManager() throws InterruptedException {
64abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
65abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
66abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
67abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
68abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
69abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testFocusWithoutLayoutManager() throws InterruptedException {
70abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
71abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
72abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
73abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        focusSearch();
74abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
75abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
76abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testScrollWithoutLayoutManager() throws InterruptedException {
77abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
78abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
79abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
80abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.scrollBy(10, 10);
81abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
82abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
83abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testSmoothScrollWithoutLayoutManager() throws InterruptedException {
84abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
85abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
86abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
87abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.smoothScrollBy(10, 10);
88abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
89abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
90abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testScrollToPositionWithoutLayoutManager() throws InterruptedException {
91abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
92abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
93abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
94abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.scrollToPosition(5);
95abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
96abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
97abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    public void testSmoothScrollToPositionWithoutLayoutManager() throws InterruptedException {
98abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(20));
99abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        measure();
100abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        layout();
101abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar        mRecyclerView.smoothScrollToPosition(5);
102abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar    }
103abd0fbfcdd5b438909f126392eca5978b5939b6dYigit Boyar
104edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    public void testLayout() throws InterruptedException {
105edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockLayoutManager layoutManager = new MockLayoutManager();
106edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setLayoutManager(layoutManager);
107edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(new MockAdapter(3));
108edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        layout();
109edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertEquals("when both layout manager and activity is set, recycler view should call"
110edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                + " layout manager's layout method", 1, layoutManager.mLayoutCount);
111edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
112edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
113edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    public void testObservingAdapters() {
114edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockAdapter adapterOld = new MockAdapter(1);
115edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(adapterOld);
116edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertTrue("attached adapter should have observables", adapterOld.hasObservers());
117edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
118edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockAdapter adapterNew = new MockAdapter(2);
119edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(adapterNew);
120edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertFalse("detached adapter should lose observable", adapterOld.hasObservers());
121edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertTrue("new adapter should have observers", adapterNew.hasObservers());
122edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
123edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(null);
124edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertNull("adapter should be removed successfully", mRecyclerView.getAdapter());
125edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        assertFalse("when adapter is removed, observables should be removed too",
126edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                adapterNew.hasObservers());
127edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
128edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
129edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    public void testAdapterChangeCallbacks() {
130edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockLayoutManager layoutManager = new MockLayoutManager();
131edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setLayoutManager(layoutManager);
132edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockAdapter adapterOld = new MockAdapter(1);
133edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(adapterOld);
134edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        layoutManager.assertPrevNextAdapters(null, adapterOld);
135edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
136edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        MockAdapter adapterNew = new MockAdapter(2);
137edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(adapterNew);
138edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        layoutManager.assertPrevNextAdapters("switching adapters should trigger correct callbacks"
139edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                , adapterOld, adapterNew);
140edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
141edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        mRecyclerView.setAdapter(null);
142edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        layoutManager.assertPrevNextAdapters(
143edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                "Setting adapter null should trigger correct callbacks",
144edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                adapterNew, null);
145edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
146edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
147c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    public void testSavedStateWithStatelessLayoutManager() throws InterruptedException {
148c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        mRecyclerView.setLayoutManager(new MockLayoutManager() {
149c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            @Override
150c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            public Parcelable onSaveInstanceState() {
151c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                return null;
152c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            }
153c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        });
154c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(3));
155c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        Parcel parcel = Parcel.obtain();
156c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        String parcelSuffix = UUID.randomUUID().toString();
157c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        Parcelable savedState = mRecyclerView.onSaveInstanceState();
158c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        savedState.writeToParcel(parcel, 0);
159c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        parcel.writeString(parcelSuffix);
160c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
161c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        // reset position for reading
162c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        parcel.setDataPosition(0);
163c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        RecyclerView restored = new RecyclerView(mContext);
164c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        restored.setLayoutManager(new MockLayoutManager());
165c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(3));
166c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        // restore
167c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
168c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        restored.onRestoreInstanceState(savedState);
169c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
170c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
171c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                parcel.readString());
172c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
173c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
174c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    }
175c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
176c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    public void testSavedState() throws InterruptedException {
177c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        MockLayoutManager mlm = new MockLayoutManager();
178c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        mRecyclerView.setLayoutManager(mlm);
179c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        mRecyclerView.setAdapter(new MockAdapter(3));
180c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        layout();
181c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        Parcelable savedState = mRecyclerView.onSaveInstanceState();
182c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        // we append a suffix to the parcelable to test out of bounds
183c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        String parcelSuffix = UUID.randomUUID().toString();
184c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        Parcel parcel = Parcel.obtain();
185c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        savedState.writeToParcel(parcel, 0);
186c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        parcel.writeString(parcelSuffix);
187c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
188c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        // reset for reading
189c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        parcel.setDataPosition(0);
190c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        // re-create
191c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
192c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
193c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        RecyclerView restored = new RecyclerView(mContext);
194c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        MockLayoutManager mlmRestored = new MockLayoutManager();
195c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        restored.setLayoutManager(mlmRestored);
196c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        restored.setAdapter(new MockAdapter(3));
197c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        restored.onRestoreInstanceState(savedState);
198c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
199c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
200c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                parcel.readString());
201c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
202c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertEquals("uuid in layout manager should be preserved properly", mlm.mUuid,
203c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                mlmRestored.mUuid);
204c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        assertNotSame("stateless parameter should not be preserved", mlm.mLayoutCount,
205c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                mlmRestored.mLayoutCount);
206c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        layout();
207c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    }
208c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
209c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    static class MockLayoutManager extends RecyclerView.LayoutManager {
210edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
211edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        int mLayoutCount = 0;
212edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
213edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        int mAdapterChangedCount = 0;
214edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
215edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        RecyclerView.Adapter mPrevAdapter;
216edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
217edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        RecyclerView.Adapter mNextAdapter;
218edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
219c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        String mUuid = UUID.randomUUID().toString();
220c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
221edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
222edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
223edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                RecyclerView.Adapter newAdapter) {
224edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            super.onAdapterChanged(oldAdapter, newAdapter);
225edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            mPrevAdapter = oldAdapter;
226edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            mNextAdapter = newAdapter;
227edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            mAdapterChangedCount++;
228edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
229edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
230edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
231d4a794983364c7b1801638abc7f332abee12b6e6Yigit Boyar        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
232edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            mLayoutCount += 1;
233edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
234edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
235edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
236c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public Parcelable onSaveInstanceState() {
237c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            LayoutManagerSavedState lss = new LayoutManagerSavedState();
238c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            lss.mUuid = mUuid;
239c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            return lss;
240c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
241c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
242c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        @Override
243c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public void onRestoreInstanceState(Parcelable state) {
244c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            super.onRestoreInstanceState(state);
245c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            if (state instanceof LayoutManagerSavedState) {
246c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                mUuid = ((LayoutManagerSavedState) state).mUuid;
247c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            }
248c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
249c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
250c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        @Override
251edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
252edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
253edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                    ViewGroup.LayoutParams.WRAP_CONTENT);
254edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
255edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
256edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public void assertPrevNextAdapters(String message, RecyclerView.Adapter prevAdapter,
257edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                RecyclerView.Adapter nextAdapter) {
258edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            assertSame(message, prevAdapter, mPrevAdapter);
259edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            assertSame(message, nextAdapter, mNextAdapter);
260edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
261edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
262edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public void assertPrevNextAdapters(RecyclerView.Adapter prevAdapter,
263edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                RecyclerView.Adapter nextAdapter) {
264edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            assertPrevNextAdapters("Adapters from onAdapterChanged callback should match",
265edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar                    prevAdapter, nextAdapter);
266edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
267bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
268bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        @Override
269bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
270bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                RecyclerView.State state) {
271bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            return dx;
272bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
273bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
274bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        @Override
275bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
276bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar                RecyclerView.State state) {
277bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            return dy;
278bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
279bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
280bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        @Override
281bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        public boolean canScrollHorizontally() {
282bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            return true;
283bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
284bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar
285bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        @Override
286bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        public boolean canScrollVertically() {
287bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar            return true;
288bb6ebab3b3b85ec20b3bc262289a2460705322f5Yigit Boyar        }
289edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
290edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
291c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    static class LayoutManagerSavedState implements Parcelable {
292c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
293c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        String mUuid;
294c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
295c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public LayoutManagerSavedState(Parcel in) {
296c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            mUuid = in.readString();
297c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
298c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
299c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public LayoutManagerSavedState() {
300c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
301c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
302c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
303c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        @Override
304c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public int describeContents() {
305c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            return 0;
306c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
307c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
308c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        @Override
309c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public void writeToParcel(Parcel dest, int flags) {
310c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            dest.writeString(mUuid);
311c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        }
312c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
313c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        public static final Parcelable.Creator<LayoutManagerSavedState> CREATOR
314c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                = new Parcelable.Creator<LayoutManagerSavedState>() {
315c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            @Override
316c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            public LayoutManagerSavedState createFromParcel(Parcel in) {
317c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                return new LayoutManagerSavedState(in);
318c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            }
319c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
320c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            @Override
321c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            public LayoutManagerSavedState[] newArray(int size) {
322c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar                return new LayoutManagerSavedState[size];
323c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar            }
324c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        };
325c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    }
326c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar
327c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    static class MockAdapter extends RecyclerView.Adapter {
328edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
329edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        private int mCount = 0;
330edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
331d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
332c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar        MockAdapter(int count) {
333edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            this.mCount = count;
334edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
335edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
336edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
337edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
338edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            return new MockViewHolder(new TextView(parent.getContext()));
339edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
340edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
341edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
342edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
343edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
344edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
345edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
346edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        @Override
347edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public int getItemCount() {
348edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            return mCount;
349edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
350d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
351d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        void removeItems(int start, int count) {
352d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mCount -= count;
353d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            notifyItemRangeRemoved(start, count);
354d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
355d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
356d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        void addItems(int start, int count) {
357d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mCount += count;
358d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            notifyItemRangeInserted(start, count);
359d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
360edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
361edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar
362c30b4fceb76f45348c20f8b15096e1e13ff0c42fYigit Boyar    static class MockViewHolder extends RecyclerView.ViewHolder {
363115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar        public Object mItem;
364edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        public MockViewHolder(View itemView) {
365edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar            super(itemView);
366edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar        }
367edc25dd683986a905790b0e9ef124165b6dd8004Yigit Boyar    }
368b5f8b4fecb531aee6b359b4968409410aba90817Yigit Boyar}