blob: 9174fb83d1c398078ac9ba6478b55bbfc09cff93 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 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.test;
18
19import android.app.Instrumentation;
20import android.os.SystemClock;
21import android.view.Gravity;
22import android.view.MotionEvent;
23import android.view.View;
24import android.view.ViewConfiguration;
25import android.view.ViewGroup;
26
27/**
28 * Reusable methods for generating touch events. These methods can be used with
29 * InstrumentationTestCase or ActivityTestCases to simulate user interaction with
30 * the application through a touch screen.
31 */
32public class TouchUtils {
33
34 /**
35 * Simulate touching in the center of the screen and dragging one quarter of the way down
36 * @param test The test cast that is being run
37 */
38 public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
39 int screenHeight = test.getActivity().getWindowManager().getDefaultDisplay().getHeight();
40 int screenWidth = test.getActivity().getWindowManager().getDefaultDisplay().getWidth();
41
42 final float x = screenWidth / 2.0f;
43 final float fromY = screenHeight * 0.5f;
44 final float toY = screenHeight * 0.75f;
45
46 drag(test, x, x, fromY, toY, 4);
47 }
48
49 /**
50 * Simulate touching in the center of the screen and dragging one quarter of the way up
51 * @param test The test cast that is being run
52 */
53 public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
54 int screenHeight = test.getActivity().getWindowManager().getDefaultDisplay().getHeight();
55 int screenWidth = test.getActivity().getWindowManager().getDefaultDisplay().getWidth();
56
57 final float x = screenWidth / 2.0f;
58 final float fromY = screenHeight * 0.5f;
59 final float toY = screenHeight * 0.25f;
60
61 drag(test, x, x, fromY, toY, 4);
62 }
63
64 /**
65 * Scroll a VirewGroup to the bottom by repeatedly calling
66 * {@link #dragQuarterScreenUp(ActivityInstrumentationTestCase)}
67 *
68 * @param test The test cast that is being run
69 * @param v The ViewGroup that should be dragged
70 */
71 public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
72 View firstChild;
73 int firstId = Integer.MIN_VALUE;
74 int firstTop = Integer.MIN_VALUE;
75 int prevId;
76 int prevTop;
77 do {
78 prevId = firstId;
79 prevTop = firstTop;
80 TouchUtils.dragQuarterScreenUp(test);
81 firstChild = v.getChildAt(0);
82 firstId = firstChild.getId();
83 firstTop = firstChild.getTop();
84 } while ((prevId != firstId) || (prevTop != firstTop));
85 }
86
87 /**
88 * Scroll a ViewGroup to the top by repeatedly calling
89 * {@link #dragQuarterScreenDown(ActivityInstrumentationTestCase)}
90 *
91 * @param test The test cast that is being run
92 * @param v The ViewGroup that should be dragged
93 */
94 public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
95 View firstChild;
96 int firstId = Integer.MIN_VALUE;
97 int firstTop = Integer.MIN_VALUE;
98 int prevId;
99 int prevTop;
100 do {
101 prevId = firstId;
102 prevTop = firstTop;
103 TouchUtils.dragQuarterScreenDown(test);
104 firstChild = v.getChildAt(0);
105 firstId = firstChild.getId();
106 firstTop = firstChild.getTop();
107 } while ((prevId != firstId) || (prevTop != firstTop));
108 }
109
110 /**
111 * Simulate touching the center of a view and dragging to the bottom of the screen.
112 *
113 * @param test The test cast that is being run
114 * @param v The view that should be dragged
115 */
116 public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
117 dragViewToBottom(test, v, 4);
118 }
119
120 /**
121 * Simulate touching the center of a view and dragging to the bottom of the screen.
122 *
123 * @param test The test cast that is being run
124 * @param v The view that should be dragged
125 * @param stepCount How many move steps to include in the drag
126 */
127 public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v, int stepCount) {
128 int screenHeight = test.getActivity().getWindowManager().getDefaultDisplay().getHeight();
129
130 int[] xy = new int[2];
131 v.getLocationOnScreen(xy);
132
133 final int viewWidth = v.getWidth();
134 final int viewHeight = v.getHeight();
135
136 final float x = xy[0] + (viewWidth / 2.0f);
137 float fromY = xy[1] + (viewHeight / 2.0f);
138 float toY = screenHeight - 1;
139
140 drag(test, x, x, fromY, toY, stepCount);
141 }
142
143 /**
144 * Simulate touching the center of a view and releasing quickly (before the tap timeout).
145 *
146 * @param test The test cast that is being run
147 * @param v The view that should be clicked
148 */
149 public static void tapView(InstrumentationTestCase test, View v) {
150
151 int[] xy = new int[2];
152 v.getLocationOnScreen(xy);
153
154 final int viewWidth = v.getWidth();
155 final int viewHeight = v.getHeight();
156
157 final float x = xy[0] + (viewWidth / 2.0f);
158 float y = xy[1] + (viewHeight / 2.0f);
159
160 Instrumentation inst = test.getInstrumentation();
161
162 long downTime = SystemClock.uptimeMillis();
163 long eventTime = SystemClock.uptimeMillis();
164
165 MotionEvent event = MotionEvent.obtain(downTime, eventTime,
166 MotionEvent.ACTION_DOWN, x, y, 0);
167 inst.sendPointerSync(event);
168 inst.waitForIdleSync();
169
170 eventTime = SystemClock.uptimeMillis();
171 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
172 x + (ViewConfiguration.getTouchSlop() / 2.0f),
173 y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
174 inst.sendPointerSync(event);
175 inst.waitForIdleSync();
176
177 eventTime = SystemClock.uptimeMillis();
178 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
179 inst.sendPointerSync(event);
180 inst.waitForIdleSync();
181 }
182
183 /**
184 * Simulate touching the center of a view and cancelling (so no on click should
185 * fire, etc).
186 *
187 * @param test The test cast that is being run
188 * @param v The view that should be clicked
189 */
190 public static void touchAndCancelView(InstrumentationTestCase test, View v) {
191 int[] xy = new int[2];
192 v.getLocationOnScreen(xy);
193
194 final int viewWidth = v.getWidth();
195 final int viewHeight = v.getHeight();
196
197 final float x = xy[0] + (viewWidth / 2.0f);
198 float y = xy[1] + (viewHeight / 2.0f);
199
200 Instrumentation inst = test.getInstrumentation();
201
202 long downTime = SystemClock.uptimeMillis();
203 long eventTime = SystemClock.uptimeMillis();
204
205 MotionEvent event = MotionEvent.obtain(downTime, eventTime,
206 MotionEvent.ACTION_DOWN, x, y, 0);
207 inst.sendPointerSync(event);
208 inst.waitForIdleSync();
209
210 eventTime = SystemClock.uptimeMillis();
211 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL,
212 x + (ViewConfiguration.getTouchSlop() / 2.0f),
213 y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
214 inst.sendPointerSync(event);
215 inst.waitForIdleSync();
216
217 }
218
219 /**
220 * Simulate touching the center of a view and releasing.
221 *
222 * @param test The test cast that is being run
223 * @param v The view that should be clicked
224 */
225 public static void clickView(InstrumentationTestCase test, View v) {
226
227 int[] xy = new int[2];
228 v.getLocationOnScreen(xy);
229
230 final int viewWidth = v.getWidth();
231 final int viewHeight = v.getHeight();
232
233 final float x = xy[0] + (viewWidth / 2.0f);
234 float y = xy[1] + (viewHeight / 2.0f);
235
236 Instrumentation inst = test.getInstrumentation();
237
238 long downTime = SystemClock.uptimeMillis();
239 long eventTime = SystemClock.uptimeMillis();
240
241 MotionEvent event = MotionEvent.obtain(downTime, eventTime,
242 MotionEvent.ACTION_DOWN, x, y, 0);
243 inst.sendPointerSync(event);
244 inst.waitForIdleSync();
245
246
247 eventTime = SystemClock.uptimeMillis();
248 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
249 x + (ViewConfiguration.getTouchSlop() / 2.0f),
250 y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
251 inst.sendPointerSync(event);
252 inst.waitForIdleSync();
253
254 eventTime = SystemClock.uptimeMillis();
255 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
256 inst.sendPointerSync(event);
257 inst.waitForIdleSync();
258
259 try {
260 Thread.sleep(1000);
261 } catch (InterruptedException e) {
262 e.printStackTrace();
263 }
264 }
265
266 /**
267 * Simulate touching the center of a view, holding until it is a long press, and then releasing.
268 *
269 * @param test The test cast that is being run
270 * @param v The view that should be clicked
271 */
272 public static void longClickView(ActivityInstrumentationTestCase test, View v) {
273 int[] xy = new int[2];
274 v.getLocationOnScreen(xy);
275
276 final int viewWidth = v.getWidth();
277 final int viewHeight = v.getHeight();
278
279 final float x = xy[0] + (viewWidth / 2.0f);
280 float y = xy[1] + (viewHeight / 2.0f);
281
282 Instrumentation inst = test.getInstrumentation();
283
284 long downTime = SystemClock.uptimeMillis();
285 long eventTime = SystemClock.uptimeMillis();
286
287 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
288 inst.sendPointerSync(event);
289 inst.waitForIdleSync();
290
291 eventTime = SystemClock.uptimeMillis();
292 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
293 x + ViewConfiguration.getTouchSlop() / 2,
294 y + ViewConfiguration.getTouchSlop() / 2, 0);
295 inst.sendPointerSync(event);
296 inst.waitForIdleSync();
297
298 try {
299 Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
300 } catch (InterruptedException e) {
301 e.printStackTrace();
302 }
303
304 eventTime = SystemClock.uptimeMillis();
305 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
306 inst.sendPointerSync(event);
307 inst.waitForIdleSync();
308 }
309
310 /**
311 * Simulate touching the center of a view and dragging to the top of the screen.
312 *
313 * @param test The test cast that is being run
314 * @param v The view that should be dragged
315 */
316 public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
317 dragViewToTop(test, v, 4);
318 }
319
320 /**
321 * Simulate touching the center of a view and dragging to the top of the screen.
322 *
323 * @param test The test cast that is being run
324 * @param v The view that should be dragged
325 * @param stepCount How many move steps to include in the drag
326 */
327 public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
328 int[] xy = new int[2];
329 v.getLocationOnScreen(xy);
330
331 final int viewWidth = v.getWidth();
332 final int viewHeight = v.getHeight();
333
334 final float x = xy[0] + (viewWidth / 2.0f);
335 float fromY = xy[1] + (viewHeight / 2.0f);
336 float toY = 0;
337
338 drag(test, x, x, fromY, toY, stepCount);
339 }
340
341 /**
342 * Get the location of a view. Use the gravity param to specify which part of the view to
343 * return.
344 *
345 * @param v View to find
346 * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
347 * RIGHT)
348 * @param xy Result
349 */
350 private static void getStartLocation(View v, int gravity, int[] xy) {
351 v.getLocationOnScreen(xy);
352
353 final int viewWidth = v.getWidth();
354 final int viewHeight = v.getHeight();
355
356 switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
357 case Gravity.TOP:
358 break;
359 case Gravity.CENTER_VERTICAL:
360 xy[1] += viewHeight / 2;
361 break;
362 case Gravity.BOTTOM:
363 xy[1] += viewHeight - 1;
364 break;
365 default:
366 // Same as top -- do nothing
367 }
368
369 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
370 case Gravity.LEFT:
371 break;
372 case Gravity.CENTER_HORIZONTAL:
373 xy[0] += viewWidth / 2;
374 break;
375 case Gravity.RIGHT:
376 xy[0] += viewWidth - 1;
377 break;
378 default:
379 // Same as left -- do nothing
380 }
381 }
382
383 /**
384 * Simulate touching a view and dragging it by the specified amount.
385 *
386 * @param test The test cast that is being run
387 * @param v The view that should be dragged
388 * @param gravity Which part of the view to use for the initial down event. A combination of
389 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
390 * @param deltaX Amount to drag horizontally in pixels
391 * @param deltaY Amount to drag vertically in pixels
392 *
393 * @return distance in pixels covered by the drag
394 */
395 public static int dragViewBy(ActivityInstrumentationTestCase test, View v, int gravity, int deltaX,
396 int deltaY) {
397 int[] xy = new int[2];
398
399 getStartLocation(v, gravity, xy);
400
401 final int fromX = xy[0];
402 final int fromY = xy[1];
403
404 int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
405
406 drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
407
408 return distance;
409 }
410
411 /**
412 * Simulate touching a view and dragging it to a specified location.
413 *
414 * @param test The test cast that is being run
415 * @param v The view that should be dragged
416 * @param gravity Which part of the view to use for the initial down event. A combination of
417 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
418 * @param toX Final location of the view after dragging
419 * @param toY Final location of the view after dragging
420 *
421 * @return distance in pixels covered by the drag
422 */
423 public static int dragViewTo(ActivityInstrumentationTestCase test, View v, int gravity, int toX, int toY) {
424 int[] xy = new int[2];
425
426 getStartLocation(v, gravity, xy);
427
428 final int fromX = xy[0];
429 final int fromY = xy[1];
430
431 int deltaX = fromX - toX;
432 int deltaY = fromY - toY;
433
434 int distance = (int)Math.sqrt(deltaX * deltaX + deltaY * deltaY);
435 drag(test, fromX, toX, fromY, toY, distance);
436
437 return distance;
438 }
439
440 /**
441 * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
442 *
443 * @param test The test cast that is being run
444 * @param v The view that should be dragged
445 * @param gravity Which part of the view to use for the initial down event. A combination of
446 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
447 * @param toX Final location of the view after dragging
448 *
449 * @return distance in pixels covered by the drag
450 */
451 public static int dragViewToX(ActivityInstrumentationTestCase test, View v, int gravity, int toX) {
452 int[] xy = new int[2];
453
454 getStartLocation(v, gravity, xy);
455
456 final int fromX = xy[0];
457 final int fromY = xy[1];
458
459 int deltaX = fromX - toX;
460
461 drag(test, fromX, toX, fromY, fromY, deltaX);
462
463 return deltaX;
464 }
465
466 /**
467 * Simulate touching a view and dragging it to a specified location. Only moves vertically.
468 *
469 * @param test The test cast that is being run
470 * @param v The view that should be dragged
471 * @param gravity Which part of the view to use for the initial down event. A combination of
472 * (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
473 * @param toY Final location of the view after dragging
474 *
475 * @return distance in pixels covered by the drag
476 */
477 public static int dragViewToY(ActivityInstrumentationTestCase test, View v, int gravity, int toY) {
478 int[] xy = new int[2];
479
480 getStartLocation(v, gravity, xy);
481
482 final int fromX = xy[0];
483 final int fromY = xy[1];
484
485 int deltaY = fromY - toY;
486
487 drag(test, fromX, fromX, fromY, toY, deltaY);
488
489 return deltaY;
490 }
491
492 /**
493 * Simulate touching a specific location and dragging to a new location.
494 *
495 * @param test The test cast that is being run
496 * @param fromX X coordinate of the initial touch, in screen coordinates
497 * @param toX Xcoordinate of the drag destination, in screen coordinates
498 * @param fromY X coordinate of the initial touch, in screen coordinates
499 * @param toY Y coordinate of the drag destination, in screen coordinates
500 * @param stepCount How many move steps to include in the drag
501 */
502 public static void drag(ActivityInstrumentationTestCase test, float fromX, float toX, float fromY, float toY,
503 int stepCount) {
504 Instrumentation inst = test.getInstrumentation();
505
506 long downTime = SystemClock.uptimeMillis();
507 long eventTime = SystemClock.uptimeMillis();
508
509 float y = fromY;
510 float x = fromX;
511
512 float yStep = (toY - fromY) / stepCount;
513 float xStep = (toX - fromX) / stepCount;
514
515 MotionEvent event = MotionEvent.obtain(downTime, eventTime,
516 MotionEvent.ACTION_DOWN, fromX, y, 0);
517 inst.sendPointerSync(event);
518 inst.waitForIdleSync();
519
520 for (int i = 0; i < stepCount; ++i) {
521 y += yStep;
522 x += xStep;
523 eventTime = SystemClock.uptimeMillis();
524 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
525 inst.sendPointerSync(event);
526 inst.waitForIdleSync();
527 }
528
529 eventTime = SystemClock.uptimeMillis();
530 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, fromX, y, 0);
531 inst.sendPointerSync(event);
532 inst.waitForIdleSync();
533 }
534
535}