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