diff --git a/src/io/appium/java_client/AndroidKeyCode.java b/src/io/appium/java_client/AndroidKeyCode.java new file mode 100644 index 000000000..a72721d1c --- /dev/null +++ b/src/io/appium/java_client/AndroidKeyCode.java @@ -0,0 +1,34 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +/** + * Some common key codes for Android Key Events + */ +public interface AndroidKeyCode { + + int BACK = 4; + int BACKSPACE = 67; + int DEL = 67; + int ENTER = 66; + int HOME = 3; + int MENU = 82; + int SETTINGS = 176; + int SPACE = 62; + +} diff --git a/src/io/appium/java_client/AndroidKeyMetastate.java b/src/io/appium/java_client/AndroidKeyMetastate.java new file mode 100644 index 000000000..0bf56ad75 --- /dev/null +++ b/src/io/appium/java_client/AndroidKeyMetastate.java @@ -0,0 +1,42 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +/** + * Metastates for Android Key Events + */ +public interface AndroidKeyMetastate { + + int META_ALT_LEFT_ON = 16; + int META_ALT_ON = 2; + int META_ALT_RIGHT_ON = 32; + int META_CAPS_LOCK_ON = 1048576; + int META_CTRL_LEFT_ON = 8192; + int META_CTRL_ON = 4096; + int META_CTRL_RIGHT_ON = 16384; + int META_FUNCTION_ON = 8; + int META_META_LEFT_ON = 131072; + int META_META_ON = 65536; + int META_META_RIGHT_ON = 262144; + int META_NUM_LOCK_ON = 2097152; + int META_SCROLL_LOCK_ON = 4194304; + int META_SHIFT_LEFT_ON = 64; + int META_SHIFT_ON = 1; + int META_SHIFT_RIGHT_ON = 128; + int META_SYM_ON = 4; +} diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index 9442f8ace..a609c879e 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -1,4 +1,5 @@ /* + +Copyright 2014 Appium contributors +Copyright 2014 Software Freedom Conservancy + +Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +17,6 @@ package io.appium.java_client; - import com.google.common.collect.ImmutableMap; import org.openqa.selenium.*; import org.openqa.selenium.remote.*; @@ -27,8 +27,10 @@ import java.util.Map; import java.util.Set; +import static io.appium.java_client.MobileCommand.*; + public class AppiumDriver extends RemoteWebDriver implements MobileDriver, ContextAware, FindsByIosUIAutomation, - FindsByAndroidUIAutomator { + FindsByAndroidUIAutomator, FindsByAccessibilityId { private final MobileErrorHandler errorHandler = new MobileErrorHandler(); @@ -36,7 +38,13 @@ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){ super(remoteAddress, desiredCapabilities); - ImmutableMap mobileCommands = ImmutableMap.of(); + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder + .put(RESET, postC("/session/:sessionId/appium/app/reset")) + .put(GET_STRINGS, getC("/session/:sessionId/appium/app/strings")) + .put(KEY_EVENT, postC("/session/:sessionId/appium/device/keyevent")) + ; + ImmutableMap mobileCommands = builder.build(); HttpCommandExecutor mobileExecutor = new HttpCommandExecutor(mobileCommands, remoteAddress); super.setCommandExecutor(mobileExecutor); @@ -61,6 +69,26 @@ protected Response execute(String command) { } + public void resetApp() { + execute(MobileCommand.RESET); + } + + public String getAppStrings() { + Response response = execute(GET_STRINGS); + return response.getValue().toString(); + } + + public void sendKeyEvent(int key) { + sendKeyEvent(key, null); + } + + public void sendKeyEvent(int key, Integer metastate) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put("keycode", key); + if (metastate != null) { builder.put("metastate", metastate); } + ImmutableMap parameters = builder.build(); + execute(KEY_EVENT, parameters); + } @Override @@ -114,4 +142,26 @@ public WebElement findElementByAndroidUIAutomator(String using) { public List findElementsByAndroidUIAutomator(String using) { return findElements("-android uiautomator", using); } + + @Override + public WebElement findElementByAccessibilityId(String using) { + return findElement("accessibility id", using); + } + + @Override + public List findElementsByAccessibilityId(String using) { + return findElements("accessibility id", using); + } + + private static CommandInfo getC(String url) { + return new CommandInfo(url, HttpVerb.GET); + } + + private static CommandInfo postC(String url) { + return new CommandInfo(url, HttpVerb.POST); + } + + private static CommandInfo deleteC(String url) { + return new CommandInfo(url, HttpVerb.DELETE); + } } \ No newline at end of file diff --git a/src/io/appium/java_client/ErrorCodesMobile.java b/src/io/appium/java_client/ErrorCodesMobile.java index b8eb3e647..8066e94c9 100644 --- a/src/io/appium/java_client/ErrorCodesMobile.java +++ b/src/io/appium/java_client/ErrorCodesMobile.java @@ -1,5 +1,5 @@ /* -Copyright 2014 Selenium committers +Copyright 2014 Appium contributors Copyright 2014 Software Freedom Conservancy Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/io/appium/java_client/FindsByAccessibilityId.java b/src/io/appium/java_client/FindsByAccessibilityId.java new file mode 100644 index 000000000..5ee5600d2 --- /dev/null +++ b/src/io/appium/java_client/FindsByAccessibilityId.java @@ -0,0 +1,27 @@ +/* +Copyright 2014 Appium committers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package io.appium.java_client; + +import org.openqa.selenium.WebElement; + +import java.util.List; + +public interface FindsByAccessibilityId { + WebElement findElementByAccessibilityId(String using); + + List findElementsByAccessibilityId(String using); +} \ No newline at end of file diff --git a/src/io/appium/java_client/IOSKeyCode.java b/src/io/appium/java_client/IOSKeyCode.java new file mode 100644 index 000000000..f76921bb4 --- /dev/null +++ b/src/io/appium/java_client/IOSKeyCode.java @@ -0,0 +1,30 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +/** + * Some common key codes for Android Key Events + */ +public interface IOSKeyCode { + + int BACKSPACE = 8; + int ENTER = 13; + int RETURN = 13; + int SPACE = 32; + +} diff --git a/src/io/appium/java_client/MobileBy.java b/src/io/appium/java_client/MobileBy.java index 3907e452f..a61d96c03 100644 --- a/src/io/appium/java_client/MobileBy.java +++ b/src/io/appium/java_client/MobileBy.java @@ -28,6 +28,14 @@ public static By AndroidUIAutomator(final String uiautomatorText) { return new ByAndroidUIAutomator(uiautomatorText); } + public static By AccessibilityId(final String id) { + if (id == null) { + throw new IllegalArgumentException("Must supply a uiautomationText"); + } + + return new ByAccessibilityId(id); + } + public static class ByIosUIAutomation extends By implements Serializable { private final String automationText; @@ -73,6 +81,30 @@ public WebElement findElement(SearchContext context) { @Override public String toString() { return "By.AndroidUIAutomator: " + automatorText; } } + + public static class ByAccessibilityId extends By implements Serializable { + + private final String id; + + public ByAccessibilityId(String id) { + this.id = id; + } + + @Override + public List findElements(SearchContext context) { + return ((FindsByAccessibilityId) context).findElementsByAccessibilityId(id); + } + + @Override + public WebElement findElement(SearchContext context) { + return ((FindsByAccessibilityId) context).findElementByAccessibilityId(id); + } + + @Override + public String toString() { + return "By.AccessibilityId: " + id; + } + } } diff --git a/src/io/appium/java_client/MobileCommand.java b/src/io/appium/java_client/MobileCommand.java new file mode 100644 index 000000000..541c85fad --- /dev/null +++ b/src/io/appium/java_client/MobileCommand.java @@ -0,0 +1,31 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +/** + * An empty interface defining constants for the mobile commands defined in the Mobile JSON + * wire protocol. + * + */ +public interface MobileCommand { + + String RESET = "reset"; + String GET_STRINGS = "getStrings"; + String KEY_EVENT = "keyEvent"; + +} diff --git a/src/io/appium/java_client/MobileDriver.java b/src/io/appium/java_client/MobileDriver.java index b6fde7f01..a56696ce5 100644 --- a/src/io/appium/java_client/MobileDriver.java +++ b/src/io/appium/java_client/MobileDriver.java @@ -1,4 +1,5 @@ /* + +Copyright 2014 Appium contributors +Copyright 2014 Software Freedom Conservancy + +Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,4 +22,30 @@ public interface MobileDriver extends WebDriver { + /** + * Reset the currently running app for this session + */ + void resetApp(); + + /** + * Get all defined Strings from an Android app + */ + String getAppStrings(); + + /** + * Send a key event to the device + * + * @param key code for the key pressed on the device + */ + void sendKeyEvent(int key); + + /** + * Send a key event along with an Android metastate to an Android device + * Metastates are things like *shift* to get uppercase characters + * + * @param key code for the key pressed on the Android device + * @param metastate metastate for the keypress + */ + void sendKeyEvent(int key, Integer metastate); + } diff --git a/src/io/appium/java_client/MobileErrorHandler.java b/src/io/appium/java_client/MobileErrorHandler.java index e4515e197..efdd7d5da 100644 --- a/src/io/appium/java_client/MobileErrorHandler.java +++ b/src/io/appium/java_client/MobileErrorHandler.java @@ -1,3 +1,20 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + package io.appium.java_client; import org.openqa.selenium.WebDriverException; diff --git a/test/io/appium/java_client/AccessibilityIdTest.java b/test/io/appium/java_client/AccessibilityIdTest.java new file mode 100644 index 000000000..ef6007910 --- /dev/null +++ b/test/io/appium/java_client/AccessibilityIdTest.java @@ -0,0 +1,66 @@ +package io.appium.java_client; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.io.File; +import java.net.URL; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Test context-related features + */ +public class AccessibilityIdTest { + + private AppiumDriver driver; + + @Before + public void setup() throws Exception { + File appDir = new File("test/io/appium/java_client"); + File app = new File(appDir, "UICatalog.app.zip"); + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(CapabilityType.BROWSER_NAME, ""); + capabilities.setCapability(CapabilityType.VERSION, "7.1"); + capabilities.setCapability(CapabilityType.PLATFORM, "Mac"); + capabilities.setCapability("device", "iPhone Simulator"); + capabilities.setCapability("app", app.getAbsolutePath()); + driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); + } + + @After + public void tearDown() throws Exception { + driver.quit(); + } + + @Test + public void findElementTest() { + WebElement element = driver.findElementByAccessibilityId("UICatalog"); + assertNotNull(element); + } + + @Test + public void findElementsTest() { + List elements = driver.findElementsByAccessibilityId("UICatalog"); + assertEquals(1, elements.size()); + } + + @Test + public void MobileElementByTest() { + WebElement element = driver.findElement(MobileBy.AccessibilityId("UICatalog")); + assertNotNull(element); + } + + @Test + public void MobileElementsByTest() { + List elements = driver.findElements(MobileBy.AccessibilityId("UICatalog")); + assertEquals(1, elements.size()); + } + +} diff --git a/test/io/appium/java_client/AndroidUIAutomatorTest.java b/test/io/appium/java_client/AndroidUIAutomatorTest.java index cedad93a8..f0f5df2fa 100644 --- a/test/io/appium/java_client/AndroidUIAutomatorTest.java +++ b/test/io/appium/java_client/AndroidUIAutomatorTest.java @@ -24,7 +24,7 @@ public class AndroidUIAutomatorTest { @Before public void setup() throws Exception { File appDir = new File("test/io/appium/java_client"); - File app = new File(appDir, "ApiDemos-debug.apk.zip"); + File app = new File(appDir, "ApiDemos-debug.apk"); DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, ""); capabilities.setCapability("device", "Android"); diff --git a/test/io/appium/java_client/ContextTest.java b/test/io/appium/java_client/ContextTest.java index 90eabb306..2a53c11d7 100644 --- a/test/io/appium/java_client/ContextTest.java +++ b/test/io/appium/java_client/ContextTest.java @@ -1,3 +1,20 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + package io.appium.java_client; import org.junit.After; diff --git a/test/io/appium/java_client/IosUIAutomationTest.java b/test/io/appium/java_client/IosUIAutomationTest.java index 8c094a51f..fd3c02be8 100644 --- a/test/io/appium/java_client/IosUIAutomationTest.java +++ b/test/io/appium/java_client/IosUIAutomationTest.java @@ -53,7 +53,6 @@ public void findElementsTest() { @Test public void MobileElementByTest() { WebElement element = driver.findElement(MobileBy.IosUIAutomation(".elements()[0]")); - System.out.println(element); assertEquals(element.getAttribute("name"), "UICatalog"); } diff --git a/test/io/appium/java_client/MobileDriverAndroidTest.java b/test/io/appium/java_client/MobileDriverAndroidTest.java new file mode 100644 index 000000000..7b3adb85e --- /dev/null +++ b/test/io/appium/java_client/MobileDriverAndroidTest.java @@ -0,0 +1,67 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.io.File; +import java.net.URL; + +/** + * Test Mobile Driver features + */ +public class MobileDriverAndroidTest { + + private AppiumDriver driver; + + @Before + public void setup() throws Exception { + File appDir = new File("test/io/appium/java_client"); + File app = new File(appDir, "ApiDemos-debug.apk"); + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(CapabilityType.BROWSER_NAME, ""); + capabilities.setCapability("device", "Android"); + capabilities.setCapability("app", app.getAbsolutePath()); + driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); + } + + @After + public void tearDown() throws Exception { + driver.quit(); + } + + @Test + public void getStrings() { + String strings = driver.getAppStrings(); + assert(strings.length() > 100); + } + + @Test + public void keyEvent() { + driver.sendKeyEvent(AndroidKeyCode.HOME); + } + + @Test + public void keyEventWithMetastate() { + driver.sendKeyEvent(AndroidKeyCode.SPACE, AndroidKeyMetastate.META_SHIFT_ON); + } +} diff --git a/test/io/appium/java_client/MobileDriverIOSTest.java b/test/io/appium/java_client/MobileDriverIOSTest.java new file mode 100644 index 000000000..40572a5bc --- /dev/null +++ b/test/io/appium/java_client/MobileDriverIOSTest.java @@ -0,0 +1,59 @@ +/* + +Copyright 2014 Appium contributors + +Copyright 2014 Software Freedom Conservancy + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + + http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + */ + +package io.appium.java_client; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; + +import java.io.File; +import java.net.URL; + +/** + * Test Mobile Driver features + */ +public class MobileDriverIOSTest { + + private AppiumDriver driver; + + @Before + public void setup() throws Exception { + File appDir = new File("test/io/appium/java_client"); + File app = new File(appDir, "UICatalog.app.zip"); + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability(CapabilityType.BROWSER_NAME, ""); + capabilities.setCapability(CapabilityType.VERSION, "7.1"); + capabilities.setCapability(CapabilityType.PLATFORM, "Mac"); + capabilities.setCapability("device", "iPhone Simulator"); + capabilities.setCapability("app", app.getAbsolutePath()); + driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); + } + + @After + public void tearDown() throws Exception { + driver.quit(); + } + + @Test + public void resetTest() { + driver.resetApp(); + } + +}