1/*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.recyclerview.selection;
18
19import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
21
22import android.support.test.filters.SmallTest;
23import android.support.test.runner.AndroidJUnit4;
24import android.view.MotionEvent;
25
26import androidx.recyclerview.selection.testing.SelectionProbe;
27import androidx.recyclerview.selection.testing.SelectionTrackers;
28import androidx.recyclerview.selection.testing.TestAutoScroller;
29import androidx.recyclerview.selection.testing.TestEvents;
30import androidx.recyclerview.widget.RecyclerView;
31
32import org.junit.Before;
33import org.junit.Test;
34import org.junit.runner.RunWith;
35
36@RunWith(AndroidJUnit4.class)
37@SmallTest
38public class GestureSelectionHelperTest {
39
40    private static final MotionEvent DOWN = TestEvents.builder()
41            .action(MotionEvent.ACTION_DOWN)
42            .location(1, 1)
43            .build();
44
45    private static final MotionEvent MOVE = TestEvents.builder()
46            .action(MotionEvent.ACTION_MOVE)
47            .location(1, 1)
48            .build();
49
50    private static final MotionEvent UP = TestEvents.builder()
51            .action(MotionEvent.ACTION_UP)
52            .location(1, 1)
53            .build();
54
55    private GestureSelectionHelper mHelper;
56    private SelectionTracker<String> mSelectionTracker;
57    private SelectionProbe mSelection;
58    private OperationMonitor mMonitor;
59    private TestViewDelegate mView;
60
61    @Before
62    public void setUp() {
63        mSelectionTracker = SelectionTrackers.createStringTracker("gesture-selection-test", 100);
64        mSelection = new SelectionProbe(mSelectionTracker);
65        mMonitor = new OperationMonitor();
66        mView = new TestViewDelegate();
67        mHelper = new GestureSelectionHelper(
68                mSelectionTracker, mView, new TestAutoScroller(), mMonitor);
69    }
70
71    @Test
72    public void testIgnoresDownOnNoPosition() {
73        mView.mNextPosition = RecyclerView.NO_POSITION;
74        assertFalse(mHelper.onInterceptTouchEvent(null, DOWN));
75    }
76
77
78    @Test
79    public void testNoStartOnIllegalPosition() {
80        mView.mNextPosition = RecyclerView.NO_POSITION;
81        mHelper.onInterceptTouchEvent(null, DOWN);
82        mHelper.start();
83        assertFalse(mMonitor.isStarted());
84    }
85
86    @Test
87    public void testClaimsDownOnItem() {
88        mView.mNextPosition = 0;
89        assertTrue(mHelper.onInterceptTouchEvent(null, DOWN));
90    }
91
92    @Test
93    public void testClaimsMoveIfStarted() {
94        mView.mNextPosition = 0;
95        assertTrue(mHelper.onInterceptTouchEvent(null, DOWN));
96
97        // Normally, this is controller by the TouchSelectionHelper via a a long press gesture.
98        mSelectionTracker.select("1");
99        mSelectionTracker.anchorRange(1);
100        mHelper.start();
101        assertTrue(mHelper.onInterceptTouchEvent(null, MOVE));
102    }
103
104    @Test
105    public void testCreatesRangeSelection() {
106        mView.mNextPosition = 1;
107        mHelper.onInterceptTouchEvent(null, DOWN);
108        // Another way we are implicitly coupled to TouchInputHandler, is that we depend on
109        // long press to establish the initial anchor point. Without that we'll get an
110        // error when we try to extend the range.
111
112        mSelectionTracker.select("1");
113        mSelectionTracker.anchorRange(1);
114        mHelper.start();
115
116        mHelper.onTouchEvent(null, MOVE);
117
118        mView.mNextPosition = 9;
119        mHelper.onTouchEvent(null, MOVE);
120        mHelper.onTouchEvent(null, UP);
121
122        mSelection.assertRangeSelected(1,  9);
123    }
124
125    private static final class TestViewDelegate extends GestureSelectionHelper.ViewDelegate {
126
127        private int mNextPosition = RecyclerView.NO_POSITION;
128
129        @Override
130        int getHeight() {
131            return 1000;
132        }
133
134        @Override
135        int getItemUnder(MotionEvent e) {
136            return mNextPosition;
137        }
138
139        @Override
140        int getLastGlidedItemPosition(MotionEvent e) {
141            return mNextPosition;
142        }
143    }
144}
145