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.assertEquals;
20import static org.junit.Assert.assertNotNull;
21import static org.junit.Assert.assertNull;
22
23import android.graphics.Point;
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26
27import androidx.annotation.Nullable;
28import androidx.recyclerview.selection.ViewAutoScroller.ScrollHost;
29
30import org.junit.Before;
31import org.junit.Test;
32import org.junit.runner.RunWith;
33
34@RunWith(AndroidJUnit4.class)
35@SmallTest
36public final class ViewAutoScrollerTest {
37
38    private static final float SCROLL_THRESHOLD_RATIO = 0.125f;
39    private static final int VIEW_HEIGHT = 100;
40    private static final int TOP_Y_POINT = (int) (VIEW_HEIGHT * SCROLL_THRESHOLD_RATIO) - 1;
41    private static final int BOTTOM_Y_POINT =
42            VIEW_HEIGHT - (int) (VIEW_HEIGHT * SCROLL_THRESHOLD_RATIO) + 1;
43
44    private ViewAutoScroller mScroller;
45    private TestHost mHost;
46
47    @Before
48    public void setUp() {
49        mHost = new TestHost();
50        mScroller = new ViewAutoScroller(mHost, SCROLL_THRESHOLD_RATIO);
51    }
52
53    @Test
54    public void testNoScrollWhenOutOfScrollZone() {
55        mScroller.scroll(new Point(0, VIEW_HEIGHT / 2));
56        mHost.run();
57        mHost.assertNotScrolled();
58    }
59
60//    @Test
61//    public void testNoScrollWhenDisabled() {
62//        mScroller.reset();
63//        mScroller.scroll(mEvent.location(0, TOP_Y_POINT).build());
64//        mHost.assertNotScrolled();
65//    }
66
67    @Test
68    public void testMotionThreshold() {
69        mScroller.scroll(new Point(0, TOP_Y_POINT));
70        mHost.run();
71
72        mScroller.scroll(new Point(0, TOP_Y_POINT - 1));
73        mHost.run();
74
75        mHost.assertNotScrolled();
76    }
77
78    @Test
79    public void testMotionThreshold_Resets() {
80        int expectedScrollDistance = mScroller.computeScrollDistance(-21);
81        mScroller.scroll(new Point(0, TOP_Y_POINT));
82        mHost.run();
83        // We need enough y motion to overcome motion threshold
84        mScroller.scroll(new Point(0, TOP_Y_POINT - 20));
85        mHost.run();
86
87        mHost.reset();
88        // After resetting events should be required to cross the motion threshold
89        // before auto-scrolling again.
90        mScroller.reset();
91
92        mScroller.scroll(new Point(0, TOP_Y_POINT));
93        mHost.run();
94
95        mHost.assertNotScrolled();
96    }
97
98    @Test
99    public void testAutoScrolls_Top() {
100        int expectedScrollDistance = mScroller.computeScrollDistance(-21);
101        mScroller.scroll(new Point(0, TOP_Y_POINT));
102        mHost.run();
103        // We need enough y motion to overcome motion threshold
104        mScroller.scroll(new Point(0, TOP_Y_POINT - 20));
105        mHost.run();
106
107        mHost.assertScrolledBy(expectedScrollDistance);
108    }
109
110    @Test
111    public void testAutoScrolls_Bottom() {
112        int expectedScrollDistance = mScroller.computeScrollDistance(21);
113        mScroller.scroll(new Point(0, BOTTOM_Y_POINT));
114        mHost.run();
115        // We need enough y motion to overcome motion threshold
116        mScroller.scroll(new Point(0, BOTTOM_Y_POINT + 20));
117        mHost.run();
118
119        mHost.assertScrolledBy(expectedScrollDistance);
120    }
121
122    private final class TestHost extends ScrollHost {
123
124        private @Nullable Integer mScrollDistance;
125        private @Nullable Runnable mRunnable;
126
127        @Override
128        int getViewHeight() {
129            return VIEW_HEIGHT;
130        }
131
132        @Override
133        void scrollBy(int distance) {
134            mScrollDistance = distance;
135        }
136
137        @Override
138        void runAtNextFrame(Runnable r) {
139            mRunnable = r;
140        }
141
142        @Override
143        void removeCallback(Runnable r) {
144        }
145
146        private void reset() {
147            mScrollDistance = null;
148            mRunnable = null;
149        }
150
151        private void run() {
152            mRunnable.run();
153        }
154
155        private void assertNotScrolled() {
156            assertNull(mScrollDistance);
157        }
158
159        private void assertScrolledBy(int expectedDistance) {
160            assertNotNull(mScrollDistance);
161            assertEquals(expectedDistance, mScrollDistance.intValue());
162        }
163    }
164}
165