TouchCommon.java revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser.test.util;
6
7import android.os.SystemClock;
8import android.view.MotionEvent;
9import android.view.View;
10import android.view.ViewConfiguration;
11import android.test.ActivityInstrumentationTestCase2;
12
13/**
14 * Touch-related functionality reused across test cases.
15 */
16public class TouchCommon {
17    private ActivityInstrumentationTestCase2 mActivityTestCase;
18
19    // TODO(leandrogracia): This method should receive and use an activity
20    // instead of the ActivityInstrumentationTestCase2. However this is causing
21    // problems downstream. Any fix for this should be landed downstream first.
22    public TouchCommon(ActivityInstrumentationTestCase2 activityTestCase) {
23        mActivityTestCase = activityTestCase;
24    }
25
26    /**
27     * Starts (synchronously) a drag motion. Normally followed by dragTo() and dragEnd().
28     *
29     * @param x
30     * @param y
31     * @param downTime (in ms)
32     * @see TouchUtils
33     */
34    public void dragStart(float x, float y, long downTime) {
35        MotionEvent event = MotionEvent.obtain(downTime, downTime,
36                MotionEvent.ACTION_DOWN, x, y, 0);
37        dispatchTouchEvent(event);
38    }
39
40    /**
41     * Drags / moves (synchronously) to the specified coordinates. Normally preceeded by
42     * dragStart() and followed by dragEnd()
43     *
44     * @param fromX
45     * @param toX
46     * @param fromY
47     * @param toY
48     * @param stepCount
49     * @param downTime (in ms)
50     * @see TouchUtils
51     */
52    public void dragTo(float fromX, float toX, float fromY,
53            float toY, int stepCount, long downTime) {
54        float x = fromX;
55        float y = fromY;
56        float yStep = (toY - fromY) / stepCount;
57        float xStep = (toX - fromX) / stepCount;
58        for (int i = 0; i < stepCount; ++i) {
59            y += yStep;
60            x += xStep;
61            long eventTime = SystemClock.uptimeMillis();
62            MotionEvent event = MotionEvent.obtain(downTime, eventTime,
63                    MotionEvent.ACTION_MOVE, x, y, 0);
64            dispatchTouchEvent(event);
65        }
66    }
67
68    /**
69     * Finishes (synchronously) a drag / move at the specified coordinate.
70     * Normally preceeded by dragStart() and dragTo().
71     *
72     * @param x
73     * @param y
74     * @param downTime (in ms)
75     * @see TouchUtils
76     */
77    public void dragEnd(float x, float y, long downTime) {
78        long eventTime = SystemClock.uptimeMillis();
79        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
80                MotionEvent.ACTION_UP, x, y, 0);
81        dispatchTouchEvent(event);
82    }
83
84    /**
85     * Sends (synchronously) a single click to an absolute screen coordinates.
86     *
87     * @param x screen absolute
88     * @param y screen absolute
89     * @see TouchUtils
90     */
91    public void singleClick(float x, float y) {
92
93        long downTime = SystemClock.uptimeMillis();
94        long eventTime = SystemClock.uptimeMillis();
95
96        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
97                                               MotionEvent.ACTION_DOWN, x, y, 0);
98        dispatchTouchEvent(event);
99
100        eventTime = SystemClock.uptimeMillis();
101        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP,
102                                   x, y, 0);
103        dispatchTouchEvent(event);
104    }
105
106    /**
107     * Sends (synchronously) a single click to the View at the specified coordinates.
108     *
109     * @param v The view to be clicked.
110     * @param x Relative x location to v
111     * @param y Relative y location to v
112     */
113    public void singleClickView(View v, int x, int y) {
114        int location[] = getAbsoluteLocationFromRelative(v, x, y);
115        int absoluteX = location[0];
116        int absoluteY = location[1];
117        singleClick(absoluteX, absoluteY);
118    }
119
120    /**
121     * Sends (synchronously) a single click to the center of the View.
122     */
123    public void singleClickView(View v) {
124        singleClickView(v, v.getWidth() / 2, v.getHeight() / 2);
125    }
126
127    /**
128     * Sends (synchronously) a single click on the specified relative coordinates inside
129     * a given view.
130     *
131     * @param view The view to be clicked.
132     * @param x screen absolute
133     * @param y screen absolute
134     * @see TouchUtils
135     */
136    public void singleClickViewRelative(View view, int x, int y) {
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        dispatchTouchEvent(view, event);
143
144        eventTime = SystemClock.uptimeMillis();
145        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP,
146                                   x, y, 0);
147        dispatchTouchEvent(view, event);
148    }
149
150    /**
151     * Sends (synchronously) a long press to an absolute screen coordinates.
152     *
153     * @param x screen absolute
154     * @param y screen absolute
155     * @see TouchUtils
156     */
157    public void longPress(float x, float y) {
158
159        long downTime = SystemClock.uptimeMillis();
160        long eventTime = SystemClock.uptimeMillis();
161
162        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
163                                               MotionEvent.ACTION_DOWN, x, y, 0);
164        dispatchTouchEvent(event);
165
166        int longPressTimeout = ViewConfiguration.get(
167                mActivityTestCase.getActivity()).getLongPressTimeout();
168
169        // Long press is flaky with just longPressTimeout. Doubling the time to be safe.
170        SystemClock.sleep(longPressTimeout * 2);
171
172        eventTime = SystemClock.uptimeMillis();
173        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP,
174                                   x, y, 0);
175        dispatchTouchEvent(event);
176    }
177
178    /**
179     * Sends (synchronously) a long press to the View at the specified coordinates.
180     *
181     * @param v The view to be clicked.
182     * @param x Relative x location to v
183     * @param y Relative y location to v
184     */
185    public void longPressView(View v, int x, int y) {
186        int location[] = getAbsoluteLocationFromRelative(v, x, y);
187        int absoluteX = location[0];
188        int absoluteY = location[1];
189        longPress(absoluteX, absoluteY);
190    }
191
192    /**
193     * Send a MotionEvent to the root view of the activity.
194     * @param event
195     */
196    private void dispatchTouchEvent(final MotionEvent event) {
197        View view =
198                mActivityTestCase.getActivity().findViewById(android.R.id.content).getRootView();
199        dispatchTouchEvent(view, event);
200    }
201
202    /**
203     * Send a MotionEvent to the specified view instead of the root view.
204     * For example AutofillPopup window that is above the root view.
205     * @param view The view that should receive the event.
206     * @param event The view to be dispatched.
207     */
208    private void dispatchTouchEvent(final View view, final MotionEvent event) {
209        try {
210            mActivityTestCase.runTestOnUiThread(new Runnable() {
211                @Override
212                public void run() {
213                    view.dispatchTouchEvent(event);
214                }
215            });
216        } catch(Throwable e) {
217            throw new RuntimeException("Dispatching touch event failed", e);
218        }
219    }
220
221    /**
222     * Returns the absolute location in screen coordinates from location relative
223     * to view.
224     * @param v The view the coordinates are relative to.
225     * @param x Relative x location.
226     * @param y Relative y location.
227     * @return absolute x and y location in an array.
228     */
229    private static int[] getAbsoluteLocationFromRelative(View v, int x, int y) {
230        int location[] = new int[2];
231        v.getLocationOnScreen(location);
232        location[0] += x;
233        location[1] += y;
234        return location;
235    }
236}
237