diff --git a/.gitignore b/.gitignore
index 514e95f89..b12b66ee1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,5 @@ out
out/*
target/classes/*
target/test-classes/*
-target/surfire-reports/*
+target/surefire-reports/*
settings.xml
diff --git a/README.md b/README.md
index 430aec1c5..dfbf27c53 100644
--- a/README.md
+++ b/README.md
@@ -63,3 +63,9 @@ Locators:
- when no appium server is running, the proper error is thrown, instead of a NullPointerException
*1.0.2*
- recompiled to include some missing methods such as shake() and complexFind()
+
+## Running tests
+
+Run a test using
+
+> mvn -Dtest=io.appium.java_client.MobileDriverAndroidTest clean test
\ No newline at end of file
diff --git a/java-client.iml b/java-client.iml
index 96f806544..3ff4d8e2e 100644
--- a/java-client.iml
+++ b/java-client.iml
@@ -5,9 +5,9 @@
+
-
@@ -25,6 +25,7 @@
+
diff --git a/pom.xml b/pom.xml
index e258813da..9e074205f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,6 +13,11 @@
google-collections
1.0
+
+ com.google.code.gson
+ gson
+ 2.2.4
+
org.seleniumhq.selenium
selenium-java
diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java
index 1c8ccce13..b1ec52ec8 100644
--- a/src/main/java/io/appium/java_client/AppiumDriver.java
+++ b/src/main/java/io/appium/java_client/AppiumDriver.java
@@ -35,11 +35,16 @@ public class AppiumDriver extends RemoteWebDriver implements MobileDriver, Conte
FindsByAndroidUIAutomator, FindsByAccessibilityId {
private final static MobileErrorHandler errorHandler = new MobileErrorHandler();
+ private URL remoteAddress;
+ private ComplexFind complexFind;
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){
super(remoteAddress, desiredCapabilities);
+ this.remoteAddress = remoteAddress;
+ complexFind = new ComplexFind(this);
+
ImmutableMap.Builder builder = ImmutableMap.builder();
builder
.put(RESET, postC("/session/:sessionId/appium/app/reset"))
@@ -461,14 +466,17 @@ public void shake() {
execute(SHAKE);
}
- public String complexFind(String[] complex) {
- Response response = execute(COMPLEX_FIND, ImmutableMap.of("selector", complex));
-
- return response.toString();
+ public MobileElement complexFind(String complex) {
+ return complexFind.execute(complex);
}
+ public MobileElement scrollTo(String text) {
+ return complexFind.scrollTo(text);
+ }
-
+ public MobileElement scrollToExact(String text) {
+ return complexFind.scrollToExact(text);
+ }
@Override
public WebDriver context(String name) {
@@ -571,4 +579,7 @@ private static CommandInfo deleteC(String url) {
return new CommandInfo(url, HttpVerb.DELETE);
}
+ public URL getRemoteAddress() {
+ return remoteAddress;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/appium/java_client/ComplexFind.java b/src/main/java/io/appium/java_client/ComplexFind.java
new file mode 100644
index 000000000..3821a9bf3
--- /dev/null
+++ b/src/main/java/io/appium/java_client/ComplexFind.java
@@ -0,0 +1,97 @@
+package io.appium.java_client;
+
+import com.google.gson.JsonParser;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.openqa.selenium.remote.RemoteWebElement;
+
+public class ComplexFind {
+
+ private AppiumDriver driver;
+ private static final HttpClient client = HttpClients.createDefault();
+ private static final JsonParser parser = new JsonParser();
+
+ public ComplexFind(AppiumDriver driver) {
+ this.driver = driver;
+ }
+
+ /**
+ * Create a new remote web element.
+ */
+ private MobileElement newElement(final String elementId) {
+ final MobileElement element = new MobileElement(new RemoteWebElement(), driver);
+ element.setParent(driver);
+ element.setId(elementId);
+ element.setFileDetector(driver.getFileDetector());
+ return element;
+ }
+
+ /*
+ This is a port of the following Ruby code from github.com/appium/ruby_lib
+ The Selenium Java bindings make it impossible to post JSON so we're using
+ HttpPost directly.
+
+ # Scroll to an element containing target text or description.
+ # @param text [String] the text to search for in the text value and content description
+ # @return [Element] the element scrolled to
+ def scroll_to text
+ args = 'scroll',
+ # textContains(text)
+ [ [3, text] ],
+ # descriptionContains(text)
+ [ [7, text] ]
+
+ mobile :find, args
+ end
+ */
+ protected MobileElement scrollTo(String text) {
+ text = text.replaceAll("\"", "\\\""); // quotes must be escaped.
+ // ["scroll", [[3,"animation"]], [[7,"animation"]]]
+ final String complex = "[\"scroll\",[[3,\"" + text + "\"]],[[7,\"" + text + "\"]]]";
+ return execute(complex);
+ }
+
+ protected MobileElement scrollToExact(String text) {
+ text = text.replaceAll("\"", "\\\""); // quotes must be escaped.
+ // ["scroll", [[1,"Animation"]], [[5,"Animation"]]]
+ final String complex = "[\"scroll\",[[1,\"" + text + "\"]],[[5,\"" + text + "\"]]]";
+ return execute(complex);
+ }
+
+ protected MobileElement execute(String complex) {
+ MobileElement element = null;
+ try {
+ final String id = driver.getSessionId().toString();
+ final String executeURL = driver.getRemoteAddress() + "/session/" + id + "/appium/app/complex_find";
+
+ final HttpPost post = new HttpPost(executeURL);
+ post.setEntity(new StringEntity(complex, "UTF8"));
+ post.setHeader("Content-type", "application/json");
+
+ final HttpEntity responseEntity = client.execute(post).getEntity();
+
+ if (responseEntity != null) {
+ try {
+ final String responseString = EntityUtils.toString(responseEntity);
+ // {"status":0,"value":{"ELEMENT":"1"},"sessionId":"8e982755-980f-4036-b3d1-c0e14e890273"}
+ final String elementId = parser.parse(responseString)
+ .getAsJsonObject().get("value").getAsJsonObject().get("ELEMENT")
+ .getAsString();
+
+ element = newElement(elementId);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ } finally {
+ EntityUtils.consume(responseEntity);
+ }
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ return element;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/io/appium/java_client/AndroidUIAutomatorTest.java b/src/test/java/io/appium/java_client/AndroidUIAutomatorTest.java
index 9dfc21e79..2a9865b65 100644
--- a/src/test/java/io/appium/java_client/AndroidUIAutomatorTest.java
+++ b/src/test/java/io/appium/java_client/AndroidUIAutomatorTest.java
@@ -38,6 +38,28 @@ public void tearDown() throws Exception {
driver.quit();
}
+ @Test
+ public void complexFind() {
+ String animation = String.format("[\"scroll\",[[3,\"%1$s\"]],[[7,\"%1$s\"]]]", "animation");
+ String cloning = String.format("[\"scroll\",[[3,\"%1$s\"]],[[7,\"%1$s\"]]]", "cloning");
+
+ driver.complexFind(animation).click();
+ driver.complexFind(cloning).click();
+ }
+
+ @Test
+ public void scrollTo() {
+ driver.scrollTo("animation").click();
+ driver.scrollTo("cloning").click();
+ }
+
+ @Test
+ public void scrollToExact() {
+ driver.scrollToExact("Animation").click();
+ driver.scrollToExact("Cloning").click();
+ }
+
+
@Test
public void findElementTest() {
WebElement element = driver.findElementByAndroidUIAutomator("new UiSelector().index(0)");