1/* 2 * Copyright (C) 2015 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 android.support.v7.util; 18 19import android.app.Instrumentation; 20import android.os.SystemClock; 21import android.support.v7.widget.RecyclerView; 22import android.test.InstrumentationTestCase; 23import android.view.Gravity; 24import android.view.MotionEvent; 25import android.view.View; 26import android.view.ViewConfiguration; 27 28/** 29 * RV specific layout tests. 30 */ 31public class TouchUtils { 32 public static void tapView(Instrumentation inst, RecyclerView recyclerView, 33 View v) { 34 int[] xy = new int[2]; 35 v.getLocationOnScreen(xy); 36 37 final int viewWidth = v.getWidth(); 38 final int viewHeight = v.getHeight(); 39 40 final float x = xy[0] + (viewWidth / 2.0f); 41 float y = xy[1] + (viewHeight / 2.0f); 42 43 long downTime = SystemClock.uptimeMillis(); 44 long eventTime = SystemClock.uptimeMillis(); 45 46 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 47 MotionEvent.ACTION_DOWN, x, y, 0); 48 inst.sendPointerSync(event); 49 inst.waitForIdleSync(); 50 51 eventTime = SystemClock.uptimeMillis(); 52 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 53 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 54 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 55 inst.sendPointerSync(event); 56 inst.waitForIdleSync(); 57 58 eventTime = SystemClock.uptimeMillis(); 59 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 60 inst.sendPointerSync(event); 61 inst.waitForIdleSync(); 62 } 63 64 public static void touchAndCancelView(Instrumentation inst, View v) { 65 int[] xy = new int[2]; 66 v.getLocationOnScreen(xy); 67 68 final int viewWidth = v.getWidth(); 69 final int viewHeight = v.getHeight(); 70 71 final float x = xy[0] + (viewWidth / 2.0f); 72 float y = xy[1] + (viewHeight / 2.0f); 73 74 long downTime = SystemClock.uptimeMillis(); 75 long eventTime = SystemClock.uptimeMillis(); 76 77 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 78 MotionEvent.ACTION_DOWN, x, y, 0); 79 inst.sendPointerSync(event); 80 inst.waitForIdleSync(); 81 82 eventTime = SystemClock.uptimeMillis(); 83 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 84 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL, 85 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 86 inst.sendPointerSync(event); 87 inst.waitForIdleSync(); 88 89 } 90 91 public static void clickView(Instrumentation inst, View v) { 92 int[] xy = new int[2]; 93 v.getLocationOnScreen(xy); 94 95 final int viewWidth = v.getWidth(); 96 final int viewHeight = v.getHeight(); 97 98 final float x = xy[0] + (viewWidth / 2.0f); 99 float y = xy[1] + (viewHeight / 2.0f); 100 101 long downTime = SystemClock.uptimeMillis(); 102 long eventTime = SystemClock.uptimeMillis(); 103 104 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 105 MotionEvent.ACTION_DOWN, x, y, 0); 106 inst.sendPointerSync(event); 107 inst.waitForIdleSync(); 108 109 eventTime = SystemClock.uptimeMillis(); 110 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 111 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 112 x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); 113 inst.sendPointerSync(event); 114 inst.waitForIdleSync(); 115 116 eventTime = SystemClock.uptimeMillis(); 117 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 118 inst.sendPointerSync(event); 119 inst.waitForIdleSync(); 120 121 try { 122 Thread.sleep(1000); 123 } catch (InterruptedException e) { 124 e.printStackTrace(); 125 } 126 } 127 128 public static void longClickView(Instrumentation inst, View v) { 129 int[] xy = new int[2]; 130 v.getLocationOnScreen(xy); 131 132 final int viewWidth = v.getWidth(); 133 final int viewHeight = v.getHeight(); 134 135 final float x = xy[0] + (viewWidth / 2.0f); 136 float y = xy[1] + (viewHeight / 2.0f); 137 138 long downTime = SystemClock.uptimeMillis(); 139 long eventTime = SystemClock.uptimeMillis(); 140 141 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 142 MotionEvent.ACTION_DOWN, x, y, 0); 143 inst.sendPointerSync(event); 144 inst.waitForIdleSync(); 145 146 eventTime = SystemClock.uptimeMillis(); 147 final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); 148 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 149 x + touchSlop / 2, y + touchSlop / 2, 0); 150 inst.sendPointerSync(event); 151 inst.waitForIdleSync(); 152 153 try { 154 Thread.sleep((long) (ViewConfiguration.getLongPressTimeout() * 1.5f)); 155 } catch (InterruptedException e) { 156 e.printStackTrace(); 157 } 158 159 eventTime = SystemClock.uptimeMillis(); 160 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 161 inst.sendPointerSync(event); 162 inst.waitForIdleSync(); 163 } 164 165 public static void dragViewToTop(Instrumentation inst, View v) { 166 dragViewToTop(inst, v, calculateStepsForDistance(v.getTop())); 167 } 168 169 public static void dragViewToTop(Instrumentation inst, View v, int stepCount) { 170 int[] xy = new int[2]; 171 v.getLocationOnScreen(xy); 172 173 final int viewWidth = v.getWidth(); 174 final int viewHeight = v.getHeight(); 175 176 final float x = xy[0] + (viewWidth / 2.0f); 177 float fromY = xy[1] + (viewHeight / 2.0f); 178 float toY = 0; 179 180 drag(inst, x, x, fromY, toY, stepCount); 181 } 182 183 private static void getStartLocation(View v, int gravity, int[] xy) { 184 v.getLocationOnScreen(xy); 185 186 final int viewWidth = v.getWidth(); 187 final int viewHeight = v.getHeight(); 188 189 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) { 190 case Gravity.TOP: 191 break; 192 case Gravity.CENTER_VERTICAL: 193 xy[1] += viewHeight / 2; 194 break; 195 case Gravity.BOTTOM: 196 xy[1] += viewHeight - 1; 197 break; 198 default: 199 // Same as top -- do nothing 200 } 201 202 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { 203 case Gravity.LEFT: 204 break; 205 case Gravity.CENTER_HORIZONTAL: 206 xy[0] += viewWidth / 2; 207 break; 208 case Gravity.RIGHT: 209 xy[0] += viewWidth - 1; 210 break; 211 default: 212 // Same as left -- do nothing 213 } 214 } 215 216 public static int dragViewTo(Instrumentation inst, View v, int gravity, int toX, 217 int toY) { 218 int[] xy = new int[2]; 219 220 getStartLocation(v, gravity, xy); 221 222 final int fromX = xy[0]; 223 final int fromY = xy[1]; 224 225 int deltaX = fromX - toX; 226 int deltaY = fromY - toY; 227 228 int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY); 229 drag(inst, fromX, toX, fromY, toY, calculateStepsForDistance(distance)); 230 231 return distance; 232 } 233 234 public static int dragViewToX(Instrumentation inst, View v, int gravity, int toX) { 235 int[] xy = new int[2]; 236 237 getStartLocation(v, gravity, xy); 238 239 final int fromX = xy[0]; 240 final int fromY = xy[1]; 241 242 int deltaX = fromX - toX; 243 244 drag(inst, fromX, toX, fromY, fromY, calculateStepsForDistance(deltaX)); 245 246 return deltaX; 247 } 248 249 public static int dragViewToY(Instrumentation inst, View v, int gravity, int toY) { 250 int[] xy = new int[2]; 251 252 getStartLocation(v, gravity, xy); 253 254 final int fromX = xy[0]; 255 final int fromY = xy[1]; 256 257 int deltaY = fromY - toY; 258 259 drag(inst, fromX, fromX, fromY, toY, calculateStepsForDistance(deltaY)); 260 261 return deltaY; 262 } 263 264 265 public static void drag(Instrumentation inst, float fromX, float toX, float fromY, 266 float toY, int stepCount) { 267 long downTime = SystemClock.uptimeMillis(); 268 long eventTime = SystemClock.uptimeMillis(); 269 270 float y = fromY; 271 float x = fromX; 272 273 float yStep = (toY - fromY) / stepCount; 274 float xStep = (toX - fromX) / stepCount; 275 276 MotionEvent event = MotionEvent.obtain(downTime, eventTime, 277 MotionEvent.ACTION_DOWN, x, y, 0); 278 inst.sendPointerSync(event); 279 for (int i = 0; i < stepCount; ++i) { 280 y += yStep; 281 x += xStep; 282 eventTime = SystemClock.uptimeMillis(); 283 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 284 inst.sendPointerSync(event); 285 } 286 287 eventTime = SystemClock.uptimeMillis(); 288 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 289 inst.sendPointerSync(event); 290 inst.waitForIdleSync(); 291 } 292 293 private static int calculateStepsForDistance(int distance) { 294 return 1 + Math.abs(distance) / 10; 295 } 296} 297