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