1 | // Copyright (c) 2011 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 | |
5 | package org.chromium.content.browser.test.util; |
6 | |
7 | import android.app.Activity; |
8 | import android.app.Instrumentation; |
9 | import android.os.SystemClock; |
10 | import android.test.InstrumentationTestCase; |
11 | import android.view.MotionEvent; |
12 | import android.view.View; |
13 | import android.view.ViewConfiguration; |
14 | |
15 | /** |
16 | * Collection of utilities for generating touch events. |
17 | * Based on android.test.TouchUtils, but slightly more flexible (allows to |
18 | * specify coordinates for longClick, splits drag operation in three stages, etc). |
19 | */ |
20 | public class TestTouchUtils extends android.test.TouchUtils { |
21 | /** |
22 | * Returns the absolute location in screen coordinates from location relative |
23 | * to view. |
24 | * @param v The view the coordinates are relative to. |
25 | * @param x Relative x location. |
26 | * @param y Relative y location. |
27 | * @return the absolute x and y location in an array. |
28 | */ |
29 | public static int[] getAbsoluteLocationFromRelative(View v, int x, int y) { |
30 | int location[] = new int[2]; |
31 | v.getLocationOnScreen(location); |
32 | location[0] += x; |
33 | location[1] += y; |
34 | return location; |
35 | } |
36 | |
37 | private static void sendAction(Instrumentation instrumentation, int action, long downTime, |
38 | float x, float y) { |
39 | long eventTime = SystemClock.uptimeMillis(); |
40 | MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0); |
41 | instrumentation.sendPointerSync(event); |
42 | instrumentation.waitForIdleSync(); |
43 | } |
44 | |
45 | /** |
46 | * Sends (synchronously) a single click to an absolute screen coordinates. |
47 | * |
48 | * @param instrumentation Instrumentation object used by the test. |
49 | * @param x Screen absolute x location. |
50 | * @param y Screen absolute y location. |
51 | */ |
52 | public static void singleClick(Instrumentation instrumentation, float x, float y) { |
53 | long downTime = SystemClock.uptimeMillis(); |
54 | sendAction(instrumentation, MotionEvent.ACTION_DOWN, downTime, x, y); |
55 | sendAction(instrumentation, MotionEvent.ACTION_UP, downTime, x, y); |
56 | } |
57 | |
58 | /** |
59 | * Sends (synchronously) a single click to the View at the specified coordinates. |
60 | * |
61 | * @param instrumentation Instrumentation object used by the test. |
62 | * @param v The view the coordinates are relative to. |
63 | * @param x Relative x location to the view. |
64 | * @param y Relative y location to the view. |
65 | */ |
66 | public static void singleClickView(Instrumentation instrumentation, View v, int x, int y) { |
67 | int location[] = getAbsoluteLocationFromRelative(v, x, y); |
68 | int absoluteX = location[0]; |
69 | int absoluteY = location[1]; |
70 | singleClick(instrumentation, absoluteX, absoluteY); |
71 | } |
72 | |
73 | /** |
74 | * Sends (synchronously) a single click to the center of the View. |
75 | * |
76 | * @param instrumentation Instrumentation object used by the test. |
77 | * @param v The view the coordinates are relative to. |
78 | */ |
79 | public static void singleClickView(Instrumentation instrumentation, View v) { |
80 | int x = v.getWidth() / 2; |
81 | int y = v.getHeight() / 2; |
82 | singleClickView(instrumentation, v, x, y); |
83 | } |
84 | |
85 | /** |
86 | * Sleeps for at least the length of the double tap timeout. |
87 | * |
88 | * @param instrumentation Instrumentation object used by the test. |
89 | */ |
90 | public static void sleepForDoubleTapTimeout(Instrumentation instrumentation) { |
91 | SystemClock.sleep((long)(ViewConfiguration.getDoubleTapTimeout() * 1.5)); |
92 | } |
93 | |
94 | /** |
95 | * Sends (synchronously) a long click to the View at the specified coordinates. |
96 | * |
97 | * @param instrumentation Instrumentation object used by the test. |
98 | * @param v The view the coordinates are relative to. |
99 | * @param x Relative x location to the view. |
100 | * @param y Relative y location to the view. |
101 | */ |
102 | public static void longClickView(Instrumentation instrumentation, View v, int x, int y) { |
103 | int location[] = getAbsoluteLocationFromRelative(v, x, y); |
104 | int absoluteX = location[0]; |
105 | int absoluteY = location[1]; |
106 | |
107 | long downTime = SystemClock.uptimeMillis(); |
108 | sendAction(instrumentation, MotionEvent.ACTION_DOWN, downTime, absoluteX, absoluteY); |
109 | SystemClock.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5)); |
110 | sendAction(instrumentation, MotionEvent.ACTION_UP, downTime, absoluteX, absoluteY); |
111 | } |
112 | |
113 | /** |
114 | * Starts (synchronously) a drag motion. Normally followed by dragTo() and dragEnd(). |
115 | * |
116 | * @param instrumentation Instrumentation object used by the test. |
117 | * @param x The x location. |
118 | * @param y The y location. |
119 | * @return The downTime of the triggered event. |
120 | */ |
121 | public static long dragStart(Instrumentation instrumentation, float x, float y) { |
122 | long downTime = SystemClock.uptimeMillis(); |
123 | sendAction(instrumentation, MotionEvent.ACTION_DOWN, downTime, x, y); |
124 | return downTime; |
125 | } |
126 | |
127 | /** |
128 | * Drags / moves (synchronously) to the specified coordinates. Normally preceeded by |
129 | * dragStart() and followed by dragEnd() |
130 | * |
131 | * @param instrumentation Instrumentation object used by the test. |
132 | * @param fromX The relative x-coordinate of the start point of the drag. |
133 | * @param toX The relative x-coordinate of the end point of the drag. |
134 | * @param fromY The relative y-coordinate of the start point of the drag. |
135 | * @param toY The relative y-coordinate of the end point of the drag. |
136 | * @param stepCount The total number of motion events that should be generated during the drag. |
137 | * @param downTime The initial time of the drag, in ms. |
138 | */ |
139 | public static void dragTo(Instrumentation instrumentation, float fromX, float toX, float fromY, |
140 | float toY, int stepCount, long downTime) { |
141 | float x = fromX; |
142 | float y = fromY; |
143 | float yStep = (toY - fromY) / stepCount; |
144 | float xStep = (toX - fromX) / stepCount; |
145 | for (int i = 0; i < stepCount; ++i) { |
146 | y += yStep; |
147 | x += xStep; |
148 | sendAction(instrumentation, MotionEvent.ACTION_MOVE, downTime, x, y); |
149 | } |
150 | } |
151 | |
152 | /** |
153 | * Finishes (synchronously) a drag / move at the specified coordinate. |
154 | * Normally preceeded by dragStart() and dragTo(). |
155 | * |
156 | * @param instrumentation Instrumentation object used by the test. |
157 | * @param x The x location. |
158 | * @param y The y location. |
159 | * @param downTime The initial time of the drag, in ms. |
160 | */ |
161 | public static void dragEnd(Instrumentation instrumentation, float x, float y, long downTime) { |
162 | sendAction(instrumentation, MotionEvent.ACTION_UP, downTime, x, y); |
163 | } |
164 | |
165 | /** |
166 | * Performs a drag between the given coordinates, specified relative to the given view. |
167 | * This method makes calls to dragStart, dragTo and dragEnd. |
168 | * |
169 | * @param instrumentation Instrumentation object used by the test. |
170 | * @param view The view the coordinates are relative to. |
171 | * @param fromX The relative x-coordinate of the start point of the drag. |
172 | * @param toX The relative x-coordinate of the end point of the drag. |
173 | * @param fromY The relative y-coordinate of the start point of the drag. |
174 | * @param toY The relative y-coordinate of the end point of the drag. |
175 | * @param stepCount The total number of motion events that should be generated during the drag. |
176 | */ |
177 | public static void dragCompleteView(Instrumentation instrumentation, View view, |
178 | int fromX, int toX, int fromY, int toY, int stepCount) { |
179 | int fromLocation[] = getAbsoluteLocationFromRelative(view, fromX, fromY); |
180 | int toLocation[] = getAbsoluteLocationFromRelative(view, toX, toY); |
181 | long downTime = dragStart(instrumentation, fromLocation[0], fromLocation[1]); |
182 | dragTo(instrumentation, fromLocation[0], toLocation[0], fromLocation[1], toLocation[1], |
183 | stepCount, downTime); |
184 | dragEnd(instrumentation, toLocation[0], toLocation[1], downTime); |
185 | } |
186 | |
187 | /** |
188 | * Calls performClick on a View on the main UI thread. |
189 | * |
190 | * @param instrumentation Instrumentation object used by the test. |
191 | * @param v The view to call performClick on. |
192 | */ |
193 | public static void performClickOnMainSync(Instrumentation instrumentation, final View v) { |
194 | instrumentation.runOnMainSync(new Runnable() { |
195 | @Override |
196 | public void run() { |
197 | v.performClick(); |
198 | } |
199 | }); |
200 | } |
201 | |
202 | /** |
203 | * Clicks on specified view in the given {@link Activity}. |
204 | * |
205 | * @param test The test case using this utility. |
206 | * @param activity Activity containing the view. |
207 | * @param id The view to be clicked. |
208 | * @return {@code true} if a view with the given id exists. |
209 | */ |
210 | public static boolean clickById(InstrumentationTestCase test, Activity activity, int id) { |
211 | View v = activity.findViewById(id); |
212 | if (v == null) return false; |
213 | clickView(test, v); |
214 | return true; |
215 | } |
216 | } |