1 /*
2  * Copyright (C) 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 package com.android.launcher3.touch;
17 
18 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH;
19 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
20 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSITIVE;
21 import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
22 import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
23 
24 import static org.junit.Assert.assertTrue;
25 import static org.mockito.Matchers.any;
26 import static org.mockito.Matchers.anyBoolean;
27 import static org.mockito.Matchers.anyFloat;
28 import static org.mockito.Mockito.doAnswer;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.verify;
32 
33 import android.util.Log;
34 import android.view.MotionEvent;
35 import android.view.ViewConfiguration;
36 
37 import androidx.test.InstrumentationRegistry;
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.launcher3.testcomponent.TouchEventGenerator;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 @SmallTest
50 @RunWith(AndroidJUnit4.class)
51 public class SingleAxisSwipeDetectorTest {
52 
53     private static final String TAG = SingleAxisSwipeDetectorTest.class.getSimpleName();
L(String s, Object... parts)54     public static void L(String s, Object... parts) {
55         Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
56     }
57 
58     private TouchEventGenerator mGenerator;
59     private SingleAxisSwipeDetector mDetector;
60     private int mTouchSlop;
61 
62     @Mock
63     private SingleAxisSwipeDetector.Listener mMockListener;
64 
65     @Mock
66     private ViewConfiguration mMockConfig;
67 
68     @Before
setup()69     public void setup() {
70         MockitoAnnotations.initMocks(this);
71         mGenerator = new TouchEventGenerator((ev) -> mDetector.onTouchEvent(ev));
72         ViewConfiguration orgConfig = ViewConfiguration
73                 .get(InstrumentationRegistry.getTargetContext());
74         doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
75                 .getScaledMaximumFlingVelocity();
76 
77         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
78         mDetector.setDetectableScrollConditions(DIRECTION_BOTH, false);
79         mTouchSlop = orgConfig.getScaledTouchSlop();
80         doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
81 
82         L("mTouchSlop=", mTouchSlop);
83     }
84 
85     @Test
testDragStart_verticalPositive()86     public void testDragStart_verticalPositive() {
87         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
88         mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
89         mGenerator.put(0, 100, 100);
90         mGenerator.move(0, 100, 100 - mTouchSlop);
91         // TODO: actually calculate the following parameters and do exact value checks.
92         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
93     }
94 
95     @Test
testDragStart_verticalNegative()96     public void testDragStart_verticalNegative() {
97         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
98         mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
99         mGenerator.put(0, 100, 100);
100         mGenerator.move(0, 100, 100 + mTouchSlop);
101         // TODO: actually calculate the following parameters and do exact value checks.
102         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
103     }
104 
105     @Test
testDragStart_failed()106     public void testDragStart_failed() {
107         mGenerator.put(0, 100, 100);
108         mGenerator.move(0, 100 + mTouchSlop, 100);
109         // TODO: actually calculate the following parameters and do exact value checks.
110         verify(mMockListener, never()).onDragStart(anyBoolean(), anyFloat());
111     }
112 
113     @Test
testDragStart_horizontalPositive()114     public void testDragStart_horizontalPositive() {
115         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
116         mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
117 
118         mGenerator.put(0, 100, 100);
119         mGenerator.move(0, 100 + mTouchSlop, 100);
120         // TODO: actually calculate the following parameters and do exact value checks.
121         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
122     }
123 
124     @Test
testDragStart_horizontalNegative()125     public void testDragStart_horizontalNegative() {
126         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
127         mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
128 
129         mGenerator.put(0, 100, 100);
130         mGenerator.move(0, 100 - mTouchSlop, 100);
131         // TODO: actually calculate the following parameters and do exact value checks.
132         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
133     }
134 
135     @Test
testDragStart_horizontalRtlPositive()136     public void testDragStart_horizontalRtlPositive() {
137         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
138         mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
139 
140         mGenerator.put(0, 100, 100);
141         mGenerator.move(0, 100 - mTouchSlop, 100);
142         // TODO: actually calculate the following parameters and do exact value checks.
143         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
144     }
145 
146     @Test
testDragStart_horizontalRtlNegative()147     public void testDragStart_horizontalRtlNegative() {
148         mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
149         mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
150 
151         mGenerator.put(0, 100, 100);
152         mGenerator.move(0, 100 + mTouchSlop, 100);
153         // TODO: actually calculate the following parameters and do exact value checks.
154         verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
155     }
156 
157     @Test
testDrag()158     public void testDrag() {
159         mGenerator.put(0, 100, 100);
160         mGenerator.move(0, 100, 100 + mTouchSlop);
161         // TODO: actually calculate the following parameters and do exact value checks.
162         verify(mMockListener).onDrag(anyFloat(), anyFloat(), any(MotionEvent.class));
163     }
164 
165     @Test
testDragEnd()166     public void testDragEnd() {
167         mGenerator.put(0, 100, 100);
168         mGenerator.move(0, 100, 100 + mTouchSlop);
169         mGenerator.move(0, 100, 100 + mTouchSlop * 2);
170         mGenerator.lift(0);
171         // TODO: actually calculate the following parameters and do exact value checks.
172         verify(mMockListener).onDragEnd(anyFloat());
173     }
174 
175     @Test
testInterleavedSetState()176     public void testInterleavedSetState() {
177         doAnswer(invocationOnMock -> {
178             // Sets state to IDLE. (Normally onDragEnd() will have state SETTLING.)
179             mDetector.finishedScrolling();
180             return null;
181         }).when(mMockListener).onDragEnd(anyFloat());
182 
183         mGenerator.put(0, 100, 100);
184         mGenerator.move(0, 100, 100 + mTouchSlop);
185         mGenerator.move(0, 100, 100 + mTouchSlop * 2);
186         mGenerator.lift(0);
187         verify(mMockListener).onDragEnd(anyFloat());
188         assertTrue("SwipeDetector should be IDLE but was " + mDetector.mState,
189                 mDetector.isIdleState());
190     }
191 }
192