1 /* 2 * Copyright (C) 2014 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 17 package androidx.test.uiautomator; 18 19 import android.graphics.Point; 20 import android.graphics.Rect; 21 import android.view.ViewConfiguration; 22 23 /** Factory methods for constructing {@link PointerGesture}s. */ 24 class Gestures { 25 26 // Duration of a long press (with multiplier to ensure detection). 27 private static final long LONG_PRESS_DURATION_MS = 28 (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); 29 30 // Constants used by pinch gestures 31 private static final int INNER = 0; 32 private static final int OUTER = 1; 33 34 private final int mDisplayId; 35 private final int mWindowId; 36 37 /** 38 * Construct a {@link Gestures} factory for building gestures that target the given display and 39 * window IDs. 40 * 41 * @param displayId The ID of the display the gesture is on. 42 * @param windowId The ID of the window the gesture is on. 43 */ Gestures(int displayId, int windowId)44 Gestures(int displayId, int windowId) { 45 mDisplayId = displayId; 46 mWindowId = windowId; 47 } 48 49 /** 50 * Returns a {@link PointerGesture} representing a click at the given {@code point}. 51 * 52 * @param point The point to click. 53 * @return The {@link PointerGesture} representing this click. 54 */ click(Point point)55 public PointerGesture click(Point point) { 56 // A basic click is a touch down and touch up over the same point with no delay. 57 return click(point, 0); 58 } 59 60 /** 61 * Returns a {@link PointerGesture} representing a click at the given {@code point} that lasts 62 * for {@code duration} milliseconds. 63 * 64 * @param point The point to click. 65 * @param duration The duration of the click in milliseconds. 66 * @return The {@link PointerGesture} representing this click. 67 */ click(Point point, long duration)68 public PointerGesture click(Point point, long duration) { 69 // A click is a touch down and touch up over the same point with an optional delay inbetween 70 return new PointerGesture(point, mDisplayId, mWindowId).pause(duration); 71 } 72 73 /** 74 * Returns a {@link PointerGesture} representing a long click at the given {@code point}. 75 * 76 * @param point The point to click. 77 * @return The {@link PointerGesture} representing this long click. 78 */ longClick(Point point)79 public PointerGesture longClick(Point point) { 80 // A long click is a click with a duration that exceeds a certain threshold. 81 return click(point, LONG_PRESS_DURATION_MS); 82 } 83 84 /** 85 * Returns a {@link PointerGesture} representing a swipe. 86 * 87 * @param start The touch down point for the swipe. 88 * @param end The touch up point for the swipe. 89 * @param speed The speed at which to move in pixels per second. 90 * @return The {@link PointerGesture} representing this swipe. 91 */ swipe(Point start, Point end, int speed)92 public PointerGesture swipe(Point start, Point end, int speed) { 93 // A swipe is a click that moves before releasing the pointer. 94 return new PointerGesture(start, mDisplayId, mWindowId).move(end, speed); 95 } 96 97 /** 98 * Returns a {@link PointerGesture} representing a horizontal or vertical swipe over an area. 99 * 100 * @param area The area to swipe over. 101 * @param direction The direction in which to swipe. 102 * @param percent The size of the swipe as a percentage of the total area. 103 * @param speed The speed at which to move in pixels per second. 104 * @return The {@link PointerGesture} representing this swipe. 105 */ swipeRect(Rect area, Direction direction, float percent, int speed)106 public PointerGesture swipeRect(Rect area, Direction direction, float percent, int speed) { 107 Point start, end; 108 // TODO: Reverse horizontal direction if locale is RTL 109 switch (direction) { 110 case LEFT: 111 start = new Point(area.right, area.centerY()); 112 end = new Point(area.right - (int)(area.width() * percent), area.centerY()); 113 break; 114 case RIGHT: 115 start = new Point(area.left, area.centerY()); 116 end = new Point(area.left + (int)(area.width() * percent), area.centerY()); 117 break; 118 case UP: 119 start = new Point(area.centerX(), area.bottom); 120 end = new Point(area.centerX(), area.bottom - (int)(area.height() * percent)); 121 break; 122 case DOWN: 123 start = new Point(area.centerX(), area.top); 124 end = new Point(area.centerX(), area.top + (int)(area.height() * percent)); 125 break; 126 default: 127 throw new RuntimeException(); 128 } 129 130 return swipe(start, end, speed); 131 } 132 133 /** 134 * Returns a {@link PointerGesture} representing a click and drag. 135 * 136 * @param start The touch down point for the swipe. 137 * @param end The touch up point for the swipe. 138 * @param speed The speed at which to move in pixels per second. 139 * @return The {@link PointerGesture} representing this swipe. 140 */ drag(Point start, Point end, int speed)141 public PointerGesture drag(Point start, Point end, int speed) { 142 // A drag is a swipe that starts with a long click. 143 return longClick(start).move(end, speed); 144 } 145 146 /** 147 * Returns an array of {@link PointerGesture}s representing a pinch close. 148 * 149 * @param area The area to pinch over. 150 * @param percent The size of the pinch as a percentage of the total area. 151 * @param speed The speed at which to move in pixels per second. 152 * @return An array containing the two PointerGestures representing this pinch. 153 */ pinchClose(Rect area, float percent, int speed)154 public PointerGesture[] pinchClose(Rect area, float percent, int speed) { 155 Point[] bottomLeft = new Point[2]; 156 Point[] topRight = new Point[2]; 157 calcPinchCoordinates(area, percent, bottomLeft, topRight); 158 159 // A pinch close is a multi-point gesture composed of two swipes moving from the outer 160 // coordinates to the inner ones. 161 return new PointerGesture[] { 162 swipe(bottomLeft[OUTER], bottomLeft[INNER], speed).pause(250), 163 swipe(topRight[OUTER], topRight[INNER], speed).pause(250) 164 }; 165 } 166 167 /** 168 * Returns an array of {@link PointerGesture}s representing a pinch close. 169 * 170 * @param area The area to pinch over. 171 * @param percent The size of the pinch as a percentage of the total area. 172 * @param speed The speed at which to move in pixels per second. 173 * @return An array containing the two PointerGestures representing this pinch. 174 */ pinchOpen(Rect area, float percent, int speed)175 public PointerGesture[] pinchOpen(Rect area, float percent, int speed) { 176 Point[] bottomLeft = new Point[2]; 177 Point[] topRight = new Point[2]; 178 calcPinchCoordinates(area, percent, bottomLeft, topRight); 179 180 // A pinch open is a multi-point gesture composed of two swipes moving from the inner 181 // coordinates to the outer ones. 182 return new PointerGesture[] { 183 swipe(bottomLeft[INNER], bottomLeft[OUTER], speed), 184 swipe(topRight[INNER], topRight[OUTER], speed) 185 }; 186 } 187 188 /** Calculates the inner and outer coordinates used in a pinch gesture. */ calcPinchCoordinates(Rect area, float percent, Point[] bottomLeft, Point[] topRight)189 private static void calcPinchCoordinates(Rect area, float percent, 190 Point[] bottomLeft, Point[] topRight) { 191 192 int offsetX = (int) (area.width() / 2 * percent); 193 int offsetY = (int) (area.height() / 2 * percent); 194 195 // Outer set of pinch coordinates 196 bottomLeft[OUTER] = new Point(area.left, area.bottom); 197 topRight[OUTER] = new Point(area.right, area.top); 198 199 // Inner set of pinch coordinates 200 bottomLeft[INNER] = new Point(bottomLeft[OUTER]); 201 bottomLeft[INNER].offset(offsetX, -offsetY); 202 topRight[INNER] = new Point(topRight[OUTER]); 203 topRight[INNER].offset(-offsetX, offsetY); 204 } 205 } 206