1/*
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.Activity;
20import android.app.Instrumentation;
21import android.graphics.Point;
22import android.os.SystemClock;
23import android.view.Display;
24import android.view.Gravity;
25import android.view.MotionEvent;
26import android.view.View;
27import android.view.ViewConfiguration;
28import android.view.ViewGroup;
29
30/**
31 * Reusable methods for generating touch events. These methods can be used with
32 * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with
33 * the application through a touch screen.
34 */
35public class TouchUtils {
36
37    /**
38     * Simulate touching in the center of the screen and dragging one quarter of the way down
39     * @param test The test case that is being run
40     *
41     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
42     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
43     * configuring the Activity under test
44     */
45    @Deprecated
46    public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
47        dragQuarterScreenDown(test, test.getActivity());
48    }
49
50    /**
51     * Simulate touching in the center of the screen and dragging one quarter of the way down
52     * @param test The test case that is being run
53     * @param activity The activity that is in the foreground of the test case
54     */
55    public static void dragQuarterScreenDown(InstrumentationTestCase test, Activity activity) {
56        Display display = activity.getWindowManager().getDefaultDisplay();
57        final Point size = new Point();
58        display.getSize(size);
59
60        final float x = size.x / 2.0f;
61        final float fromY = size.y * 0.5f;
62        final float toY = size.y * 0.75f;
63
64        drag(test, x, x, fromY, toY, 4);
65    }
66
67    /**
68     * Simulate touching in the center of the screen and dragging one quarter of the way up
69     * @param test The test case that is being run
70     *
71     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
72     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
73     * configuring the Activity under test
74     */
75    @Deprecated
76    public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
77        dragQuarterScreenUp(test, test.getActivity());
78    }
79
80    /**
81     * Simulate touching in the center of the screen and dragging one quarter of the way up
82     * @param test The test case that is being run
83     * @param activity The activity that is in the foreground of the test case
84     */
85    public static void dragQuarterScreenUp(InstrumentationTestCase test, Activity activity) {
86        Display display = activity.getWindowManager().getDefaultDisplay();
87        final Point size = new Point();
88        display.getSize(size);
89
90        final float x = size.x / 2.0f;
91        final float fromY = size.y * 0.5f;
92        final float toY = size.y * 0.25f;
93
94        drag(test, x, x, fromY, toY, 4);
95    }
96
97    /**
98     * Scroll a ViewGroup to the bottom by repeatedly calling
99     * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
100     *
101     * @param test The test case that is being run
102     * @param v The ViewGroup that should be dragged
103     *
104     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
105     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
106     * configuring the Activity under test
107     */
108    @Deprecated
109    public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
110        scrollToBottom(test, test.getActivity(), v);
111    }
112
113    /**
114     * Scroll a ViewGroup to the bottom by repeatedly calling
115     * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
116     *
117     * @param test The test case that is being run
118     * @param activity The activity that is in the foreground of the test case
119     * @param v The ViewGroup that should be dragged
120     */
121    public static void scrollToBottom(InstrumentationTestCase test, Activity activity,
122            ViewGroup v) {
123        View firstChild;
124        int firstId = Integer.MIN_VALUE;
125        int firstTop = Integer.MIN_VALUE;
126        int prevId;
127        int prevTop;
128        do {
129            prevId = firstId;
130            prevTop = firstTop;
131            TouchUtils.dragQuarterScreenUp(test, activity);
132            firstChild = v.getChildAt(0);
133            firstId = firstChild.getId();
134            firstTop = firstChild.getTop();
135        } while ((prevId != firstId) || (prevTop != firstTop));
136    }
137
138    /**
139     * Scroll a ViewGroup to the top by repeatedly calling
140     * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
141     *
142     * @param test The test case that is being run
143     * @param v The ViewGroup that should be dragged
144     *
145     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
146     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
147     * configuring the Activity under test
148     */
149    @Deprecated
150    public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
151        scrollToTop(test, test.getActivity(), v);
152    }
153
154    /**
155     * Scroll a ViewGroup to the top by repeatedly calling
156     * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
157     *
158     * @param test The test case that is being run
159     * @param activity The activity that is in the foreground of the test case
160     * @param v The ViewGroup that should be dragged
161     */
162    public static void scrollToTop(InstrumentationTestCase test, Activity activity, ViewGroup v) {
163        View firstChild;
164        int firstId = Integer.MIN_VALUE;
165        int firstTop = Integer.MIN_VALUE;
166        int prevId;
167        int prevTop;
168        do {
169            prevId = firstId;
170            prevTop = firstTop;
171            TouchUtils.dragQuarterScreenDown(test, activity);
172            firstChild = v.getChildAt(0);
173            firstId = firstChild.getId();
174            firstTop = firstChild.getTop();
175        } while ((prevId != firstId) || (prevTop != firstTop));
176    }
177
178    /**
179     * Simulate touching the center of a view and dragging to the bottom of the screen.
180     *
181     * @param test The test case that is being run
182     * @param v The view that should be dragged
183     *
184     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
185     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
186     * configuring the Activity under test
187     */
188    @Deprecated
189    public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
190        dragViewToBottom(test, test.getActivity(), v, 4);
191    }
192
193    /**
194     * Simulate touching the center of a view and dragging to the bottom of the screen.
195     *
196     * @param test The test case that is being run
197     * @param activity The activity that is in the foreground of the test case
198     * @param v The view that should be dragged
199     */
200    public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) {
201        dragViewToBottom(test, activity, v, 4);
202    }
203
204    /**
205     * Simulate touching the center of a view and dragging to the bottom of the screen.
206     *
207     * @param test The test case that is being run
208     * @param v The view that should be dragged
209     * @param stepCount How many move steps to include in the drag
210     *
211     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
212     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
213     * configuring the Activity under test
214     */
215    @Deprecated
216    public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v,
217            int stepCount) {
218        dragViewToBottom(test, test.getActivity(), v, stepCount);
219    }
220
221    /**
222     * Simulate touching the center of a view and dragging to the bottom of the screen.
223     *
224     * @param test The test case that is being run
225     * @param activity The activity that is in the foreground of the test case
226     * @param v The view that should be dragged
227     * @param stepCount How many move steps to include in the drag
228     */
229    public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
230            int stepCount) {
231        int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
232
233        int[] xy = new int[2];
234        v.getLocationOnScreen(xy);
235
236        final int viewWidth = v.getWidth();
237        final int viewHeight = v.getHeight();
238
239        final float x = xy[0] + (viewWidth / 2.0f);
240        float fromY = xy[1] + (viewHeight / 2.0f);
241        float toY = screenHeight - 1;
242
243        drag(test, x, x, fromY, toY, stepCount);
244    }
245
246    /**
247     * Simulate touching the center of a view and releasing quickly (before the tap timeout).
248     *
249     * @param test The test case that is being run
250     * @param v The view that should be clicked
251     */
252    public static void tapView(InstrumentationTestCase test, View v) {
253        int[] xy = new int[2];
254        v.getLocationOnScreen(xy);
255
256        final int viewWidth = v.getWidth();
257        final int viewHeight = v.getHeight();
258
259        final float x = xy[0] + (viewWidth / 2.0f);
260        float y = xy[1] + (viewHeight / 2.0f);
261
262        Instrumentation inst = test.getInstrumentation();
263
264        long downTime = SystemClock.uptimeMillis();
265        long eventTime = SystemClock.uptimeMillis();
266
267        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
268                MotionEvent.ACTION_DOWN, x, y, 0);
269        inst.sendPointerSync(event);
270        inst.waitForIdleSync();
271
272        eventTime = SystemClock.uptimeMillis();
273        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
274        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
275                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
276        inst.sendPointerSync(event);
277        inst.waitForIdleSync();
278
279        eventTime = SystemClock.uptimeMillis();
280        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
281        inst.sendPointerSync(event);
282        inst.waitForIdleSync();
283    }
284
285    /**
286     * Simulate touching the center of a view and cancelling (so no onClick should
287     * fire, etc).
288     *
289     * @param test The test case that is being run
290     * @param v The view that should be clicked
291     */
292    public static void touchAndCancelView(InstrumentationTestCase test, View v) {
293        int[] xy = new int[2];
294        v.getLocationOnScreen(xy);
295
296        final int viewWidth = v.getWidth();
297        final int viewHeight = v.getHeight();
298
299        final float x = xy[0] + (viewWidth / 2.0f);
300        float y = xy[1] + (viewHeight / 2.0f);
301
302        Instrumentation inst = test.getInstrumentation();
303
304        long downTime = SystemClock.uptimeMillis();
305        long eventTime = SystemClock.uptimeMillis();
306
307        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
308                MotionEvent.ACTION_DOWN, x, y, 0);
309        inst.sendPointerSync(event);
310        inst.waitForIdleSync();
311
312        eventTime = SystemClock.uptimeMillis();
313        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
314        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL,
315                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
316        inst.sendPointerSync(event);
317        inst.waitForIdleSync();
318
319    }
320
321    /**
322     * Simulate touching the center of a view and releasing.
323     *
324     * @param test The test case that is being run
325     * @param v The view that should be clicked
326     */
327    public static void clickView(InstrumentationTestCase test, View v) {
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 y = xy[1] + (viewHeight / 2.0f);
336
337        Instrumentation inst = test.getInstrumentation();
338
339        long downTime = SystemClock.uptimeMillis();
340        long eventTime = SystemClock.uptimeMillis();
341
342        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
343                MotionEvent.ACTION_DOWN, x, y, 0);
344        inst.sendPointerSync(event);
345        inst.waitForIdleSync();
346
347
348        eventTime = SystemClock.uptimeMillis();
349        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
350        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
351                x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
352        inst.sendPointerSync(event);
353        inst.waitForIdleSync();
354
355        eventTime = SystemClock.uptimeMillis();
356        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
357        inst.sendPointerSync(event);
358        inst.waitForIdleSync();
359
360        try {
361            Thread.sleep(1000);
362        } catch (InterruptedException e) {
363            e.printStackTrace();
364        }
365    }
366
367    /**
368     * Simulate touching the center of a view, holding until it is a long press, and then releasing.
369     *
370     * @param test The test case that is being run
371     * @param v The view that should be clicked
372     *
373     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
374     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
375     * configuring the Activity under test
376     */
377    @Deprecated
378    public static void longClickView(ActivityInstrumentationTestCase test, View v) {
379        longClickView((InstrumentationTestCase) test, v);
380    }
381
382    /**
383     * Simulate touching the center of a view, holding until it is a long press, and then releasing.
384     *
385     * @param test The test case that is being run
386     * @param v The view that should be clicked
387     */
388    public static void longClickView(InstrumentationTestCase test, View v) {
389        int[] xy = new int[2];
390        v.getLocationOnScreen(xy);
391
392        final int viewWidth = v.getWidth();
393        final int viewHeight = v.getHeight();
394
395        final float x = xy[0] + (viewWidth / 2.0f);
396        float y = xy[1] + (viewHeight / 2.0f);
397
398        Instrumentation inst = test.getInstrumentation();
399
400        long downTime = SystemClock.uptimeMillis();
401        long eventTime = SystemClock.uptimeMillis();
402
403        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
404                MotionEvent.ACTION_DOWN, x, y, 0);
405        inst.sendPointerSync(event);
406        inst.waitForIdleSync();
407
408        eventTime = SystemClock.uptimeMillis();
409        final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
410        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
411                x + touchSlop / 2, y + touchSlop / 2, 0);
412        inst.sendPointerSync(event);
413        inst.waitForIdleSync();
414
415        try {
416            Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
417        } catch (InterruptedException e) {
418            e.printStackTrace();
419        }
420
421        eventTime = SystemClock.uptimeMillis();
422        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
423        inst.sendPointerSync(event);
424        inst.waitForIdleSync();
425    }
426
427    /**
428     * Simulate touching the center of a view and dragging to the top of the screen.
429     *
430     * @param test The test case that is being run
431     * @param v The view that should be dragged
432     *
433     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
434     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
435     * configuring the Activity under test
436     */
437    @Deprecated
438    public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
439        dragViewToTop((InstrumentationTestCase) test, v, 4);
440    }
441
442    /**
443     * Simulate touching the center of a view and dragging to the top of the screen.
444     *
445     * @param test The test case that is being run
446     * @param v The view that should be dragged
447     * @param stepCount How many move steps to include in the drag
448     *
449     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
450     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
451     * configuring the Activity under test
452     */
453    @Deprecated
454    public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
455        dragViewToTop((InstrumentationTestCase) test, v, stepCount);
456    }
457
458    /**
459     * Simulate touching the center of a view and dragging to the top of the screen.
460     *
461     * @param test The test case that is being run
462     * @param v The view that should be dragged
463     */
464    public static void dragViewToTop(InstrumentationTestCase test, View v) {
465        dragViewToTop(test, v, 4);
466    }
467
468    /**
469     * Simulate touching the center of a view and dragging to the top of the screen.
470     *
471     * @param test The test case that is being run
472     * @param v The view that should be dragged
473     * @param stepCount How many move steps to include in the drag
474     */
475    public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) {
476        int[] xy = new int[2];
477        v.getLocationOnScreen(xy);
478
479        final int viewWidth = v.getWidth();
480        final int viewHeight = v.getHeight();
481
482        final float x = xy[0] + (viewWidth / 2.0f);
483        float fromY = xy[1] + (viewHeight / 2.0f);
484        float toY = 0;
485
486        drag(test, x, x, fromY, toY, stepCount);
487    }
488
489    /**
490     * Get the location of a view. Use the gravity param to specify which part of the view to
491     * return.
492     *
493     * @param v View to find
494     * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
495     *        RIGHT)
496     * @param xy Result
497     */
498    private static void getStartLocation(View v, int gravity, int[] xy) {
499        v.getLocationOnScreen(xy);
500
501        final int viewWidth = v.getWidth();
502        final int viewHeight = v.getHeight();
503
504        switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
505        case Gravity.TOP:
506            break;
507        case Gravity.CENTER_VERTICAL:
508            xy[1] += viewHeight / 2;
509            break;
510        case Gravity.BOTTOM:
511            xy[1] += viewHeight - 1;
512            break;
513        default:
514            // Same as top -- do nothing
515        }
516
517        switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
518        case Gravity.LEFT:
519            break;
520        case Gravity.CENTER_HORIZONTAL:
521            xy[0] += viewWidth / 2;
522            break;
523        case Gravity.RIGHT:
524            xy[0] += viewWidth - 1;
525            break;
526        default:
527            // Same as left -- do nothing
528        }
529    }
530
531    /**
532     * Simulate touching a view and dragging it by the specified amount.
533     *
534     * @param test The test case that is being run
535     * @param v The view that should be dragged
536     * @param gravity Which part of the view to use for the initial down event. A combination of
537     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
538     * @param deltaX Amount to drag horizontally in pixels
539     * @param deltaY Amount to drag vertically in pixels
540     *
541     * @return distance in pixels covered by the drag
542     *
543     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
544     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
545     * configuring the Activity under test
546     */
547    @Deprecated
548    public static int dragViewBy(ActivityInstrumentationTestCase test, View v, int gravity,
549            int deltaX, int deltaY) {
550        return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY);
551    }
552
553    /**
554     * Simulate touching a view and dragging it by the specified amount.
555     *
556     * @param test The test case that is being run
557     * @param v The view that should be dragged
558     * @param gravity Which part of the view to use for the initial down event. A combination of
559     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
560     * @param deltaX Amount to drag horizontally in pixels
561     * @param deltaY Amount to drag vertically in pixels
562     *
563     * @return distance in pixels covered by the drag
564     *
565     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
566     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
567     * configuring the Activity under test
568     */
569    @Deprecated
570    public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
571            int deltaY) {
572        int[] xy = new int[2];
573
574        getStartLocation(v, gravity, xy);
575
576        final int fromX = xy[0];
577        final int fromY = xy[1];
578
579        int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
580
581        drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
582
583        return distance;
584    }
585
586    /**
587     * Simulate touching a view and dragging it to a specified location.
588     *
589     * @param test The test case that is being run
590     * @param v The view that should be dragged
591     * @param gravity Which part of the view to use for the initial down event. A combination of
592     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
593     * @param toX Final location of the view after dragging
594     * @param toY Final location of the view after dragging
595     *
596     * @return distance in pixels covered by the drag
597     *
598     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
599     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
600     * configuring the Activity under test
601     */
602    @Deprecated
603    public static int dragViewTo(ActivityInstrumentationTestCase test, View v, int gravity, int toX,
604            int toY) {
605        return dragViewTo((InstrumentationTestCase) test, v, gravity, toX, toY);
606    }
607
608    /**
609     * Simulate touching a view and dragging it to a specified location.
610     *
611     * @param test The test case that is being run
612     * @param v The view that should be dragged
613     * @param gravity Which part of the view to use for the initial down event. A combination of
614     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
615     * @param toX Final location of the view after dragging
616     * @param toY Final location of the view after dragging
617     *
618     * @return distance in pixels covered by the drag
619     */
620    public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX,
621            int toY) {
622        int[] xy = new int[2];
623
624        getStartLocation(v, gravity, xy);
625
626        final int fromX = xy[0];
627        final int fromY = xy[1];
628
629        int deltaX = fromX - toX;
630        int deltaY = fromY - toY;
631
632        int distance = (int)Math.sqrt(deltaX * deltaX + deltaY * deltaY);
633        drag(test, fromX, toX, fromY, toY, distance);
634
635        return distance;
636    }
637
638    /**
639     * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
640     *
641     * @param test The test case that is being run
642     * @param v The view that should be dragged
643     * @param gravity Which part of the view to use for the initial down event. A combination of
644     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
645     * @param toX Final location of the view after dragging
646     *
647     * @return distance in pixels covered by the drag
648     *
649     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
650     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
651     * configuring the Activity under test
652     */
653    @Deprecated
654    public static int dragViewToX(ActivityInstrumentationTestCase test, View v, int gravity,
655            int toX) {
656        return dragViewToX((InstrumentationTestCase) test, v, gravity, toX);
657    }
658
659    /**
660     * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
661     *
662     * @param test The test case that is being run
663     * @param v The view that should be dragged
664     * @param gravity Which part of the view to use for the initial down event. A combination of
665     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
666     * @param toX Final location of the view after dragging
667     *
668     * @return distance in pixels covered by the drag
669     */
670    public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) {
671        int[] xy = new int[2];
672
673        getStartLocation(v, gravity, xy);
674
675        final int fromX = xy[0];
676        final int fromY = xy[1];
677
678        int deltaX = fromX - toX;
679
680        drag(test, fromX, toX, fromY, fromY, deltaX);
681
682        return deltaX;
683    }
684
685    /**
686     * Simulate touching a view and dragging it to a specified location. Only moves vertically.
687     *
688     * @param test The test case that is being run
689     * @param v The view that should be dragged
690     * @param gravity Which part of the view to use for the initial down event. A combination of
691     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
692     * @param toY Final location of the view after dragging
693     *
694     * @return distance in pixels covered by the drag
695     *
696     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
697     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
698     * configuring the Activity under test
699     */
700    @Deprecated
701    public static int dragViewToY(ActivityInstrumentationTestCase test, View v, int gravity,
702            int toY) {
703        return dragViewToY((InstrumentationTestCase) test, v, gravity, toY);
704    }
705
706    /**
707     * Simulate touching a view and dragging it to a specified location. Only moves vertically.
708     *
709     * @param test The test case that is being run
710     * @param v The view that should be dragged
711     * @param gravity Which part of the view to use for the initial down event. A combination of
712     *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
713     * @param toY Final location of the view after dragging
714     *
715     * @return distance in pixels covered by the drag
716     */
717    public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) {
718        int[] xy = new int[2];
719
720        getStartLocation(v, gravity, xy);
721
722        final int fromX = xy[0];
723        final int fromY = xy[1];
724
725        int deltaY = fromY - toY;
726
727        drag(test, fromX, fromX, fromY, toY, deltaY);
728
729        return deltaY;
730    }
731
732
733    /**
734     * Simulate touching a specific location and dragging to a new location.
735     *
736     * @param test The test case that is being run
737     * @param fromX X coordinate of the initial touch, in screen coordinates
738     * @param toX Xcoordinate of the drag destination, in screen coordinates
739     * @param fromY X coordinate of the initial touch, in screen coordinates
740     * @param toY Y coordinate of the drag destination, in screen coordinates
741     * @param stepCount How many move steps to include in the drag
742     *
743     * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
744     * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
745     * configuring the Activity under test
746     */
747    @Deprecated
748    public static void drag(ActivityInstrumentationTestCase test, float fromX, float toX,
749            float fromY, float toY, int stepCount) {
750        drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount);
751    }
752
753    /**
754     * Simulate touching a specific location and dragging to a new location.
755     *
756     * @param test The test case that is being run
757     * @param fromX X coordinate of the initial touch, in screen coordinates
758     * @param toX Xcoordinate of the drag destination, in screen coordinates
759     * @param fromY X coordinate of the initial touch, in screen coordinates
760     * @param toY Y coordinate of the drag destination, in screen coordinates
761     * @param stepCount How many move steps to include in the drag
762     */
763    public static void drag(InstrumentationTestCase test, float fromX, float toX, float fromY,
764            float toY, int stepCount) {
765        Instrumentation inst = test.getInstrumentation();
766
767        long downTime = SystemClock.uptimeMillis();
768        long eventTime = SystemClock.uptimeMillis();
769
770        float y = fromY;
771        float x = fromX;
772
773        float yStep = (toY - fromY) / stepCount;
774        float xStep = (toX - fromX) / stepCount;
775
776        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
777                MotionEvent.ACTION_DOWN, x, y, 0);
778        inst.sendPointerSync(event);
779        inst.waitForIdleSync();
780
781        for (int i = 0; i < stepCount; ++i) {
782            y += yStep;
783            x += xStep;
784            eventTime = SystemClock.uptimeMillis();
785            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
786            inst.sendPointerSync(event);
787            inst.waitForIdleSync();
788        }
789
790        eventTime = SystemClock.uptimeMillis();
791        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
792        inst.sendPointerSync(event);
793        inst.waitForIdleSync();
794    }
795}
796