ItemTouchHelperTest.java revision 8a11e6829c522aa1efcc903afa4c01d337082eab
1e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar/*
2e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Copyright (C) 2015 The Android Open Source Project
3e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
4e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * you may not use this file except in compliance with the License.
6e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * You may obtain a copy of the License at
7e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
8e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar *
10e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * See the License for the specific language governing permissions and
14e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar * limitations under the License.
15e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar */
16e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
17e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarpackage android.support.v7.widget.helper;
18e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
19754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static android.support.v7.widget.helper.ItemTouchHelper.END;
20754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
21754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
22754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static android.support.v7.widget.helper.ItemTouchHelper.START;
23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback;
240a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar
25754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertEquals;
26754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertNotNull;
27754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport static org.junit.Assert.assertTrue;
2845d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas
2945d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikasimport android.os.Build;
308a11e6829c522aa1efcc903afa4c01d337082eabChris Craikimport android.support.annotation.NonNull;
3135232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikasimport android.support.test.filters.LargeTest;
3245d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikasimport android.support.test.filters.SdkSuppress;
33fb06780abd4844c38173c183afff0fca3d954193Aurimas Liutikasimport android.support.test.filters.Suppress;
340a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.test.runner.AndroidJUnit4;
356d20a527c6adad79f5fb48ec8bc02d738db1e1d2Aurimas Liutikasimport android.support.testutils.PollingCheck;
36350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapardimport android.support.v4.util.Pair;
370a017072206f93474ccd2706e7983c2ff778b904Yigit Boyarimport android.support.v7.util.TouchUtils;
38e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
39e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.RecyclerView;
40e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.support.v7.widget.WrappedRecyclerView;
41e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport android.view.Gravity;
42350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapardimport android.view.View;
4345d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas
4445d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikasimport org.junit.Test;
4545d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikasimport org.junit.runner.RunWith;
46e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
47e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport java.util.ArrayList;
48e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarimport java.util.List;
49e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
5035232c6eaeb9b99f390cb8ef0ac83bf45fa0b3faAurimas Liutikas@LargeTest
510a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar@RunWith(AndroidJUnit4.class)
52e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyarpublic class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
53e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
54350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    private static class RecyclerViewState {
55350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        public TestAdapter mAdapter;
56350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        public TestLayoutManager mLayoutManager;
57350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        public WrappedRecyclerView mWrappedRecyclerView;
58350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    }
59e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
60e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private LoggingCalback mCalback;
61e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
62e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private LoggingItemTouchHelper mItemTouchHelper;
63e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
64e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private Boolean mSetupRTL;
65e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
66e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public ItemTouchHelperTest() {
67e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        super(false);
68e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
69e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
70350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    private RecyclerViewState setupRecyclerView() throws Throwable {
71350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        RecyclerViewState rvs = new RecyclerViewState();
72350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mWrappedRecyclerView = inflateWrappedRV();
73350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mAdapter = new TestAdapter(10);
74350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager = new TestLayoutManager() {
75e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            @Override
76e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
77e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                detachAndScrapAttachedViews(recycler);
78e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                layoutRange(recycler, 0, Math.min(5, state.getItemCount()));
79e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                layoutLatch.countDown();
80e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
81e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
82e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            @Override
83e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public boolean canScrollHorizontally() {
84e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
85e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
86e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
87e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            @Override
88e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            public boolean supportsPredictiveItemAnimations() {
89e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                return false;
90e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
91e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        };
92350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mWrappedRecyclerView.setFakeRTL(mSetupRTL);
93350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mWrappedRecyclerView.setAdapter(rvs.mAdapter);
94350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mWrappedRecyclerView.setLayoutManager(rvs.mLayoutManager);
95350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        return rvs;
96350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    }
97350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
98350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    private RecyclerViewState setupItemTouchHelper(final RecyclerViewState rvs, int dragDirs,
99350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            int swipeDirs) throws Throwable {
100e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mCalback = new LoggingCalback(dragDirs, swipeDirs);
101e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mItemTouchHelper = new LoggingItemTouchHelper(mCalback);
10242e7d6fafcde7bfe261dd7d8d75ee53ca0cd6790Aurimas Liutikas        mActivityRule.runOnUiThread(new Runnable() {
103629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar            @Override
104629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar            public void run() {
105350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                mItemTouchHelper.attachToRecyclerView(rvs.mWrappedRecyclerView);
106629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar            }
107629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar        });
108629687bba8da1a73c48d8fe87393a13581ce46caYigit Boyar
109350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        return rvs;
110e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
111e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1120a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1130a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeLeft() throws Throwable {
114e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(LEFT, LEFT | RIGHT, -getActivity().getWindow().getDecorView().getWidth());
115e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
116e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1170a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1180a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeRight() throws Throwable {
119e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(RIGHT, LEFT | RIGHT, getActivity().getWindow().getDecorView().getWidth());
120e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
121e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1220a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1230a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeStart() throws Throwable {
124e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(START, START | END, -getActivity().getWindow().getDecorView().getWidth());
125e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
126e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
1270a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1280a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeEnd() throws Throwable {
129e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(END, START | END, getActivity().getWindow().getDecorView().getWidth());
130e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
131e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
132fb06780abd4844c38173c183afff0fca3d954193Aurimas Liutikas    // Test is disabled as it is flaky.
133fb06780abd4844c38173c183afff0fca3d954193Aurimas Liutikas    @Suppress
13445d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
1350a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1360a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeStartInRTL() throws Throwable {
137e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mSetupRTL = true;
138e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(START, START | END, getActivity().getWindow().getDecorView().getWidth());
139e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
140e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
14145d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
1420a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    @Test
1430a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar    public void swipeEndInRTL() throws Throwable {
144e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        mSetupRTL = true;
145e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        basicSwipeTest(END, START | END, -getActivity().getWindow().getDecorView().getWidth());
146e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
147e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
148350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    @Test
149350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    public void attachToNullRecycleViewDuringLongPress() throws Throwable {
150350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
151350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.expectLayouts(1);
152350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        setRecyclerView(rvs.mWrappedRecyclerView);
153350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.waitForLayout(1);
154350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
155350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerView.ViewHolder target = mRecyclerView
156350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                .findViewHolderForAdapterPosition(1);
157350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
158350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            @Override
159350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            public boolean onLongClick(View v) {
160350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                mItemTouchHelper.attachToRecyclerView(null);
161350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                return false;
162350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            }
163350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        });
164350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        TouchUtils.longClickView(getInstrumentation(), target.itemView);
165350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    }
166350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
167350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    @Test
168350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    public void attachToAnotherRecycleViewDuringLongPress() throws Throwable {
169350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerViewState rvs2 = setupRecyclerView();
170350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs2.mLayoutManager.expectLayouts(1);
171350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        mActivityRule.runOnUiThread(new Runnable() {
172350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            @Override
173350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            public void run() {
174350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                getActivity().getContainer().addView(rvs2.mWrappedRecyclerView);
175350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            }
176350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        });
177350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs2.mLayoutManager.waitForLayout(1);
178350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
179350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
180350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.expectLayouts(1);
181350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        setRecyclerView(rvs.mWrappedRecyclerView);
182350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.waitForLayout(1);
183350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
184350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerView.ViewHolder target = mRecyclerView
185350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                .findViewHolderForAdapterPosition(1);
186350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
187350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            @Override
188350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            public boolean onLongClick(View v) {
189350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                mItemTouchHelper.attachToRecyclerView(rvs2.mWrappedRecyclerView);
190350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard                return false;
191350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            }
192350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        });
193350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        TouchUtils.longClickView(getInstrumentation(), target.itemView);
194350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        assertEquals(0, mCalback.mHasDragFlag.size());
195350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard    }
196350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
197e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    public void basicSwipeTest(int dir, int swipeDirs, int targetX) throws Throwable {
198350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), 0, swipeDirs);
199350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.expectLayouts(1);
200350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        setRecyclerView(rvs.mWrappedRecyclerView);
201350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.waitForLayout(1);
202e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
203e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final RecyclerView.ViewHolder target = mRecyclerView
204e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                .findViewHolderForAdapterPosition(1);
2050a017072206f93474ccd2706e7983c2ff778b904Yigit Boyar        TouchUtils.dragViewToX(getInstrumentation(), target.itemView, Gravity.CENTER, targetX);
206277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas
207277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas        PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() {
208277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas            @Override
209277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas            public boolean canProceed() {
210277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas                return mCalback.getSwipe(target) != null;
211277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas            }
212277b9d6d56ba5a21240710b27c6e431498392a08Aurimas Liutikas        });
213e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final SwipeRecord swipe = mCalback.getSwipe(target);
214e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertNotNull(swipe);
215e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertEquals(dir, swipe.dir);
216e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertEquals(1, mItemTouchHelper.mRecoverAnimations.size());
217e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertEquals(1, mItemTouchHelper.mPendingCleanup.size());
218e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        // get rid of the view
219350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.expectLayouts(1);
220350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mAdapter.deleteAndNotify(1, 1);
221350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        rvs.mLayoutManager.waitForLayout(1);
222e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        waitForAnimations();
223e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertEquals(0, mItemTouchHelper.mRecoverAnimations.size());
224e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertEquals(0, mItemTouchHelper.mPendingCleanup.size());
225e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        assertTrue(mCalback.isCleared(target));
226e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
227e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
228e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private void waitForAnimations() throws InterruptedException {
229e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        while (mRecyclerView.getItemAnimator().isRunning()) {
230e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            Thread.sleep(100);
231e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
232e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
233e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
234e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static class LoggingCalback extends SimpleCallback {
235e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
236e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private List<MoveRecord> mMoveRecordList = new ArrayList<MoveRecord>();
237e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
238e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private List<SwipeRecord> mSwipeRecords = new ArrayList<SwipeRecord>();
239e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
240e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        private List<RecyclerView.ViewHolder> mCleared = new ArrayList<RecyclerView.ViewHolder>();
241e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
242350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        public List<Pair<RecyclerView, RecyclerView.ViewHolder>> mHasDragFlag = new ArrayList<>();
243350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
24445d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas        LoggingCalback(int dragDirs, int swipeDirs) {
245e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            super(dragDirs, swipeDirs);
246e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
247e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
248e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2498a11e6829c522aa1efcc903afa4c01d337082eabChris Craik        public boolean onMove(@NonNull RecyclerView recyclerView,
2508a11e6829c522aa1efcc903afa4c01d337082eabChris Craik                @NonNull RecyclerView.ViewHolder viewHolder,
2518a11e6829c522aa1efcc903afa4c01d337082eabChris Craik                @NonNull RecyclerView.ViewHolder target) {
252e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mMoveRecordList.add(new MoveRecord(viewHolder, target));
253e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return true;
254e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
255e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
256e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2578a11e6829c522aa1efcc903afa4c01d337082eabChris Craik        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
258e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mSwipeRecords.add(new SwipeRecord(viewHolder, direction));
259e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
260e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
261e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public MoveRecord getMove(RecyclerView.ViewHolder vh) {
262e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (MoveRecord move : mMoveRecordList) {
263e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (move.from == vh) {
264e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return move;
265e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
266e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
267e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
268e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
269e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
270e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        @Override
2718a11e6829c522aa1efcc903afa4c01d337082eabChris Craik        public void clearView(@NonNull RecyclerView recyclerView,
2728a11e6829c522aa1efcc903afa4c01d337082eabChris Craik                @NonNull RecyclerView.ViewHolder viewHolder) {
273e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            super.clearView(recyclerView, viewHolder);
274e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            mCleared.add(viewHolder);
275e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
276e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
277350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        @Override
278350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        boolean hasDragFlag(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
279350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            mHasDragFlag.add(new Pair<>(recyclerView, viewHolder));
280350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard            return super.hasDragFlag(recyclerView, viewHolder);
281350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard        }
282350a38a3cc040891c3f94b1fd9c1642aa29a7db3shepshapard
283e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public SwipeRecord getSwipe(RecyclerView.ViewHolder vh) {
284e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            for (SwipeRecord swipe : mSwipeRecords) {
285e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                if (swipe.viewHolder == vh) {
286e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                    return swipe;
287e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar                }
288e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            }
289e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return null;
290e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
291e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
292e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public boolean isCleared(RecyclerView.ViewHolder vh) {
293e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            return mCleared.contains(vh);
294e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
295e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
296e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
297e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static class LoggingItemTouchHelper extends ItemTouchHelper {
298e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
299e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public LoggingItemTouchHelper(Callback callback) {
300e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            super(callback);
301e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
302e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
303e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
304e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static class SwipeRecord {
305e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
306e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        RecyclerView.ViewHolder viewHolder;
307e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
308e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        int dir;
309e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
310e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        public SwipeRecord(RecyclerView.ViewHolder viewHolder, int dir) {
311e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            this.viewHolder = viewHolder;
312e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            this.dir = dir;
313e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
314e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
315e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
316e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    private static class MoveRecord {
317e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
318e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        final int fromPos, toPos;
319e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
320e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        RecyclerView.ViewHolder from, to;
321e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar
32245d07c8efb62ee378db48884989e5b05b5494981Aurimas Liutikas        MoveRecord(RecyclerView.ViewHolder from, RecyclerView.ViewHolder to) {
323e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            this.from = from;
324e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            this.to = to;
325e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            fromPos = from.getAdapterPosition();
326e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar            toPos = to.getAdapterPosition();
327e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar        }
328e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar    }
329e71a1df9b3c0e1bd3c21a1b3dd20a41790d4a950Yigit Boyar}
330