diff --git a/.gitignore b/.gitignore
index e55f86e7f..04f0265e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ app/android/AndroidManifest.xml
.*~
*~
uiautomator/bootstrap/target/
+org.eclipse.ltk.core.refactoring.prefs
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java b/uiautomator/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java
index 9c6ef813b..eb2afad79 100644
--- a/uiautomator/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java
@@ -1,6 +1,8 @@
package io.appium.android.bootstrap;
+import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException;
import io.appium.android.bootstrap.exceptions.NoAttributeFoundException;
+import io.appium.android.bootstrap.utils.Point;
import android.graphics.Rect;
import com.android.uiautomator.core.UiObject;
@@ -29,6 +31,63 @@ public class AndroidElement {
return el.click();
}
+ public Point getAbsolutePosition(final Double X, final Double Y)
+ throws UiObjectNotFoundException, InvalidCoordinatesException {
+ final Point point = new Point(X, Y);
+ return getAbsolutePosition(point, false);
+ }
+
+ public Point getAbsolutePosition(final Double X, final Double Y,
+ final boolean boundsChecking) throws UiObjectNotFoundException,
+ InvalidCoordinatesException {
+ final Point point = new Point(X, Y);
+ return getAbsolutePosition(point, boundsChecking);
+ }
+
+ public Point getAbsolutePosition(final Point point)
+ throws UiObjectNotFoundException, InvalidCoordinatesException {
+ return getAbsolutePosition(point, false);
+ }
+
+ public Point getAbsolutePosition(final Point point,
+ final boolean boundsChecking) throws UiObjectNotFoundException,
+ InvalidCoordinatesException {
+ final Rect rect = el.getBounds();
+ final Point pos = new Point();
+
+ if (point.x == 0) {
+ pos.x = rect.width() * 0.5 + rect.left;
+ } else if (point.x <= 1) {
+ pos.x = rect.width() * point.x + rect.left;
+ } else {
+ pos.x = rect.left + point.x;
+ }
+ if (boundsChecking == true) {
+ if (pos.x > rect.right || pos.x < rect.left) {
+ throw new InvalidCoordinatesException("X coordinate ("
+ + pos.x.toString() + " is outside of element rect: "
+ + rect.toShortString());
+ }
+ }
+
+ if (point.y == 0) {
+ pos.y = rect.height() * 0.5 + rect.top;
+ } else if (point.y <= 1) {
+ pos.y = rect.height() * point.y + rect.top;
+ } else {
+ pos.y = rect.left + point.y;
+ }
+ if (boundsChecking == true) {
+ if (pos.y > rect.bottom || pos.y < rect.top) {
+ throw new InvalidCoordinatesException("Y coordinate ("
+ + pos.y.toString() + " is outside of element rect: "
+ + rect.toShortString());
+ }
+ }
+
+ return pos;
+ }
+
public boolean getBoolAttribute(final String attr)
throws UiObjectNotFoundException, NoAttributeFoundException {
boolean res = false;
@@ -98,4 +157,5 @@ public class AndroidElement {
public boolean setText(final String text) throws UiObjectNotFoundException {
return el.setText(text);
}
+
}
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/CommandHandler.java b/uiautomator/bootstrap/src/io/appium/android/bootstrap/CommandHandler.java
index ee46ac299..1684bb485 100644
--- a/uiautomator/bootstrap/src/io/appium/android/bootstrap/CommandHandler.java
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/CommandHandler.java
@@ -1,5 +1,8 @@
package io.appium.android.bootstrap;
+import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException;
+import io.appium.android.bootstrap.utils.Point;
+
import java.util.ArrayList;
import org.json.JSONException;
@@ -38,6 +41,36 @@ public abstract class CommandHandler {
return retPos;
}
+ protected static Point GetAbsPos(final Point point)
+ throws InvalidCoordinatesException {
+ final UiDevice d = UiDevice.getInstance();
+ final Point retPos = new Point(point); // copy inputed point
+
+ final Double width = new Double(d.getDisplayWidth());
+ if (point.x < 1) {
+ retPos.x = width * point.x;
+ }
+
+ if (retPos.x > width || retPos.x < 0) {
+ throw new InvalidCoordinatesException("X coordinate ("
+ + retPos.x.toString() + " is outside of screen width: "
+ + width.toString());
+ }
+
+ final Double height = new Double(d.getDisplayHeight());
+ if (point.y < 1) {
+ retPos.y = height * point.y;
+ }
+
+ if (retPos.y > height || retPos.y < 0) {
+ throw new InvalidCoordinatesException("Y coordinate ("
+ + retPos.y.toString() + " is outside of screen height: "
+ + height.toString());
+ }
+
+ return retPos;
+ }
+
/**
* Abstract method that handlers must implement.
*
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/exceptions/InvalidCoordinatesException.java b/uiautomator/bootstrap/src/io/appium/android/bootstrap/exceptions/InvalidCoordinatesException.java
new file mode 100644
index 000000000..cd3c47ff6
--- /dev/null
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/exceptions/InvalidCoordinatesException.java
@@ -0,0 +1,14 @@
+package io.appium.android.bootstrap.exceptions;
+
+/**
+ * An exception that is thrown when an invalid coordinate is used.
+ *
+ * @author xuru
+ * @param msg
+ * A descriptive message describing the error.
+ */
+public class InvalidCoordinatesException extends Exception {
+ public InvalidCoordinatesException(final String msg) {
+ super(msg);
+ }
+}
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/handler/Swipe.java b/uiautomator/bootstrap/src/io/appium/android/bootstrap/handler/Swipe.java
index ca93d7a52..7efc6039c 100644
--- a/uiautomator/bootstrap/src/io/appium/android/bootstrap/handler/Swipe.java
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/handler/Swipe.java
@@ -2,14 +2,19 @@ package io.appium.android.bootstrap.handler;
import io.appium.android.bootstrap.AndroidCommand;
import io.appium.android.bootstrap.AndroidCommandResult;
+import io.appium.android.bootstrap.AndroidElement;
import io.appium.android.bootstrap.CommandHandler;
+import io.appium.android.bootstrap.Logger;
+import io.appium.android.bootstrap.exceptions.ElementNotInHashException;
+import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException;
+import io.appium.android.bootstrap.utils.Point;
-import java.util.ArrayList;
import java.util.Hashtable;
import org.json.JSONException;
import com.android.uiautomator.core.UiDevice;
+import com.android.uiautomator.core.UiObjectNotFoundException;
/**
* This handler is used to swipe.
@@ -33,26 +38,40 @@ public class Swipe extends CommandHandler {
public AndroidCommandResult execute(final AndroidCommand command)
throws JSONException {
final Hashtable params = command.params();
- final Double startX = Double.parseDouble(params.get("startX").toString());
- final Double startY = Double.parseDouble(params.get("startY").toString());
- final Double endX = Double.parseDouble(params.get("endX").toString());
- final Double endY = Double.parseDouble(params.get("endY").toString());
+ final Point start = new Point(params.get("startX"), params.get("startY"));
+ final Point end = new Point(params.get("endX"), params.get("endY"));
final Integer steps = (Integer) params.get("steps");
+ final UiDevice device = UiDevice.getInstance();
+
+ Point absStartPos = new Point();
+ Point absEndPos = new Point();
if (command.isElementCommand()) {
- // Can this command run on the element it's self?
- // swipe on an element is handled by 4 different commands:
- // swipeDown, swipeLeft, swipeRight, and swipeUp
- // We have to figure out which to call and position it correctly...
+ try {
+ final AndroidElement el = command.getElement();
+ absStartPos = el.getAbsolutePosition(start);
+ absEndPos = el.getAbsolutePosition(end, false);
+ } catch (final ElementNotInHashException e) {
+ return getErrorResult(e.getMessage());
+ } catch (final UiObjectNotFoundException e) {
+ return getErrorResult(e.getMessage());
+ } catch (final InvalidCoordinatesException e) {
+ return getErrorResult(e.getMessage());
+ }
} else {
- final UiDevice device = UiDevice.getInstance();
- final Double[] coords = { startX, startY, endX, endY };
- final ArrayList posVals = absPosFromCoords(coords);
- final boolean rv = device.swipe(posVals.get(0), posVals.get(1),
- posVals.get(2), posVals.get(3), steps);
- return getSuccessResult(rv);
+ try {
+ absStartPos = GetAbsPos(start);
+ absEndPos = GetAbsPos(end);
+ } catch (final InvalidCoordinatesException e) {
+ return getErrorResult(e.getMessage());
+ }
}
- return getErrorResult("Error in swiping...");
+ Logger.info("Swiping from " + absStartPos.toString() + " to "
+ + absEndPos.toString() + " with steps: " + steps.toString());
+ final boolean rv = device.swipe(absStartPos.x.intValue(),
+ absStartPos.y.intValue(), absEndPos.x.intValue(),
+ absEndPos.y.intValue(), steps);
+ return getSuccessResult(rv);
}
}
diff --git a/uiautomator/bootstrap/src/io/appium/android/bootstrap/utils/Point.java b/uiautomator/bootstrap/src/io/appium/android/bootstrap/utils/Point.java
new file mode 100644
index 000000000..a90367d76
--- /dev/null
+++ b/uiautomator/bootstrap/src/io/appium/android/bootstrap/utils/Point.java
@@ -0,0 +1,71 @@
+package io.appium.android.bootstrap.utils;
+
+public class Point {
+
+ public Double x;
+ public Double y;
+
+ public Point() {
+ x = 0.0;
+ y = 0.0;
+ }
+
+ public Point(final Double x, final Double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Point(final Object x, final Object y) {
+ this.x = Double.parseDouble(x.toString());
+ this.y = Double.parseDouble(y.toString());
+ }
+
+ public Point(final Point other) {
+ x = other.x;
+ y = other.y;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Point other = (Point) obj;
+ if (x == null) {
+ if (other.x != null) {
+ return false;
+ }
+ } else if (!x.equals(other.x)) {
+ return false;
+ }
+ if (y == null) {
+ if (other.y != null) {
+ return false;
+ }
+ } else if (!y.equals(other.y)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (x == null ? 0 : x.hashCode());
+ result = prime * result + (y == null ? 0 : y.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "[x=" + x + ", y=" + y + "]";
+ }
+
+}