From dfcd1b0843a0ed9a5cae779b05af23c96e0af5f7 Mon Sep 17 00:00:00 2001 From: jonahss Date: Tue, 15 Apr 2014 18:55:56 -0700 Subject: [PATCH 1/5] pullFile --- src/io/appium/java_client/AppiumDriver.java | 9 +++++++++ src/io/appium/java_client/MobileCommand.java | 1 + src/io/appium/java_client/MobileDriver.java | 10 ++++++++++ test/io/appium/java_client/MobileDriverIOSTest.java | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index c07634e1d..9ae52b1d1 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -21,6 +21,7 @@ import org.openqa.selenium.*; import org.openqa.selenium.remote.*; +import javax.xml.bind.DatatypeConverter; import java.net.URL; import java.util.LinkedHashSet; import java.util.List; @@ -45,6 +46,7 @@ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){ .put(KEY_EVENT, postC("/session/:sessionId/appium/device/keyevent")) .put(CURRENT_ACTIVITY, getC("/session/:sessionId/appium/device/current_activity")) .put(SET_VALUE, postC("/session/:sessionId/appium/element/:id/value")) + .put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")) ; ImmutableMap mobileCommands = builder.build(); @@ -97,6 +99,13 @@ public String currentActivity() { return response.getValue().toString(); } + public byte[] pullFile(String remotePath) { + Response response = execute(PULL_FILE, ImmutableMap.of("path", remotePath)); + String base64String = response.getValue().toString(); + + return DatatypeConverter.parseBase64Binary(base64String); + } + @Override public WebDriver context(String name) { diff --git a/src/io/appium/java_client/MobileCommand.java b/src/io/appium/java_client/MobileCommand.java index d7b2c383d..508416fb9 100644 --- a/src/io/appium/java_client/MobileCommand.java +++ b/src/io/appium/java_client/MobileCommand.java @@ -29,6 +29,7 @@ public interface MobileCommand { String KEY_EVENT = "keyEvent"; String CURRENT_ACTIVITY = "currentActivity"; String SET_VALUE = "setValue"; + String PULL_FILE = "pullFile"; } diff --git a/src/io/appium/java_client/MobileDriver.java b/src/io/appium/java_client/MobileDriver.java index a1151e378..65781c1d4 100644 --- a/src/io/appium/java_client/MobileDriver.java +++ b/src/io/appium/java_client/MobileDriver.java @@ -35,6 +35,8 @@ public interface MobileDriver extends WebDriver { /** * Get all defined Strings from an Android app + * + * @return a string of all the localized strings defined in the app */ String getAppStrings(); @@ -59,4 +61,12 @@ public interface MobileDriver extends WebDriver { */ String currentActivity(); + /** + * + * @param remotePath On Android and iOS, this is either the path to the file (relative to the root of the app's file system). + * On iOS only, if path starts with /AppName.app, which will be replaced with the application's .app directory + * @return A byte array of Base64 encoded data. + */ + byte[] pullFile(String remotePath); + } diff --git a/test/io/appium/java_client/MobileDriverIOSTest.java b/test/io/appium/java_client/MobileDriverIOSTest.java index e11b2fe46..a19a0bf66 100644 --- a/test/io/appium/java_client/MobileDriverIOSTest.java +++ b/test/io/appium/java_client/MobileDriverIOSTest.java @@ -65,4 +65,10 @@ public void setValueTest() { element.setValue("Grace Hopper"); } + @Test + public void pullFileTest() { + byte[] data = driver.pullFile("Library/AddressBook/AddressBook.sqlitedb"); + assert(data.length > 0); + } + } From c8ac73f8aa1fb97286e1c3cdd8c43310c94cdbab Mon Sep 17 00:00:00 2001 From: jonahss Date: Wed, 16 Apr 2014 11:09:10 -0700 Subject: [PATCH 2/5] Most methods implemented so far aren't actually part of mjsonwp, so shouldn't be in the MobileDriver interface --- src/io/appium/java_client/AppiumDriver.java | 29 ++++++++++++ src/io/appium/java_client/MobileCommand.java | 1 + src/io/appium/java_client/MobileDriver.java | 44 +------------------ .../java_client/MobileDriverIOSTest.java | 8 ++++ 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index 9ae52b1d1..009057fa6 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -73,19 +73,39 @@ protected Response execute(String command) { } + /** + * Reset the currently running app for this session + */ public void resetApp() { execute(MobileCommand.RESET); } + /** + * Get all defined Strings from an Android app + * + * @return a string of all the localized strings defined in the app + */ public String getAppStrings() { Response response = execute(GET_STRINGS); return response.getValue().toString(); } + /** + * Send a key event to the device + * + * @param key code for the key pressed on the device + */ public void sendKeyEvent(int key) { sendKeyEvent(key, null); } + /** + * 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 + */ public void sendKeyEvent(int key, Integer metastate) { ImmutableMap.Builder builder = ImmutableMap.builder(); builder.put("keycode", key); @@ -94,11 +114,20 @@ public void sendKeyEvent(int key, Integer metastate) { execute(KEY_EVENT, parameters); } + /** + * Get the current activity being run on the mobile device + */ public String currentActivity() { Response response = execute(CURRENT_ACTIVITY); return response.getValue().toString(); } + /** + * + * @param remotePath On Android and iOS, this is either the path to the file (relative to the root of the app's file system). + * On iOS only, if path starts with /AppName.app, which will be replaced with the application's .app directory + * @return A byte array of Base64 encoded data. + */ public byte[] pullFile(String remotePath) { Response response = execute(PULL_FILE, ImmutableMap.of("path", remotePath)); String base64String = response.getValue().toString(); diff --git a/src/io/appium/java_client/MobileCommand.java b/src/io/appium/java_client/MobileCommand.java index 508416fb9..230a7b19a 100644 --- a/src/io/appium/java_client/MobileCommand.java +++ b/src/io/appium/java_client/MobileCommand.java @@ -30,6 +30,7 @@ public interface MobileCommand { String CURRENT_ACTIVITY = "currentActivity"; String SET_VALUE = "setValue"; String PULL_FILE = "pullFile"; + String HIDE_KEYBOARD = "hideKeyboard"; } diff --git a/src/io/appium/java_client/MobileDriver.java b/src/io/appium/java_client/MobileDriver.java index 65781c1d4..80453b202 100644 --- a/src/io/appium/java_client/MobileDriver.java +++ b/src/io/appium/java_client/MobileDriver.java @@ -18,55 +18,15 @@ package io.appium.java_client; +import org.openqa.selenium.ContextAware; import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.Response; import java.util.Map; -public interface MobileDriver extends WebDriver { +public interface MobileDriver extends WebDriver, ContextAware { public Response execute(String driverCommand, Map parameters); - /** - * Reset the currently running app for this session - */ - void resetApp(); - - /** - * Get all defined Strings from an Android app - * - * @return a string of all the localized strings defined in the 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); - - /** - * Get the current activity being run on the mobile device - */ - String currentActivity(); - - /** - * - * @param remotePath On Android and iOS, this is either the path to the file (relative to the root of the app's file system). - * On iOS only, if path starts with /AppName.app, which will be replaced with the application's .app directory - * @return A byte array of Base64 encoded data. - */ - byte[] pullFile(String remotePath); - } diff --git a/test/io/appium/java_client/MobileDriverIOSTest.java b/test/io/appium/java_client/MobileDriverIOSTest.java index a19a0bf66..1d889b754 100644 --- a/test/io/appium/java_client/MobileDriverIOSTest.java +++ b/test/io/appium/java_client/MobileDriverIOSTest.java @@ -70,5 +70,13 @@ public void pullFileTest() { byte[] data = driver.pullFile("Library/AddressBook/AddressBook.sqlitedb"); assert(data.length > 0); } +/* + @Test + public void hideKeyboardTest() { + MobileElement element = new MobileElement((RemoteWebElement)driver.findElementByAccessibilityId("TextFields, Uses of UITextField"), driver); + element.click(); + driver.hideKeyboard(); + } +*/ } From 185dddb42cafcb539e59b0b7a1903236a44f4b62 Mon Sep 17 00:00:00 2001 From: jonahss Date: Wed, 16 Apr 2014 11:39:46 -0700 Subject: [PATCH 3/5] hideKeyboard --- src/io/appium/java_client/AppiumDriver.java | 18 ++++++++++++++++++ .../java_client/MobileDriverIOSTest.java | 7 ++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index 009057fa6..fd21baa5f 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -47,6 +47,7 @@ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){ .put(CURRENT_ACTIVITY, getC("/session/:sessionId/appium/device/current_activity")) .put(SET_VALUE, postC("/session/:sessionId/appium/element/:id/value")) .put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")) + .put(HIDE_KEYBOARD, postC("/session/:sessionId/appium/device/hide_keyboard")) ; ImmutableMap mobileCommands = builder.build(); @@ -135,6 +136,23 @@ public byte[] pullFile(String remotePath) { return DatatypeConverter.parseBase64Binary(base64String); } + /** + * Hides the keyboard if it is showing. + * This is an iOS only command. + */ + public void hideKeyboard() { + execute(HIDE_KEYBOARD); + } + + /** + * Hides the keyboard by pressing the button specified by keyName if it is showing. + * This is an iOS only command. + * @param keyName The button pressed by the mobile driver to attempt hiding the keyboard + */ + public void hideKeyboard(String keyName) { + execute(HIDE_KEYBOARD, ImmutableMap.of("keyName", keyName)); + } + @Override public WebDriver context(String name) { diff --git a/test/io/appium/java_client/MobileDriverIOSTest.java b/test/io/appium/java_client/MobileDriverIOSTest.java index 1d889b754..3490a6ad8 100644 --- a/test/io/appium/java_client/MobileDriverIOSTest.java +++ b/test/io/appium/java_client/MobileDriverIOSTest.java @@ -70,13 +70,14 @@ public void pullFileTest() { byte[] data = driver.pullFile("Library/AddressBook/AddressBook.sqlitedb"); assert(data.length > 0); } -/* + @Test public void hideKeyboardTest() { MobileElement element = new MobileElement((RemoteWebElement)driver.findElementByAccessibilityId("TextFields, Uses of UITextField"), driver); element.click(); + element = new MobileElement((RemoteWebElement)driver.findElementByAccessibilityId("Normal"), driver); + element.click(); driver.hideKeyboard(); - } -*/ + } From 14d3df5e8dd0fa6d82d02ab2986206f81e74025e Mon Sep 17 00:00:00 2001 From: jonahss Date: Wed, 16 Apr 2014 12:54:06 -0700 Subject: [PATCH 4/5] pushFile --- java-client.iml | 1 + src/io/appium/java_client/AppiumDriver.java | 13 +++++++++++++ src/io/appium/java_client/MobileCommand.java | 1 + .../appium/java_client/AndroidUIAutomatorTest.java | 10 ++++++++++ 4 files changed, 25 insertions(+) diff --git a/java-client.iml b/java-client.iml index 961a621f6..e881e4a50 100644 --- a/java-client.iml +++ b/java-client.iml @@ -19,6 +19,7 @@ + diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index fd21baa5f..64524c75d 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -48,6 +48,7 @@ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){ .put(SET_VALUE, postC("/session/:sessionId/appium/element/:id/value")) .put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")) .put(HIDE_KEYBOARD, postC("/session/:sessionId/appium/device/hide_keyboard")) + .put(PUSH_FILE, postC("/session/:sessionId/appium/device/push_file")) ; ImmutableMap mobileCommands = builder.build(); @@ -136,6 +137,18 @@ public byte[] pullFile(String remotePath) { return DatatypeConverter.parseBase64Binary(base64String); } + /** + * Save base64 encoded data as a file on the remote mobile device. + * This is an Android only method. + * @param remotePath Path to file to write data to on remote device + * @param base64Data Base64 encoded byte array of data to write to remote device + */ + public void pushFile(String remotePath, byte[] base64Data) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put("path", remotePath).put("data", base64Data); + execute(PUSH_FILE, builder.build()); + } + /** * Hides the keyboard if it is showing. * This is an iOS only command. diff --git a/src/io/appium/java_client/MobileCommand.java b/src/io/appium/java_client/MobileCommand.java index 230a7b19a..875b68210 100644 --- a/src/io/appium/java_client/MobileCommand.java +++ b/src/io/appium/java_client/MobileCommand.java @@ -30,6 +30,7 @@ public interface MobileCommand { String CURRENT_ACTIVITY = "currentActivity"; String SET_VALUE = "setValue"; String PULL_FILE = "pullFile"; + String PUSH_FILE = "pushFile"; String HIDE_KEYBOARD = "hideKeyboard"; diff --git a/test/io/appium/java_client/AndroidUIAutomatorTest.java b/test/io/appium/java_client/AndroidUIAutomatorTest.java index f0f5df2fa..73ff2c7e3 100644 --- a/test/io/appium/java_client/AndroidUIAutomatorTest.java +++ b/test/io/appium/java_client/AndroidUIAutomatorTest.java @@ -1,5 +1,6 @@ package io.appium.java_client; +import org.apache.commons.codec.binary.Base64; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -65,4 +66,13 @@ public void findElementsByTest() { public void ErrorTest() { driver.findElementByAndroidUIAutomator(null); } + + @Test + public void pushFileTest() { + byte[] data = Base64.encodeBase64("The eventual code is no more than the deposit of your understanding. ~E. W. Dijkstra".getBytes()); + driver.pushFile("/data/local/tmp/remote.txt", data); + byte[] returnData = driver.pullFile("/data/local/tmp/remote.txt"); + String returnDataDecoded = new String(Base64.decodeBase64(returnData)); + assertEquals("The eventual code is no more than the deposit of your understanding. ~E. W. Dijkstra", returnDataDecoded); + } } \ No newline at end of file From f665896509c7a6f967e8bfcb6e5481aa2add595e Mon Sep 17 00:00:00 2001 From: jonahss Date: Wed, 16 Apr 2014 13:27:27 -0700 Subject: [PATCH 5/5] background --- src/io/appium/java_client/AppiumDriver.java | 10 ++++++++++ src/io/appium/java_client/MobileCommand.java | 1 + test/io/appium/java_client/MobileDriverIOSTest.java | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/src/io/appium/java_client/AppiumDriver.java b/src/io/appium/java_client/AppiumDriver.java index 64524c75d..aa37e209f 100644 --- a/src/io/appium/java_client/AppiumDriver.java +++ b/src/io/appium/java_client/AppiumDriver.java @@ -49,6 +49,7 @@ public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities){ .put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")) .put(HIDE_KEYBOARD, postC("/session/:sessionId/appium/device/hide_keyboard")) .put(PUSH_FILE, postC("/session/:sessionId/appium/device/push_file")) + .put(RUN_APP_IN_BACKGROUND, postC("/session/:sessionId/appium/app/background")) ; ImmutableMap mobileCommands = builder.build(); @@ -166,6 +167,15 @@ public void hideKeyboard(String keyName) { execute(HIDE_KEYBOARD, ImmutableMap.of("keyName", keyName)); } + /** + * Runs the current app as a background app for the number of seconds requested. + * This is a synchronous method, it returns after the back has been returned to the foreground. + * @param seconds Number of seconds to run App in background + */ + public void runAppInBackground(int seconds) { + execute(RUN_APP_IN_BACKGROUND, ImmutableMap.of("seconds", seconds)); + } + @Override public WebDriver context(String name) { diff --git a/src/io/appium/java_client/MobileCommand.java b/src/io/appium/java_client/MobileCommand.java index 875b68210..062186d22 100644 --- a/src/io/appium/java_client/MobileCommand.java +++ b/src/io/appium/java_client/MobileCommand.java @@ -32,6 +32,7 @@ public interface MobileCommand { String PULL_FILE = "pullFile"; String PUSH_FILE = "pushFile"; String HIDE_KEYBOARD = "hideKeyboard"; + String RUN_APP_IN_BACKGROUND = "runAppInBackground"; } diff --git a/test/io/appium/java_client/MobileDriverIOSTest.java b/test/io/appium/java_client/MobileDriverIOSTest.java index 3490a6ad8..ee0fe0989 100644 --- a/test/io/appium/java_client/MobileDriverIOSTest.java +++ b/test/io/appium/java_client/MobileDriverIOSTest.java @@ -80,4 +80,12 @@ public void hideKeyboardTest() { driver.hideKeyboard(); } + @Test + public void runAppInBackgroundTest() { + long time = System.currentTimeMillis(); + driver.runAppInBackground(4); + long timeAfter = System.currentTimeMillis(); + assert(timeAfter - time > 3000); + } + }