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