Merge "Convert AndroidTestLibTests to mockito from littlemock."
diff --git a/uiautomator/api/current.txt b/uiautomator/api/current.txt
index 1250b9f..a058111 100644
--- a/uiautomator/api/current.txt
+++ b/uiautomator/api/current.txt
@@ -90,13 +90,18 @@
method public boolean longClick() throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean longClickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean longClickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method public void multiPointerGesture(android.view.MotionEvent.PointerCoords...);
+ method public void pinchIn(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method public void pinchOut(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean setText(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean swipeDown(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean swipeLeft(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean swipeRight(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
method public boolean swipeUp(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method public void twoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
method public boolean waitForExists(long);
method public boolean waitUntilGone(long);
+ field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
field protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
@@ -182,18 +187,6 @@
method public abstract void sendStatus(int, android.os.Bundle);
}
- public class OnDeviceUiTestCase extends android.test.AndroidTestCase {
- ctor public OnDeviceUiTestCase();
- method public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
- method public android.os.Bundle getParams();
- method public com.android.uiautomator.core.UiDevice getUiDevice();
- method public void sleep(long);
- }
-
- public class OnDeviceUiTestRunner extends android.test.InstrumentationTestRunner {
- ctor public OnDeviceUiTestRunner();
- }
-
public class UiAutomatorTestCase extends junit.framework.TestCase {
ctor public UiAutomatorTestCase();
method public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java b/uiautomator/instrumentation/testrunner-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java
similarity index 76%
rename from uiautomator/library/core-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java
rename to uiautomator/instrumentation/testrunner-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java
index a668cf5..e40bd14 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java
+++ b/uiautomator/instrumentation/testrunner-src/com/android/uiautomator/core/OnDeviceUiAutomatorBridge.java
@@ -19,11 +19,15 @@
import android.app.Service;
import android.app.UiAutomation;
import android.content.Context;
+import android.os.PowerManager;
import android.view.Display;
import android.view.ViewConfiguration;
import android.view.WindowManager;
-class OnDeviceUiAutomatorBridge extends UiAutomatorBridge {
+/**
+ * @hide
+ */
+public class OnDeviceUiAutomatorBridge extends UiAutomatorBridge {
private final Context mContext;
@@ -38,6 +42,18 @@
return windowManager.getDefaultDisplay();
}
+ @Override
+ public int getRotation() {
+ return getDefaultDisplay().getRotation();
+ }
+
+ @Override
+ public boolean isScreenOn() {
+ PowerManager pm = (PowerManager)
+ mContext.getSystemService(Service.POWER_SERVICE);
+ return pm.isScreenOn();
+ }
+
public long getSystemLongPressTime() {
return ViewConfiguration.getLongPressTimeout();
}
diff --git a/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java b/uiautomator/instrumentation/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java
similarity index 95%
rename from uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java
rename to uiautomator/instrumentation/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java
index dc38d25..00897c4 100644
--- a/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java
+++ b/uiautomator/instrumentation/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestCase.java
@@ -26,12 +26,13 @@
import android.view.inputmethod.InputMethodInfo;
import com.android.internal.view.IInputMethodManager;
+import com.android.uiautomator.core.OnDeviceUiAutomatorBridge;
import com.android.uiautomator.core.UiDevice;
import java.util.List;
/**
- * UI automator test case that is executed on the device.
+ * UI automator test case that is executed on the device.
*/
public class OnDeviceUiTestCase extends AndroidTestCase {
private static final String DISABLE_IME = "disable_ime";
@@ -51,7 +52,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- UiDevice.getInstance().initialize(getContext(), mUiAutomation);
+ UiDevice.getInstance().initialize(new OnDeviceUiAutomatorBridge(mContext, mUiAutomation));
mShouldDisableIme = "true".equals(getParams().getString(DISABLE_IME));
if (mShouldDisableIme) {
setDummyIme();
diff --git a/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestRunner.java b/uiautomator/instrumentation/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestRunner.java
similarity index 100%
rename from uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestRunner.java
rename to uiautomator/instrumentation/testrunner-src/com/android/uiautomator/testrunner/OnDeviceUiTestRunner.java
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java b/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
index e712559..cd7df67 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
@@ -17,19 +17,17 @@
package com.android.uiautomator.core;
import android.app.UiAutomation;
-import android.content.Context;
import android.graphics.Point;
-import android.os.IPowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
-import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.util.Predicate;
@@ -57,22 +55,15 @@
private final UiAutomatorBridge mUiAutomatorBridge;
- private final IWindowManager mWindowManager;
-
private static final long REGULAR_CLICK_LENGTH = 100;
private long mDownTime;
+ // Inserted after each motion event injection.
+ private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;
+
public InteractionController(UiAutomatorBridge bridge) {
mUiAutomatorBridge = bridge;
-
- // Obtain the window manager.
- mWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
- if (mWindowManager == null) {
- throw new RuntimeException("Unable to connect to WindowManager, "
- + "is the system running?");
- }
}
/**
@@ -253,7 +244,7 @@
*/
public boolean clickAndWaitForNewWindow(final int x, final int y, long timeout) {
return (clickAndWaitForEvents(x, y, timeout, true,
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED +
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED |
AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED));
}
@@ -389,7 +380,7 @@
// become completely dependent on the speed of the system and results
// may vary on different devices. This guarantees at minimum we have
// a preset delay.
- SystemClock.sleep(5);
+ SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
}
ret &= touchUp(upX, upY);
return(ret);
@@ -432,7 +423,7 @@
// become completely dependent on the speed of the system and results
// may vary on different devices. This guarantees at minimum we have
// a preset delay.
- SystemClock.sleep(5);
+ SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
}
}
}
@@ -447,6 +438,7 @@
}
KeyEvent[] events = mKeyCharacterMap.getEvents(text.toCharArray());
+
if (events != null) {
for (KeyEvent event2 : events) {
// We have to change the time of an event before injecting it because
@@ -491,8 +483,8 @@
* @throws RemoteException
*/
public boolean isNaturalRotation() throws RemoteException {
- return mWindowManager.getRotation() == UiAutomation.ROTATION_FREEZE_0
- || mWindowManager.getRotation() == UiAutomation.ROTATION_FREEZE_180;
+ int ret = mUiAutomatorBridge.getRotation();
+ return ret == UiAutomation.ROTATION_FREEZE_0 || ret == UiAutomation.ROTATION_FREEZE_180;
}
/**
@@ -583,12 +575,111 @@
* @throws RemoteException
*/
public boolean isScreenOn() throws RemoteException {
- IPowerManager pm =
- IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
- return pm.isScreenOn();
+ return mUiAutomatorBridge.isScreenOn();
}
private boolean injectEventSync(InputEvent event) {
return mUiAutomatorBridge.injectInputEvent(event, true);
}
+
+ private int getPointerAction(int motionEnvent, int index) {
+ return motionEnvent + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ }
+
+ /**
+ * Performs a multi-touch gesture
+ *
+ * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have
+ * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability
+ * to specify the touch points along the path of a pointer, the caller is able to specify
+ * complex gestures like circles, irregular shapes etc, where each pointer may take a
+ * different path.
+ *
+ * To create a single point on a pointer's touch path
+ * <code>
+ * PointerCoords p = new PointerCoords();
+ * p.x = stepX;
+ * p.y = stepY;
+ * p.pressure = 1;
+ * p.size = 1;
+ * </code>
+ * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path.
+ * Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own
+ * path. Each {@link PointerCoords} in an array constitute a point on a pointer's path.
+ * @since API Level 18
+ */
+ public void generateMultiPointerGesture(PointerCoords[] ... touches) {
+ if (touches.length < 2) {
+ throw new IllegalArgumentException("Must provide coordinates for at least 2 pointers");
+ }
+
+ // Get the pointer with the max steps to inject.
+ int maxSteps = 0;
+ for (int x = 0; x < touches.length; x++)
+ maxSteps = (maxSteps < touches[x].length) ? touches[x].length : maxSteps;
+
+ // specify the properties for each pointer as finger touch
+ PointerProperties[] properties = new PointerProperties[touches.length];
+ PointerCoords[] pointerCoords = new PointerCoords[touches.length];
+ for (int x = 0; x < touches.length; x++) {
+ PointerProperties prop = new PointerProperties();
+ prop.id = x;
+ prop.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ properties[x] = prop;
+
+ // for each pointer set the first coordinates for touch down
+ pointerCoords[x] = touches[x][0];
+ }
+
+ // Touch down all pointers
+ long downTime = SystemClock.uptimeMillis();
+ MotionEvent event;
+ event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 1,
+ properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ injectEventSync(event);
+
+ for (int x = 1; x < touches.length; x++) {
+ event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
+ getPointerAction(MotionEvent.ACTION_POINTER_DOWN, x), x + 1, properties,
+ pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ injectEventSync(event);
+ }
+
+ // Move all pointers
+ for (int i = 1; i < maxSteps - 1; i++) {
+ // for each pointer
+ for (int x = 0; x < touches.length; x++) {
+ // check if it has coordinates to move
+ if (touches[x].length > i)
+ pointerCoords[x] = touches[x][i];
+ else
+ pointerCoords[x] = touches[x][touches[x].length - 1];
+ }
+
+ event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_MOVE, touches.length, properties, pointerCoords, 0, 0, 1, 1,
+ 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+
+ injectEventSync(event);
+ SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
+ }
+
+ // For each pointer get the last coordinates
+ for (int x = 0; x < touches.length; x++)
+ pointerCoords[x] = touches[x][touches[x].length - 1];
+
+ // touch up
+ for (int x = 1; x < touches.length; x++) {
+ event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
+ getPointerAction(MotionEvent.ACTION_POINTER_UP, x), x + 1, properties,
+ pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ injectEventSync(event);
+ }
+
+ Log.i(LOG_TAG, "x " + pointerCoords[0].x);
+ // first to touch down is last up
+ event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 1,
+ properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+ injectEventSync(event);
+ }
}
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/UiAutomatorBridge.java b/uiautomator/library/core-src/com/android/uiautomator/core/UiAutomatorBridge.java
index 0387a62..a15cc24 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/UiAutomatorBridge.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/UiAutomatorBridge.java
@@ -17,7 +17,10 @@
import java.io.IOException;
import java.util.concurrent.TimeoutException;
-abstract class UiAutomatorBridge {
+/**
+ * @hide
+ */
+public abstract class UiAutomatorBridge {
private static final String LOG_TAG = UiAutomatorBridge.class.getSimpleName();
@@ -79,6 +82,10 @@
return mUiAutomation.setRotation(rotation);
}
+ public abstract int getRotation();
+
+ public abstract boolean isScreenOn();
+
public void waitForIdle() {
waitForIdle(TOTAL_TIME_TO_WAIT_FOR_IDLE_STATE);
}
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java b/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
index 910deda..51695f6 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java
@@ -16,7 +16,6 @@
package com.android.uiautomator.core;
-import android.app.UiAutomation;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -82,12 +81,8 @@
/**
* @hide
*/
- public void initialize(Context context, UiAutomation uiAutomation) {
- if (context == null) {
- mUiAutomationBridge = new ShellUiAutomatorBridge(uiAutomation);
- } else {
- mUiAutomationBridge = new OnDeviceUiAutomatorBridge(context, uiAutomation);
- }
+ public void initialize(UiAutomatorBridge uiAutomatorBridge) {
+ mUiAutomationBridge = uiAutomatorBridge;
}
boolean isInWatcherContext() {
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java b/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
index 2bf6455..ff49f38 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
@@ -16,10 +16,12 @@
package com.android.uiautomator.core;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.MotionEvent.PointerCoords;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -47,13 +49,17 @@
**/
protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500;
/**
+ * @since API Level 16
+ **/
+ protected static final int SWIPE_MARGIN_LIMIT = 5;
+ /**
* @since API Level 17
**/
protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000;
/**
- * @since API Level 16
+ * @since API Level 18
**/
- protected static final int SWIPE_MARGIN_LIMIT = 5;
+ protected static final int FINGER_TOUCH_HALF_WIDTH = 20;
private final UiSelector mSelector;
private final UiAutomatorBridge mUiAutomationBridge;
@@ -338,7 +344,7 @@
}
Rect rect = getVisibleBounds(node);
return getInteractionController().clickAndWaitForEvents(rect.centerX(), rect.centerY(),
- WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED +
+ WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED |
AccessibilityEvent.TYPE_VIEW_SELECTED);
}
@@ -832,4 +838,175 @@
return "";
return cs.toString();
}
-}
+
+ /**
+ * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out
+ * away from each other diagonally towards the edges of the current UI element represented by
+ * this UiObject.
+ * @param percent of the object's diagonal length to use for the pinch
+ * @param steps indicates the number of injected move steps into the system. Steps are
+ * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void pinchOut(int percent, int steps) throws UiObjectNotFoundException {
+ // make value between 1 and 100
+ percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
+ float percentage = percent / 100f;
+
+ AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
+ if (node == null) {
+ throw new UiObjectNotFoundException(getSelector().toString());
+ }
+
+ Rect rect = getVisibleBounds(node);
+ if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
+ throw new IllegalStateException("Object width is too small for operation");
+
+ // start from the same point at the center of the control
+ Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
+ Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
+
+ // End at the top-left and bottom-right corners of the control
+ Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
+ rect.centerY());
+ Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
+ rect.centerY());
+
+ twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
+ }
+
+ /**
+ * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other
+ * diagonally from the edges of the current UI element represented by this UiObject, until the
+ * center.
+ * @param percent of the object's diagonal length to use for the pinch
+ * @param steps indicates the number of injected move steps into the system. Steps are
+ * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
+ * @throws UiObjectNotFoundException
+ * @since API Level 18
+ */
+ public void pinchIn(int percent, int steps) throws UiObjectNotFoundException {
+ // make value between 1 and 100
+ percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent;
+ float percentage = percent / 100f;
+
+ AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
+ if (node == null) {
+ throw new UiObjectNotFoundException(getSelector().toString());
+ }
+
+ Rect rect = getVisibleBounds(node);
+ if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
+ throw new IllegalStateException("Object width is too small for operation");
+
+ Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
+ rect.centerY());
+ Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
+ rect.centerY());
+
+ Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
+ Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
+
+ twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
+ }
+
+ /**
+ * Generates a 2 pointer gesture from an arbitrary starting and ending points.
+ *
+ * @param startPoint1 start point of pointer 1
+ * @param startPoint2 start point of pointer 2
+ * @param endPoint1 end point of pointer 1
+ * @param endPoint2 end point of pointer 2
+ * @param steps indicates the number of injected move steps into the system. Steps are
+ * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
+ * @since API Level 18
+ */
+ public void twoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1,
+ Point endPoint2, int steps) {
+
+ // avoid a divide by zero
+ if(steps == 0)
+ steps = 1;
+
+ final float stepX1 = (endPoint1.x - startPoint1.x) / steps;
+ final float stepY1 = (endPoint1.y - startPoint1.y) / steps;
+ final float stepX2 = (endPoint2.x - startPoint2.x) / steps;
+ final float stepY2 = (endPoint2.y - startPoint2.y) / steps;
+
+ int eventX1, eventY1, eventX2, eventY2;
+ eventX1 = startPoint1.x;
+ eventY1 = startPoint1.y;
+ eventX2 = startPoint2.x;
+ eventY2 = startPoint2.y;
+
+ // allocate for steps plus first down and last up
+ PointerCoords[] points1 = new PointerCoords[steps + 2];
+ PointerCoords[] points2 = new PointerCoords[steps + 2];
+
+ // Include the first and last touch downs in the arrays of steps
+ for (int i = 0; i < steps + 1; i++) {
+ PointerCoords p1 = new PointerCoords();
+ p1.x = eventX1;
+ p1.y = eventY1;
+ p1.pressure = 1;
+ p1.size = 1;
+ points1[i] = p1;
+
+ PointerCoords p2 = new PointerCoords();
+ p2.x = eventX2;
+ p2.y = eventY2;
+ p2.pressure = 1;
+ p2.size = 1;
+ points2[i] = p2;
+
+ eventX1 += stepX1;
+ eventY1 += stepY1;
+ eventX2 += stepX2;
+ eventY2 += stepY2;
+ }
+
+ // ending pointers coordinates
+ PointerCoords p1 = new PointerCoords();
+ p1.x = endPoint1.x;
+ p1.y = endPoint1.y;
+ p1.pressure = 1;
+ p1.size = 1;
+ points1[steps + 1] = p1;
+
+ PointerCoords p2 = new PointerCoords();
+ p2.x = endPoint2.x;
+ p2.y = endPoint2.y;
+ p2.pressure = 1;
+ p2.size = 1;
+ points2[steps + 1] = p2;
+
+ multiPointerGesture(points1, points2);
+ }
+
+ /**
+ * Performs a multi-touch gesture
+ *
+ * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have
+ * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability
+ * to specify the touch points along the path of a pointer, the caller is able to specify
+ * complex gestures like circles, irregular shapes etc, where each pointer may take a
+ * different path.
+ *
+ * To create a single point on a pointer's touch path
+ * <code>
+ * PointerCoords p = new PointerCoords();
+ * p.x = stepX;
+ * p.y = stepY;
+ * p.pressure = 1;
+ * p.size = 1;
+ * </code>
+ * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path.
+ * Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own
+ * path. Each {@link PointerCoords} in an array constitute a point on a pointer's path.
+ * @since API Level 18
+ */
+ public void multiPointerGesture(PointerCoords[] ...touches) {
+ getInteractionController().generateMultiPointerGesture(touches);
+ }
+}
\ No newline at end of file
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
similarity index 73%
rename from uiautomator/library/core-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
rename to uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index ebf99f2..1afa513 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -18,24 +18,31 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.UiAutomation;
import android.app.IActivityManager.ContentProviderHolder;
+import android.app.UiAutomation;
+import android.content.Context;
import android.content.IContentProvider;
import android.database.Cursor;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.os.IBinder;
+import android.os.IPowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.Display;
+import android.view.IWindowManager;
-class ShellUiAutomatorBridge extends UiAutomatorBridge {
+/**
+ * @hide
+ */
+public class ShellUiAutomatorBridge extends UiAutomatorBridge {
private static final String LOG_TAG = ShellUiAutomatorBridge.class.getSimpleName();
- ShellUiAutomatorBridge(UiAutomation uiAutomation) {
+ public ShellUiAutomatorBridge(UiAutomation uiAutomation) {
super(uiAutomation);
}
@@ -84,4 +91,32 @@
}
return longPressTimeout;
}
+
+ @Override
+ public int getRotation() {
+ IWindowManager wm =
+ IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
+ int ret = -1;
+ try {
+ ret = wm.getRotation();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Error getting screen rotation", e);
+ throw new RuntimeException(e);
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean isScreenOn() {
+ IPowerManager pm =
+ IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
+ boolean ret = false;
+ try {
+ ret = pm.isScreenOn();
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Error getting screen status", e);
+ throw new RuntimeException(e);
+ }
+ return ret;
+ }
}
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
similarity index 100%
rename from uiautomator/library/core-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
rename to uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
diff --git a/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestRunner.java b/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestRunner.java
index 4405927..1b751da 100644
--- a/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestRunner.java
+++ b/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestRunner.java
@@ -28,6 +28,7 @@
import android.test.RepetitiveTest;
import android.util.Log;
+import com.android.uiautomator.core.ShellUiAutomatorBridge;
import com.android.uiautomator.core.Tracer;
import com.android.uiautomator.core.UiAutomationShellWrapper;
import com.android.uiautomator.core.UiDevice;
@@ -113,8 +114,8 @@
mHandlerThread.start();
UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();
automationWrapper.connect();
- UiDevice.getInstance().initialize(null, automationWrapper.getUiAutomation());
mUiDevice = UiDevice.getInstance();
+ mUiDevice.initialize(new ShellUiAutomatorBridge(automationWrapper.getUiAutomation()));
List<TestCase> testCases = collector.getTestCases();
Bundle testRunOutput = new Bundle();